Files
docs-alpha.jayfield.org/scripts/clients/vlda-01/README.md
T
jensandClaude Sonnet 5 e9b51dbffe Check in scripts/configs, organized and documented by host OS
Every script/config built this session (sanity-check, attacker-check,
the Gitea backup pipeline on both ends) now lives in this repo as
reference copies, not just described in prose - previously they only
existed on the live servers.

Split into scripts/alpha/ (Ubuntu 24.04.4 LTS) and
scripts/clients/vlda-01/ (Unraid 7.3.2), each with its own README
stating the exact OS/kernel and a file-by-file map to deployed paths,
since a script written for one host's conventions doesn't just work
unchanged on the other - the vlda-01 README in particular documents
the persistence gotchas that actually broke earlier attempts (RAM-
backed root filesystem, VFAT /boot with no execute bit, Unassigned
Device auto-mount). Root README.md now links directly to these files
from each relevant section instead of only describing them.

Explicitly not included: the dedicated SSH private key vlda-01 uses to
authenticate to alpha - noted in clients/vlda-01/README.md to
regenerate rather than ever commit one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 17:21:05 +02:00

4.4 KiB

Scripts running on vlda-01

OS: Unraid 7.3.2, kernel 6.18.38-Unraid. Very different persistence model from Ubuntu/alpha — this tripped up the first version of every script here, so it's worth stating plainly before anything else:

  • / and /usr are RAM-backed (rootfs / an overlay on top of the read-only squashfs image loaded from the boot USB stick). Anything written there — a plain crontab, a script dropped in /usr/local/sbin — is silently gone on the next reboot. Only /boot (the actual USB stick, mounted read/write as a normal filesystem) survives.
  • /boot is VFAT, which has no concept of a Unix execute bit at all. A script stored there can never be chmod +x'd in any way that sticks — don't try to exec it directly from another script; invoke it via bash <path> instead. (The User Scripts plugin itself handles this correctly when it runs a script through the plugin — it copies the content to a RAM-backed tmp location and chmod +xs that copy before running it — but a script invoking another script directly, as the -onboot wrapper here does, has to work around it manually.)
  • Real, persistent storage lives on the array (/mnt/user/...) or on Unassigned Devices — extra disks attached but not part of the protected array, mounted at /mnt/disks/<label> — which is where these backups actually land. An Unassigned Device is not guaranteed to already be mounted when a script runs; see gitea-backup-pull's own handling of this below.
  • Scheduled tasks persist via the User Scripts plugin (already installed, already used for this box's other maintenance), which stores scripts under /boot/config/plugins/user.scripts/scripts/<name>/ and scheduling in /boot/config/plugins/user.scripts/schedule.json — both on the persistent USB stick. update_cron folds the JSON's cron-style entries into the live /etc/cron.d/root at every boot; "frequency": "boot" entries instead run once via the plugin's own disks_mounted array-start event hook, not through cron at all.
  • SSH keys under /root/.ssh needed no special persistence handling — Unraid already auto-mirrors that whole directory to /boot/config/ssh/root/ on its own.

Files, and where they're actually deployed

File here Deployed path Purpose
user-scripts/gitea-backup-pull/script /boot/config/plugins/user.scripts/scripts/gitea-backup-pull/script Pulls new gitea-dump archives from alpha via the restricted giteabackup SFTP account, verifies each one's sha256 checksum, deletes both files on alpha only after a confirmed match, prunes its own local retention (30). Resolves and mounts the WSD2L840 Unassigned Device itself first — see the script's own header comment for the full reasoning.
user-scripts/gitea-backup-pull/description .../gitea-backup-pull/description Shown in the User Scripts UI.
user-scripts/gitea-backup-pull-onboot/script .../gitea-backup-pull-onboot/script One-line wrapper: bash-invokes the script above. Exists only because schedule.json supports one schedule per script path — this is how the "also run once at every restart" requirement was added alongside the existing daily 03:30 schedule without disturbing it.
user-scripts/gitea-backup-pull-onboot/description .../gitea-backup-pull-onboot/description Shown in the User Scripts UI.
user-scripts/schedule.json /boot/config/plugins/user.scripts/schedule.json Whole file, as deployed — includes entries for this box's other, pre-existing scheduled maintenance (delete_dangling_images, rc.fancontrol, etc.) that predate this project and aren't described elsewhere in this repo. Only the gitea-backup-pull and gitea-backup-pull-onboot entries near the bottom belong to this project.

Redeploying from this checked-in copy

# on vlda-01:
mkdir -p /boot/config/plugins/user.scripts/scripts/gitea-backup-pull
mkdir -p /boot/config/plugins/user.scripts/scripts/gitea-backup-pull-onboot
# copy script/description files into place from this repo, then:
cp /boot/config/plugins/user.scripts/schedule.json /tmp/user.scripts/schedule.json
/usr/local/sbin/update_cron

The dedicated ed25519 keypair this depends on (/root/.ssh/gitea-backup/, authorized on alpha's giteabackup account) is not in this repo — regenerate it and re-authorize the new public key on alpha rather than ever committing a private key here.