# CLAUDE.md ## What this repo is Git-based provisioning and recovery repo for the "argento" home server (Rocky Linux 9, ZFS, Docker). The repo lives at `/opt/argento/` on the server and contains the actual running configs. This dev copy at `~/dev/argento` is where edits happen, then files are manually copied to the server. Recovery steps are in `RUNBOOK.md`. Repo overview and workflows are in `README.md`. ## Architecture notes not in the docs - **Docker shared network**: Created by the nginx compose file. All Docker apps that nginx proxies to join this network as `external: true`. If nginx compose hasn't been started, other apps will fail with "network shared not found". - **nginx variable upstreams**: `nginx.conf` uses `resolver 127.0.0.11` (Docker DNS). Confs that proxy to container names use `set $upstream_` variables so nginx resolves at request time, not startup. Without this, one down container prevents nginx from starting at all. - **host.docker.internal**: Used for services running on the host network (Jellyfin, Cockpit). Requires `extra_hosts: ["host.docker.internal:host-gateway"]` in nginx's compose.yaml. - **Jellyfin uses host network**: Needs direct access to NVIDIA GPU for hardware transcoding. Proxied via `host.docker.internal:8096`. - **Cockpit (argento.timothykim.net)**: Runs directly on the host (not Docker) on port 9090 with self-signed TLS. The nginx conf inlines security headers instead of including security-headers.inc because Cockpit's internal iframes break with X-Frame-Options: DENY. Cockpit has a known bug where font files return 404 — this is not a proxy issue. - **Minecraft HTTP-only**: HTTPS causes WebSocket/CORS errors with the MCSManager daemon. No cert issued for this domain. - **SSL cert issuance chicken-and-egg**: On fresh recovery, certs don't exist so SSL confs can't load. The `.hold` pattern moves SSL confs aside, starts nginx with HTTP-only confs, issues certs, then restores SSL confs. - **SELinux is enforcing**: Caused issues with samba (symlinks blocked, parent directory traversal blocked). Don't use symlinks for config files — use the sync-system.sh copy approach instead. - **Secrets in .env files**: All secrets (DB passwords, API keys, tokens) live in `.env` files under each app's `docker//` directory on the server. These are gitignored (`**/.env` in root `.gitignore`). The `.env` files are included in the USB backup. If the backup is lost, all secrets can be recreated from Bitwarden. The `system/msmtprc` in the repo has its password REDACTED -- the real one is only on the server. - **ZFS parent dataset mountpoints**: Pools have parent datasets (e.g., `nextcloud`, `threeteras`) that create mountpoints like `/mnt/nextcloud`. These are empty and expected — do not delete them. - **msmtp**: Replaces sendmail for cron MAILTO and smartd email alerts. Configured via `/etc/msmtprc` (Fastmail SMTP). The symlink `/usr/sbin/sendmail -> /usr/bin/msmtp` is set up in recovery step 2. - **hantim-server**: Sister repo with similar nginx/certbot patterns. Located at `~/dev/hantim-server`. Useful as reference for deploy patterns. ## Remotes - **origin**: Gitea on argento (private) - **GitHub mirror**: Push mirror configured in Gitea repo settings (survives if argento dies) ## Working preferences - Don't edit compose files in this repo — Timothy edits those directly on the server. Compose changes here get rejected. - Comments in config files should explain the real WHY for this specific app, not generic descriptions of what a directive does. - Don't add redundant documentation. If something is already on disk (e.g., crontab contents), don't repeat it in the docs. - Keep docs linear and non-confusing. Avoid branching flows that duplicate steps. - When proposing config changes, explain the flags/options — Timothy wants to understand what he's committing, not blindly trust it. - No emojis in any files. - Verify suggestions actually work before confidently recommending them. If unsure, say so.