Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
164 commits
Select commit Hold shift + click to select a range
3fa8e13
Merge pull request #9 from cwage/feature/debian-cloud-image
cwage Nov 20, 2025
c8460eb
Add Ansible role to build Proxmox templates
cwage Nov 20, 2025
e6b5ba7
Restore proxmox managed_users while keeping template vars
cwage Nov 20, 2025
8e12863
Address review feedback for pve template role
cwage Nov 20, 2025
4b75059
Document Proxmox template workflow
cwage Nov 20, 2025
55531e0
Merge pull request #12 from cwage/feature/pve-template-ansible
cwage Nov 20, 2025
647a3af
simplifying motd
cwage Nov 20, 2025
9d140d9
Merge pull request #15 from cwage/feature/felix-motd-chmod
cwage Nov 20, 2025
28d9653
adding screeshot key and fixing a tinyfugue issue
cwage Nov 22, 2025
963bcb5
Merge pull request #16 from cwage/add-portaptty-shot-key
cwage Nov 22, 2025
8448d63
misc improvements and specifying in AGENTS that we will only ever use…
cwage Nov 22, 2025
9e1b00e
Merge pull request #17 from cwage/template-maintenance
cwage Nov 22, 2025
160b65d
Add Synology NFS management via Ansible
cwage Nov 22, 2025
0309d9e
Implement NFS share management for Synology DSM 7
cwage Nov 22, 2025
4445468
Address Copilot PR review feedback
cwage Nov 22, 2025
8ce3452
Merge pull request #18 from cwage/feature/synology-nfs-management
cwage Nov 22, 2025
9344fb8
adding a role for nfs mounts
cwage Nov 27, 2025
4bd5b72
resolving copilot bitching
cwage Nov 27, 2025
002d00a
Merge pull request #27 from cwage/nas-mount-role
cwage Nov 27, 2025
80e5cc2
adding nfs mounts to proxmox and rearranging make targets/playbooks t…
cwage Nov 27, 2025
1d7dfb9
making mount options consistent
cwage Nov 27, 2025
01d6ad9
Merge pull request #28 from cwage/add-pve-mounts
cwage Nov 27, 2025
d4398ac
fixing clippy's retardation
cwage Nov 27, 2025
9c06b3b
Merge pull request #29 from cwage/fix-bug
cwage Nov 27, 2025
7b12aac
cleaning up dhcpd.conf template
cwage Dec 2, 2025
556f775
Update ansible/roles/openbsd_firewall/templates/dhcpd.conf.j2
cwage Dec 2, 2025
c352247
Update ansible/roles/openbsd_firewall/templates/dhcpd.conf.j2
cwage Dec 2, 2025
cd1a39a
Update ansible/roles/openbsd_firewall/templates/dhcpd.conf.j2
cwage Dec 2, 2025
de7773c
Merge pull request #30 from cwage/cleanup-dhcp
cwage Dec 2, 2025
53375c7
adding example env and excluding in gitignore
cwage Dec 5, 2025
fa4bf22
Merge pull request #32 from cwage/add-example-env
cwage Dec 5, 2025
2f9f8c6
adding mosh
cwage Dec 5, 2025
6f2e2b0
Merge pull request #33 from cwage/add-mosh
cwage Dec 5, 2025
734944f
adding symlink of CLAUDE.md to AGENTS
cwage Dec 5, 2025
bd76163
Merge pull request #34 from cwage/add-claude-symlink
cwage Dec 5, 2025
63a16ff
adding basic documentation of adding a new VM
cwage Dec 5, 2025
91aab20
Merge pull request #35 from cwage/document-vm-addition
cwage Dec 5, 2025
f62ab82
initial provisioning of dns1 authoritative DNS server for lan.quietli…
cwage Dec 5, 2025
0740e28
Merge pull request #36 from cwage/add-nsd
cwage Dec 5, 2025
2f9d7fc
Address PR review feedback for NSD role
cwage Dec 5, 2025
81cd24c
Merge pull request #37 from cwage/nsd-review-fixes
cwage Dec 5, 2025
aeef247
modifying unbound to stub to our new dns1 for lan.quietlife.net
cwage Dec 5, 2025
70e05ec
Merge pull request #38 from cwage/add-stub
cwage Dec 5, 2025
5f778cd
adding search domain
cwage Dec 5, 2025
2975166
fixing paths
cwage Dec 5, 2025
a18a2fa
Merge pull request #39 from cwage/add-default-domain
cwage Dec 5, 2025
e14c59f
Remove redundant note about OpenTofu API creds
cwage Dec 5, 2025
df79533
Merge pull request #40 from cwage/cwage-patch-1
cwage Dec 5, 2025
1ef2737
adding state to git repo for now
cwage Dec 5, 2025
c511463
removing git pull and just adding a check that state is up to date fo…
cwage Dec 5, 2025
5b6e449
reverting checks
cwage Dec 5, 2025
93dce51
Merge pull request #41 from cwage/tofu-state-git
cwage Dec 5, 2025
6f3724e
adding containers vm
cwage Dec 6, 2025
c06fa5d
Merge pull request #43 from cwage/containers
cwage Dec 6, 2025
ea11503
Add Traefik reverse proxy and Jellyfin container stack
cwage Dec 6, 2025
28cd62d
Pin Jellyfin to version 10.11.4
cwage Dec 6, 2025
79c055f
Merge pull request #45 from cwage/add-traefik-jellyfin
cwage Dec 6, 2025
807612f
Add NFS media mount for Jellyfin
cwage Dec 6, 2025
fa9ca77
Merge pull request #49 from cwage/add-jellyfin-nfs-mount
cwage Dec 6, 2025
b560851
Add GPU passthrough for Jellyfin transcoding
cwage Dec 6, 2025
1da5382
Update terraform state after GPU passthrough
cwage Dec 6, 2025
d6583c7
Add GPU passthrough documentation
cwage Dec 6, 2025
974bad2
Address PR feedback: become, idempotency, blacklist
cwage Dec 6, 2025
3a4d3cb
adding state reflecting new containers VM
cwage Dec 6, 2025
d60e1fa
Merge pull request #51 from cwage/gpu-passthrough-jellyfin
cwage Dec 6, 2025
95c91d6
Add NFS music mount for Jellyfin
cwage Dec 6, 2025
549a7fb
Merge pull request #52 from cwage/add-jellyfin-music-mount
cwage Dec 6, 2025
b676825
adding rules about deploying and committing
cwage Dec 6, 2025
a1308e9
Merge pull request #53 from cwage/claude-tweaks
cwage Dec 6, 2025
71ca4c6
making boot order explicit to avoid state drift
cwage Dec 6, 2025
9f0f4d6
Merge pull request #55 from cwage/fix-boot-order-drift
cwage Dec 6, 2025
f6ab8ee
adding recap of our realtek NIC fuckup
cwage Dec 6, 2025
f3fb71e
don't restart my shit clippy
cwage Dec 6, 2025
df88134
Merge pull request #57 from cwage/more-rules
cwage Dec 6, 2025
6d28d24
adding dns_client role for VMs
cwage Dec 6, 2025
bcf0743
Merge pull request #58 from cwage/fix-dns
cwage Dec 6, 2025
73b6864
removing cloudflare from dhcpd dns
cwage Dec 8, 2025
30cc001
Merge pull request #60 from cwage/change-dns
cwage Dec 8, 2025
4aba833
Merge pull request #56 from cwage/add-fuckup-docs
cwage Dec 9, 2025
22cbed7
adding hardware scan docs of proxmox PC
cwage Dec 9, 2025
91a4546
Merge pull request #61 from cwage/add-hardware-docs
cwage Dec 9, 2025
7bfe102
adding phone wireguard client
cwage Dec 11, 2025
72928f0
Merge pull request #64 from cwage/wg-add-phone
cwage Dec 11, 2025
d90db17
adding openbao VM
cwage Dec 11, 2025
24e2398
addressing copilot feedback
cwage Dec 11, 2025
514f607
Merge pull request #66 from cwage/openbao
cwage Dec 11, 2025
028552a
making sure openbao is backed up to NAS
cwage Dec 11, 2025
31634a2
addressing copilot feedback
cwage Dec 11, 2025
9add28c
Merge pull request #68 from cwage/bao-backups
cwage Dec 11, 2025
5a7fc66
updating cloud-init for setting hostname from the getgo and ansible t…
cwage Dec 12, 2025
6cce140
Merge pull request #69 from cwage/fix-hostnames
cwage Dec 12, 2025
2014a90
reorging users into a global file and setting a hash for cwage
cwage Dec 12, 2025
5f77757
Merge pull request #70 from cwage/reorg-users
cwage Dec 12, 2025
2bf9446
initial pass at reorging the .env file for more centralized usage
cwage Dec 12, 2025
615e700
cleaning up unused cloudinit snippet
cwage Dec 12, 2025
6327481
Add hvac library and fix OpenBao test playbook
cwage Dec 12, 2025
a7f3d17
Address Copilot review feedback
cwage Dec 12, 2025
a38e4b7
Merge pull request #71 from cwage/openbao-ansible-integration
cwage Dec 12, 2025
c92b9b0
Add Lego ACME client for Let's Encrypt certificates
cwage Dec 12, 2025
ae5a171
Address Copilot review feedback
cwage Dec 12, 2025
7aaac6b
Merge pull request #72 from cwage/lego-acme
cwage Dec 12, 2025
ca058a6
Add HTTPS support to Traefik with Let's Encrypt wildcard cert
cwage Dec 12, 2025
516aa6e
Address Copilot review feedback
cwage Dec 12, 2025
1293e36
adding agents addition
cwage Dec 12, 2025
d47b064
Merge pull request #74 from cwage/traefik-https
cwage Dec 12, 2025
4caf9e9
Add proxmox_certs role to deploy wildcard cert from OpenBao
cwage Dec 13, 2025
6247fbe
Address Copilot review feedback
cwage Dec 13, 2025
265db0c
Merge pull request #75 from cwage/proxmox-wildcard-cert
cwage Dec 13, 2025
72753f1
Add wildcard cert deployment to OpenBao role
cwage Dec 13, 2025
72af4cd
Clarify TLS hostname usage in docs per review feedback
cwage Dec 13, 2025
d34f0c1
Merge pull request #76 from cwage/openbao-wildcard-cert
cwage Dec 13, 2025
32cdfcd
Enable TLS verification for Proxmox provider
cwage Dec 13, 2025
9c20d95
Merge pull request #77 from cwage/tofu-proxmox-tls-verify
cwage Dec 13, 2025
e333b67
Add gaming_server role for LinuxGSM-based game servers
cwage Jan 9, 2026
f3846de
Address Copilot review feedback on gaming_server role
cwage Jan 10, 2026
6e5054c
Merge pull request #83 from cwage/gaming-server-lgsm
cwage Jan 10, 2026
751b780
Add gaming profile archive functionality
cwage Jan 10, 2026
746017f
Address Copilot review feedback
cwage Jan 10, 2026
af721a7
Merge pull request #84 from cwage/gaming-server-archive
cwage Jan 10, 2026
1252e06
Add config deployment and fix tag inheritance for gaming_server role
cwage Jan 10, 2026
053c419
Merge pull request #85 from cwage/gaming-server-configs
cwage Jan 10, 2026
bdaeeab
Add mod and ModConfig deployment support for Vintage Story
cwage Jan 10, 2026
38ed02d
Merge pull request #86 from cwage/gaming-server-mods
cwage Jan 10, 2026
ed28da1
Add automatic game installation for gaming_server role
cwage Jan 10, 2026
908e59a
Address review feedback: add minecraft executable, simplify condition
cwage Jan 10, 2026
3deee58
Merge pull request #87 from cwage/gaming-server-autoinstall
cwage Jan 10, 2026
2db28e1
Add templated serverconfig.json for Vintage Story
cwage Jan 10, 2026
e22980f
Fix JSON string escaping in serverconfig.json template
cwage Jan 10, 2026
1e6b501
Merge pull request #88 from cwage/gaming-server-templated-config
cwage Jan 10, 2026
19c5c15
Integrate OpenBao for gaming server passwords
cwage Jan 10, 2026
402ce6f
Merge pull request #89 from cwage/gaming-server-openbao-secrets
cwage Jan 10, 2026
c3c04b5
make sure indexes are on for books site
cwage Jan 10, 2026
95c86c0
Merge pull request #90 from cwage/books-changes
cwage Jan 10, 2026
c5b3236
Add Valheim server support to gaming_server role
cwage Jan 13, 2026
9e06d06
Fix i386 architecture detection to report changes accurately
cwage Jan 13, 2026
7844ae9
Merge pull request #92 from cwage/valheim-support
cwage Jan 13, 2026
7d8431b
Add BepInEx and mod support for Valheim servers
cwage Jan 13, 2026
b212f4e
Merge pull request #93 from cwage/valheim-mods
cwage Jan 13, 2026
eb555cf
Add vs-cwage Vintage Story server profile and gunsmoke nginx site
cwage Jan 14, 2026
85913d1
Remove redundant when clause from mod DLLs task
cwage Jan 14, 2026
3903c4d
Merge pull request #94 from cwage/vs-cwage-migration
cwage Jan 14, 2026
4f6f442
Reactivate vs-buttopia with new modpack and fix WorldConfiguration te…
cwage Jan 24, 2026
7a0164e
Fix type inconsistencies in world_config values
cwage Jan 24, 2026
e020e20
Merge pull request #96 from cwage/vs-server-cleanup
cwage Jan 24, 2026
8bc1c7b
Disable temporal storms and stability for vs-buttopia
cwage Jan 31, 2026
e9e6aa0
Merge pull request #97 from cwage/vs-disable-temporal
cwage Jan 31, 2026
284ff20
Add Cloudflare Tunnel for external Jellyfin access
cwage Jan 31, 2026
a0e5509
Address Copilot review feedback for cloudflared
cwage Jan 31, 2026
b8e15d3
Merge pull request #98 from cwage/cloudflare-tunnel
cwage Jan 31, 2026
50a06ee
Consolidate NAS mounts and switch Jellyfin to LinuxServer image
cwage Feb 3, 2026
031f40f
Merge pull request #102 from cwage/consolidate-mounts
cwage Feb 3, 2026
901ba5b
Add Radarr/Sonarr/SABnzbd arr stack for media automation
cwage Feb 3, 2026
b93af03
Address Copilot review feedback for SABnzbd whitelist config
cwage Feb 3, 2026
d9e8081
Merge pull request #103 from cwage/arr-stack
cwage Feb 3, 2026
37bcf1c
Add paperless-ngx to containers stack
cwage Feb 3, 2026
9b64b3b
Pin paperless and redis image versions
cwage Feb 3, 2026
aac7e0f
Merge pull request #105 from cwage/paperless-migration
cwage Feb 3, 2026
52d9555
Add Dependabot configuration for dependency updates
cwage Feb 3, 2026
5847820
Merge pull request #107 from cwage/add-dependabot-config
cwage Feb 3, 2026
c1fb0b8
Bump trufflesecurity/trufflehog from 3.79.0 to 3.92.5
dependabot[bot] Feb 3, 2026
db85668
Remove docker-compose-only directories from Dependabot config
cwage Feb 3, 2026
1c3b9db
Merge pull request #109 from cwage/fix-dependabot-config
cwage Feb 3, 2026
737962f
Merge pull request #108 from cwage/dependabot/docker/trufflesecurity/…
cwage Feb 3, 2026
b741281
Add Grype vulnerability scanning (proof-of-concept)
cwage Feb 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
53 changes: 53 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Homelab Infrastructure Configuration
# Copy this file to .env and fill in your values
# The .env file is gitignored for security

# =============================================================================
# Docker Compose user mapping (for both Ansible and OpenTofu containers)
# These values are auto-populated by 'make init' (run from ansible/ directory)
# =============================================================================
UID=1000
GID=1000

# =============================================================================
# OpenBao Secrets Management
# Required for Ansible/OpenTofu to retrieve secrets from OpenBao
# =============================================================================

# OpenBao server address
BAO_ADDR=https://bao.lan.quietlife.net:8200

# OpenBao token (create with appropriate policy - see docs/openbao-secrets.md)
# This token should have read-only access to secrets needed by automation
BAO_TOKEN=

# Skip TLS certificate verification
# Only needed for:
# - Initial bootstrap (before wildcard cert is deployed to OpenBao)
# - Recovery when wildcard cert has expired
# Once wildcard cert is deployed, remove this or set to false
# See docs/openbao.md "TLS Certificate Management" for details
# BAO_SKIP_VERIFY=true

# =============================================================================
# Proxmox API Configuration (for OpenTofu VM provisioning)
# =============================================================================

# Proxmox API URL (use hostname for TLS verification with wildcard cert)
PM_API_URL=https://pve1.lan.quietlife.net:8006/api2/json

# Proxmox API Token ID (format: user@realm!tokenid)
# Example: root@pam!tofu-token
PM_API_TOKEN_ID=

# Proxmox API Token Secret
PM_API_TOKEN_SECRET=

# Proxmox node name (usually "pve", not the inventory hostname)
PM_NODE_NAME=pve

# Datastore for downloaded cloud images (defaults to 'local')
PM_IMAGE_DATASTORE_ID=local

# Datastore for VM disks (defaults to 'local-lvm')
PM_VM_DATASTORE_ID=local-lvm
25 changes: 25 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: 2
updates:
# OpenTofu provider updates
- package-ecosystem: "terraform"
directory: "/tofu"
schedule:
interval: "weekly"

# Development/build Dockerfiles
# Note: Dependabot's docker ecosystem only works with Dockerfile files,
# not docker-compose.yml. Directories with only compose files are excluded.
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "monthly"

- package-ecosystem: "docker"
directory: "/tofu"
schedule:
interval: "monthly"

- package-ecosystem: "docker"
directory: "/ansible"
schedule:
interval: "monthly"
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Root-level secrets
.env
.env.*
!.env.example
2 changes: 2 additions & 0 deletions .trufflehog-exclude.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@
^/repo/tofu/\.env$
^/repo/tofu/\.env\..*
^/repo/tofu/secrets/
# Exclude generated Let's Encrypt certificates (lego)
^/repo/lego/certs/
17 changes: 16 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
# Homelab monorepo agent guide

## BEFORE MAKING ANY CODE CHANGES
- [ ] Check current branch with `git branch --show-current`
- [ ] If on `master`, STOP and alert the user to create/switch to a feature branch first
- [ ] Only proceed with code changes once on a non-master branch

---

- **Layout**: `ansible/` (host config, formerly homelab-ansible), `tofu/` (OpenTofu VM provisioning, formerly homelab-tofu), `docs/` (design notes like `docs/dns-plan.md`).
- **Make wrappers**: From repo root use `make ansible-<target>` and `make tofu-<target>` to call component Makefiles (see `make ansible-help`, `make tofu-help`). Avoid running `ansible-playbook` or `tofu` directly; prefer the Dockerized targets.
- **Containerized workflows**: Both stacks expect Docker/Compose; use provided Make targets for build/plan/apply/lint. Keep secrets in local `.env` files (gitignored) and never commit keys or state.
- **DNS direction**: We standardized on NSD as the authoritative server (`lan.quietlife.net`), with Unbound on the firewall as recursive + stub to NSD. DHCP/DNS should be driven from a shared data model; include an `dhcp-<nn>.lan.quietlife.net` pool for ephemeral clients. See `docs/dns-plan.md`.
- **Host data**: Inventories and templates live under `ansible/` (e.g., `inventories/hosts.yml`, `roles/openbsd_firewall`). Keep DHCP reservations, DNS records, and VM definitions consistent by editing shared host metadata when adding nodes.
- **Networking**: Proxmox hosts only expose a single useful bridge (`vmbr0`). Assume VMs (even ones with multiple NICs) attach to that same bridge unless the user explicitly requests a different network.
- **Testing/validation**: Run relevant Dockerized checks before changes: `make ansible-trufflehog`, `make tofu-validate/plan`, `make ansible-ping`/`ansible-firewall` dry runs as needed. Keep changes scoped; avoid large “deploy everything” unless required.
- **No destructive ops**: Don’t use sudo; avoid wiping state or force pushes. If you must propose a destructive command, surface it to the user instead of running it.
- **No destructive ops**: Don't use sudo; avoid wiping state or force pushes. If you must propose a destructive command, surface it to the user instead of running it.
- **No service restarts without approval**: NEVER restart containers, services, or VMs without explicit user approval. Always ask first - even if a restart seems like the obvious fix. Diagnose the problem, explain the fix, and let the user decide when to restart.
- **Deployment workflow**: Do NOT automatically deploy changes (ansible playbooks, tofu apply, etc.) without explicit user approval. After making code changes, ask the user if they want to deploy rather than assuming. The user prefers to review and deploy manually so they can observe and learn. Only run `make ansible-*` or `make tofu-apply` when the user explicitly requests it or approves it.
- **Let the user drive**: When suggesting commands to run (dry-runs, tests, deploys), prefer telling the user the command rather than running it automatically. The user wants to build muscle memory and learn by doing. Exception: simple read-only diagnostics like `git status` or `ping` are fine to run.
- **Git workflow**: The user will handle git commits and PR creation. Do NOT run `git commit`, `git push`, or `gh pr create` unless explicitly asked. Focus on making code changes; the user will review and commit them. **Important**: Before making code changes, verify you're not on `master` branch. If on master, alert the user so they can create/switch to an appropriate feature branch first.
- **SSH key errors**: If you encounter SSH permission denied errors (e.g., `git@github.com: Permission denied (publickey)`), simply ask the user to add their SSH key (it's passphrase-protected) and then retry the command. Don't attempt to run ssh-agent or ssh-add yourself.
- **IP address allocation**: Before assigning a static IP to a new VM, always verify it's not already in use by checking `ansible/roles/openbsd_firewall/templates/dhcpd.conf.j2` for existing reservations and running `ping -c1 <ip>` to confirm no active host. Prefer IPs in the 10.10.15.10-99 range for infrastructure VMs (the .100-.254 range is the DHCP pool).
- **Documentation**: When adding new Makefile targets, always update the root `README.md` with examples and descriptions of the new targets. Keep the documentation in sync with available commands.
1 change: 1 addition & 0 deletions CLAUDE.md
2 changes: 1 addition & 1 deletion Dockerfile.trufflehog
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ghcr.io/trufflesecurity/trufflehog:3.79.0
FROM ghcr.io/trufflesecurity/trufflehog:3.92.5

WORKDIR /repo
ENTRYPOINT ["trufflehog"]
33 changes: 31 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,33 @@ SHELL := /bin/bash

ANSIBLE_DIR := ansible
TOFU_DIR := tofu
LEGO_DIR := lego

ANSIBLE_TARGETS := help init build galaxy version ping access_check users users-check firewall firewall-check felix felix-check all check-all run adhoc sh build-tinyfugue trufflehog
ANSIBLE_TARGETS := help init build galaxy version ping access_check proxmox proxmox-check firewall firewall-check felix felix-check all check-all run adhoc sh build-tinyfugue trufflehog
TOFU_TARGETS := help build shell init plan apply destroy fmt validate trufflehog clean
LEGO_TARGETS := help run renew renew-staging renew-force list show fetch-creds store retrieve
TRUFFLEHOG_ARGS ?= filesystem /repo --fail --no-update --exclude-paths /repo/.trufflehog-exclude.txt

.DEFAULT_GOAL := help

.PHONY: help ansible tofu ansible-% tofu-% trufflehog install-precommit-hook
.PHONY: help ansible tofu lego ansible-% tofu-% lego-% trufflehog grype grype-compose grype-pull install-precommit-hook

help:
@echo "homelab monorepo"
@echo ""
@echo "Use namespaced targets to drive component Makefiles:"
@echo " make ansible-<target> (targets: $(ANSIBLE_TARGETS))"
@echo " make tofu-<target> (targets: $(TOFU_TARGETS))"
@echo " make lego-<target> (targets: $(LEGO_TARGETS))"
@echo " make trufflehog (root) scan entire repo for secrets"
@echo " make grype IMAGE=<img> (root) scan a container image for CVEs"
@echo " make grype-compose (root) scan all images in production compose"
@echo " make grype-pull (root) pull the grype scanner image"
@echo ""
@echo "Shortcuts:"
@echo " make ansible # same as: (cd ansible && make) -> opens component help/defaults"
@echo " make tofu # same as: (cd tofu && make) -> opens component help/defaults"
@echo " make lego # same as: (cd lego && make) -> opens component help/defaults"
@echo " make install-precommit-hook # install root pre-commit hook (trufflehog)"

ansible-%:
Expand All @@ -36,8 +43,30 @@ ansible:
tofu:
@$(MAKE) -C $(TOFU_DIR)

lego-%:
@$(MAKE) -C $(LEGO_DIR) $*

lego:
@$(MAKE) -C $(LEGO_DIR)

trufflehog:
docker compose -f docker-compose.trufflehog.yml run --rm trufflehog $(TRUFFLEHOG_ARGS)

# Grype vulnerability scanning
GRYPE_ARGS ?=
IMAGE ?=

grype-pull:
docker compose -f docker-compose.grype.yml pull

grype:
ifndef IMAGE
$(error IMAGE is required. Usage: make grype IMAGE=nginx:latest)
endif
docker compose -f docker-compose.grype.yml run --rm grype $(IMAGE) $(GRYPE_ARGS)

grype-compose:
./scripts/grype-compose.sh ansible/files/stacks/docker-compose.yml $(GRYPE_ARGS)

install-precommit-hook:
@./scripts/install-precommit-hook.sh
78 changes: 77 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Examples:
make ansible-firewall # apply firewall config via Ansible container
make ansible-firewall-check # dry-run firewall (check+diff)
make ansible-felix-check # dry-run felix VPS playbook
make ansible-gaming # provision gaming servers (all active profiles)
make ansible-gaming-check # dry-run gaming server config
make ansible-gaming PROFILE=vs-buttopia # provision specific profile only
make ansible-gaming-configs # deploy configs/mods only (no deps/lgsm install)
make ansible-run PLAY=playbooks/firewall.yml LIMIT=openbsd_firewalls OPTS="--check --diff" # dry-run limited group
make ansible-all # run users + firewall + felix (apply)
make ansible-check-all # dry-run users + firewall + felix
Expand All @@ -24,6 +28,9 @@ make ansible-trufflehog # run secrets scan for Ansible tree
make tofu-trufflehog # run secrets scan for Tofu tree
make trufflehog # scan entire repo for secrets (root-level)
make install-precommit-hook # install root pre-commit hook (trufflehog)
make grype IMAGE=nginx:latest # scan a container image for CVEs
make grype-compose # scan all images in production docker-compose
make grype-pull # pull the grype scanner image
```

### Common scenarios
Expand All @@ -34,11 +41,80 @@ make install-precommit-hook # install root pre-commit hook (trufflehog)
- **Apply to all standard playbooks**: `make ansible-all` (users, firewall, felix) — use sparingly
- **Dry-run all standard playbooks**: `make ansible-check-all`

### Gaming servers
Game servers on Linode VPS. Each game profile gets its own Linux user with isolated installation.

#### Quick reference
| Command | Description |
|---------|-------------|
| `make ansible-gaming` | Full provision (all active profiles) |
| `make ansible-gaming PROFILE=name` | Full provision (single profile) |
| `make ansible-gaming-check` | Dry-run with --check/--diff |
| `make ansible-gaming-configs` | Deploy configs/mods only |
| `make ansible-gaming-archive PROFILE=name` | Archive and purge a profile |

#### New profile setup

1. Add profile to `ansible/inventories/group_vars/gaming_servers.yml`
2. Run `make ansible-gaming PROFILE=<name>` to provision user and dependencies
3. Install the game server (see game-specific instructions below)
4. Start the server and verify it works
5. (Optional) Add configs/mods to `ansible/roles/gaming_server/files/profiles/<name>/`
6. Deploy configs with `make ansible-gaming-configs PROFILE=<name>`

#### Game-specific setup

**Vintage Story / Valheim (LinuxGSM)**

After provisioning, install the game via LGSM:
```bash
ssh gaming.quietlife.net
sudo -iu <profile>
./<script> install # e.g., ./vintsserver install, ./vhserver install
./<script> start
```

#### Day-to-day operations

Ansible never auto-restarts game servers. After config changes, manually restart:
```bash
ssh gaming.quietlife.net
sudo -iu <profile>
./<script> restart
```

#### Archiving profiles

To safely remove a profile and reclaim disk space:

1. Set `active: false` in `ansible/inventories/group_vars/gaming_servers.yml`
2. Stop the server: `sudo -iu <profile> ./<script> stop`
3. Preview: `make ansible-gaming-archive PROFILE=<name>`
4. Execute: `make ansible-gaming-archive PROFILE=<name> CONFIRM=yes`
5. Copy the tarball: `scp gaming.quietlife.net:/tmp/<name>-*.tar.gz ./`

To restore later:
1. Set `active: true` in group_vars
2. Run `make ansible-gaming PROFILE=<name>`
3. Extract the tarball to restore world data

### Secrets and local state
- OpenTofu API creds live in `tofu/.env` (gitignored). Copy from your old checkout if needed.
- OpenTofu API creds live in `tofu/.env` (gitignored).
- Ansible deploy keys live in `ansible/keys/` (gitignored).
- Other local artifacts (.tfstate, .terraform, etc.) remain gitignored via component `.gitignore` files.

### TruffleHog scanning
- Root scanner: `make trufflehog` (uses `docker-compose.trufflehog.yml` in repo root, excludes defined in `.trufflehog-exclude.txt`).
- Install pre-commit hook: `make install-precommit-hook` (respects `SKIP_TRUFFLEHOG=1` and `TRUFFLEHOG_PRECOMMIT_ARGS`).

### Grype vulnerability scanning
Scan container images for CVEs using [Grype](https://github.com/anchore/grype):
- `make grype IMAGE=<image>` — scan a single image (e.g., `make grype IMAGE=nginx:latest`)
- `make grype-compose` — scan all images in `ansible/files/stacks/docker-compose.yml`
- `make grype-pull` — pull the grype scanner image

Pass additional args via `GRYPE_ARGS`:
```bash
make grype IMAGE=nginx:latest GRYPE_ARGS="--fail-on high" # fail on high+ severity
make grype-compose GRYPE_ARGS="--only-fixed" # only show fixable CVEs
```
1 change: 1 addition & 0 deletions ansible/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ venv/
.venv/
.env
.env.*
!.env.example

# Keys (keep directory, ignore contents)
keys/*
Expand Down
23 changes: 17 additions & 6 deletions ansible/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ All Ansible operations via Makefile targets (runs in containers):

- `make ping` - Test connectivity to all hosts
- `make access_check` - Verify SSH and sudo access
- `make users` - Deploy user configurations
- `make proxmox` - Configure the Proxmox hosts (users, mounts, baseline)
- `make firewall` - Configure OpenBSD firewall (requires `--ask-become-pass`)
- `make felix` - Configure VPS (felix) users
- `make version` - Show Ansible version in container
Expand Down Expand Up @@ -72,7 +72,8 @@ Three host groups defined in `inventories/hosts.yml`:

### Playbook-Role Mapping

- `playbooks/users.yml` → `proxmox` hosts → `users` role
- `playbooks/proxmox.yml` → `proxmox` hosts → `users` + `nfs_mounts` roles
- `playbooks/users.yml` → `proxmox` hosts → `users` role (limited run)
- `playbooks/firewall.yml` → `openbsd_firewalls` hosts → `wireguard_server` + `openbsd_firewall` roles
- `playbooks/vps.yml` → `linode_vps` hosts → `users` role
- `playbooks/ping.yml` - Connectivity test
Expand Down Expand Up @@ -105,10 +106,20 @@ The `openbsd_firewall` role uses `ansible.builtin.raw` module exclusively (no Py

### SSH Key Management

- Private keys: `keys/deploy/` directory (gitignored)
- Public keys: `keys/deploy.pub` (committed to repo)
- SSH key paths in ansible.cfg: `private_key_file = keys/deploy`
- Users role supports both `ssh_pubkey` (literal string) and `ssh_pubkey_file` (path) formats
Two separate key directories exist:

- **`keys/`** - Deploy key only (for Ansible automation)
- `keys/deploy` - Private key (gitignored)
- `keys/deploy.pub` - Public key (committed)
- Reserved for eventual Vault/OpenBao integration
- Do NOT add user pubkeys here

- **`inventories/keys/`** - User SSH public keys for deployment to hosts
- Reference these in `managed_users` with `ssh_pubkey_file: "keys/username.pub"`
- Path is relative to inventory directory

SSH key path in ansible.cfg: `private_key_file = keys/deploy`
Users role supports both `ssh_pubkey` (literal string) and `ssh_pubkey_file` (path) formats

### Docker Configuration

Expand Down
2 changes: 1 addition & 1 deletion ansible/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ RUN apt-get update \
ca-certificates git \
&& python3 -m venv /opt/venv \
&& /opt/venv/bin/pip install --no-cache-dir --upgrade pip \
&& /opt/venv/bin/pip install --no-cache-dir ansible-core==2.16.* \
&& /opt/venv/bin/pip install --no-cache-dir ansible-core==2.16.* hvac==2.4.0 \
&& ln -s /opt/venv/bin/ansible /usr/local/bin/ansible \
&& ln -s /opt/venv/bin/ansible-playbook /usr/local/bin/ansible-playbook \
&& ln -s /opt/venv/bin/ansible-galaxy /usr/local/bin/ansible-galaxy \
Expand Down
Loading