Off-PA backups — the local (Mac) leg
Off-PA backups — the local (Mac) leg
This is one of two legs that get the Cockpit’s gitignored server-state off PythonAnywhere:
| Leg | Runs on | Where it lands | Set up via |
|---|---|---|---|
| Bunny | PA (cron) | Bunny storage-only zone | backup_offsite.py + BUNNY_BACKUP_* env |
| Local (this dir) | your Mac (launchd) | ~/pa-backups/ |
pull-backups.sh + the plist |
Together with PA’s own ~/db-backups/ sweep (backup_all.py), every at-risk
file exists in three places. Canonical plan: .kt/BACKUP_AND_RECOVERY.md §5.
Why the Mac pulls instead of PA pushing
PA is always up and reachable; a laptop isn’t. A PA→Mac push would silently miss every window the Mac is asleep or on another network. A Mac→PA pull grabs the backups whenever the Mac is awake, using the passwordless SSH key the Cockpit deploy flow already relies on. PA is the always-on side, so it’s the side you reach toward.
One-time setup
-
Confirm SSH works (paid PA accounts have SSH; the key is already installed if
git pullon PA works passwordlessly):ssh aaronaiken@ssh.pythonanywhere.com 'ls db-backups/ | tail -3'If that prints recent
*.YYYYMMDD-HHMMSSfiles, you’re good. If it prompts for a password, add your key:ssh-copy-id aaronaiken@ssh.pythonanywhere.com. -
Test the pull manually:
./pull-backups.sh ls -la ~/pa-backups/ | tail -
Schedule it (daily 10:00 local + at load):
cp com.aaronaiken.pa-backups.plist ~/Library/LaunchAgents/ launchctl load ~/Library/LaunchAgents/com.aaronaiken.pa-backups.plistVerify it’s registered:
launchctl list | grep pa-backups.
Config (env overrides — all optional)
| Var | Default | Meaning |
|---|---|---|
PA_SSH |
aaronaiken@ssh.pythonanywhere.com |
SSH target |
PA_REMOTE_DIR |
db-backups/ |
remote dir (relative to PA home) |
LOCAL_DIR |
$HOME/pa-backups |
where the copy lands |
Notes
- No
--delete. The Mac keeps a deeper history than PA’s 30-per-file prune — old snapshots are the point of a backup. Trim~/pa-backups/by hand if it ever grows large (du -sh ~/pa-backups). - Logs:
~/pa-backups/pull.log(script) +launchd.{out,err}.log(agent). - Uninstall:
launchctl unload ~/Library/LaunchAgents/com.aaronaiken.pa-backups.plist && rm ~/Library/LaunchAgents/com.aaronaiken.pa-backups.plist - Moved the repo? Update the script path inside the plist and reload.
Restore
To restore a file from the local copy, it’s just a normal file — pick the
timestamp you want and copy it back (stop Flask on PA first). Full procedure:
.kt/BACKUP_AND_RECOVERY.md §4.