# Config-to-git fleet Each host snapshots its critical config to a private Gitea repo on `git.nuclide.systems` daily. Force-push (mirror only — history isn't sacred). Token: long-lived `fkrebs` PAT embedded in remote URLs (mode 0600 on script/config). ## Repos | Host | CT/VM | Repo | Schedule | Script | Source | |---|---|---|---|---|---| | PVE (`nuc`) | host | [fkrebs/pve-conf](https://git.nuclide.systems/fkrebs/pve-conf) | daily 03:00 | `/usr/local/sbin/pve-conf-backup.sh` (cron `/etc/cron.d/pve-conf-backup`) | `/etc/pve/` (excludes `priv/`, `*.key`, `authkey.pub*`) | | Zoraxy | CT 108 | [fkrebs/zoraxy-conf](https://git.nuclide.systems/fkrebs/zoraxy-conf) | daily 03:00 | `/usr/local/sbin/zoraxy-conf-backup.sh` (cron `/etc/cron.d/zoraxy-conf-backup`) | Zoraxy config dir | | AdGuard | CT 102 | [fkrebs/adguard-conf](https://git.nuclide.systems/fkrebs/adguard-conf) | daily 03:00 | `/usr/local/sbin/adguard-conf-backup.sh` (cron `/etc/cron.d/adguard-conf-backup`) | AdGuard config dir | | Home Assistant | VM 100 | [fkrebs/home-assistant-config](https://git.nuclide.systems/fkrebs/home-assistant-config) | manual cron via addon `init_commands` (see below) | `/config/scripts/git-push.sh` | `/config/` (sees `.gitignore` allowlist) | | Backrest | CT 103 | [fkrebs/ct103-conf](https://git.nuclide.systems/fkrebs/ct103-conf) | daily 03:00 | `/usr/local/sbin/ct103-conf-backup.sh` | `/opt/backrest/config/`, `/etc/cron.d/`, `/usr/local/bin/` | | Ops stack | CT 109 | [fkrebs/ct109-conf](https://git.nuclide.systems/fkrebs/ct109-conf) | daily 03:00 | `/usr/local/sbin/ct109-conf-backup.sh` | `/opt/stacks/` (excludes `*/data/`, `*.db*`), `/etc/cron.d/` | | Postgres / WAL-G | CT 113 | [fkrebs/ct113-conf](https://git.nuclide.systems/fkrebs/ct113-conf) | daily 03:00 | `/usr/local/sbin/ct113-conf-backup.sh` | `/opt/stacks/` (excludes `*/data/`), `/etc/postgresql/`, `/etc/cron.d/`, `/usr/local/bin/` | | Obsidian vault | UNAS via CT 103 | [fkrebs/obsidian-vault](https://git.nuclide.systems/fkrebs/obsidian-vault) | daily 04:00 | `/usr/local/sbin/obsidian-vault-backup.sh` | `Notizen/` (excludes sync indices, `.obsidian/`, `.trash`). Rolling 2-commit history. | | Obsidian config | manual zip drop | [fkrebs/obsidian-config](https://git.nuclide.systems/fkrebs/obsidian-config) | manual (or via Obsidian Git plugin) | `/tmp/obsidian-config-init.sh` (one-shot) | `.obsidian/` minus `workspace*.json`, `cache/`, `*.bak*` | `fkrebs/ha-config` was created in error 2026-05-24 — deleted. ## Pattern All scripts follow the same shape: ```bash #!/bin/bash set -e REPO_URL="https://fkrebs:@git.nuclide.systems/fkrebs/.git" WORK="/tmp/-work" mkdir -p "$WORK" git -C "$WORK" init -b main -q 2>/dev/null || true git -C "$WORK" config user.email "noreply@nuclide.systems" git -C "$WORK" config user.name "-backup" git -C "$WORK" remote set-url origin "$REPO_URL" 2>/dev/null \ || git -C "$WORK" remote add origin "$REPO_URL" rsync -a --delete --exclude='.git' [+ secret excludes] / "$WORK/" git -C "$WORK" add -A git -C "$WORK" commit -q -m "auto: $(date -u +%Y-%m-%dT%H:%M:%SZ)" 2>/dev/null || true git -C "$WORK" push -q --force origin main ``` PVE/CT 108/CT 102 use a rsync-to-tmp-then-push pattern. HAOS uses an in-place `git add -A` on `/config` because the `.gitignore` there is hand-curated with an allowlist for `.storage/`. ## HAOS specifics - **Path**: `/config/scripts/git-push.sh` (mode 0700, runs in the Terminal & SSH addon). - **Remote**: `https://fkrebs:@git.nuclide.systems/fkrebs/home-assistant-config.git`. Token lives in `/config/.git/config` (mode 0600). - **`.gitignore`** uses a default-deny allowlist for `.storage/` — only safe registry/lovelace/helpers/energy files are tracked. Tokens (`core.config_entries`, `mobile_app`, `androidtv_adbkey*`, etc.) are explicitly excluded. See `/config/.gitignore` on HAOS for the full list. - **Scheduling** — Terminal & SSH addon container is rebuilt on update, so its `crontabs/` are not persistent. Use the addon's `init_commands` (Configuration tab): ```yaml init_commands: - 'echo "0 3 * * * /config/scripts/git-push.sh >> /config/scripts/git-push.log 2>&1" > /etc/crontabs/root && crond -b' ``` Then **Restart** the addon. Alternative: HA automation calling `shell_command` is not viable — the `homeassistant` container doesn't have SSH to addon containers. ## Token rotation All four repos use the same PAT (`fkrebs` user, full repo scope). Rotate by: 1. Generate new PAT in Gitea → user settings → applications. 2. `git remote set-url origin https://fkrebs:@git.nuclide.systems/fkrebs/.git` on each host. 3. Manually run each script once to verify. Token leak risk: tracked in [[gitea_open_issues]]; long-term move is to switch to per-host deploy keys. ## Verification Last commit on each repo should be `auto: T03:0X:XXZ`. Quick check: ```bash for r in pve-conf zoraxy-conf adguard-conf home-assistant-config; do echo -n "$r: " curl -sk -H "Authorization: token " \ "https://git.nuclide.systems/api/v1/repos/fkrebs/$r/commits?limit=1" \ | python3 -c 'import json,sys; c=json.load(sys.stdin)[0]; print(c["commit"]["author"]["date"], c["commit"]["message"][:60])' done ``` ## Related - [[homelab-architecture]] — host topology - [[backrest-ct103]] — separate, repo-style binary backup for data (not config)