Backups, patches and the perimeter
The boring parts that make the interesting parts safe. Nightly dumps with checksums, an off-site copy, alerts when anything stops, and a short runbook for the three situations that come up most.
Nightly schedule
Backups are kept in ~/backups with SHA-256 checksums, and every job sends a heartbeat to Uptime Kuma — a job that stops running raises a Telegram alert.
| Time (UTC) | Job | What it protects |
|---|---|---|
| 02:15 | mhf-backup | MHF Votes database + ballot count |
| 02:30 | hms-backup | Persmon HMS demo database |
| 02:45 | ishasha-backup | Ishasha Ops live database |
| 02:50 | jasper-os-backup | Jasper OS database |
| 03:00 | persmon-backup | Full archive: Coolify config, volumes, tool data, SHA-256 checksums · heartbeat to Uptime Kuma |
| 03:30 | hms-reseed | Resets the public HMS demo to clean sample data |
| */10 | oms-cron | Refreshes the OMS demo |
| */15 | jasper-os-cron | Jasper OS background jobs |
| nightly | PC pull | Off-site copy of ~/backups to Jasper's workstation |
Perimeter
- ufw firewallDefault deny. Inbound: 22, 80, 443 only. Forwarded traffic may reach containers on 80/443 (Traefik) — a port rule, not an IP rule, so it survives reboots.
- SSH hardenedKey-only login, root disabled, password auth off. Admin user
persmon; root actions go throughsudo, with a scoped no-password rule only fordocker exec(used by the Coolify API helper). - fail2banBans IPs that hammer SSH.
- unattended-upgradesSecurity patches install themselves; kernel updates wait for a chosen reboot window.
- SecretsTokens live in
~/.*files with mode 600 and in Coolify's encrypted store — never in repositories or on this site. - AlertsUptime Kuma → Telegram for outages, expiring certificates and missed backups.
Three situations and what to do
Update this website
# edit files, then they are live immediately ssh persmon-vps nano ~/persmon-dashboard/site/index.html # or copy a new build from your PC: scp -r site/* persmon-vps:~/persmon-dashboard/site/
After a Coolify update
# 1. every site answers?
for h in hello hms me coolify supabase files logs; do
printf "%-10s " $h; curl -s -o /dev/null -w "%{http_code}\n" https://$h.persmon.cloud/; done
# 2. anything restarting?
sudo docker ps --format "{{.Names}} {{.Status}}" | grep -iE "restart|unhealthy"
# 3. if a service says "permission denied" on a config file:
sudo chmod 644 /data/coolify/services/<uuid>/<file>After a reboot
uname -r; uptime -p sudo ufw status | grep FWD # port rules, not IP rules curl -sI https://hello.persmon.cloud | head -1 sudo docker ps -q | wc -l # expect 44
Restore drill
ls -t ~/backups | head ~/restore-drill.sh # restores latest dump into a scratch DB # HMS demo: ~/hms-reseed.sh reloads sample data
Where things live
| Path | Contents |
|---|---|
| /data/coolify | Coolify state, proxy config, certificates, managed file mounts |
| /var/lib/docker | Images, volumes, container layers (~20 GB) |
| ~/backups | Nightly dumps + checksums + job logs |
| ~/*.sh | Backup, reseed and cron scripts (referenced by crontab — do not move) |
| ~/persmon-dashboard/site | This website (static files, served live) |
| ~/archive | Old script copies and audit snapshots (safe to delete after 30 days) |
| ~/transfers | Large one-off files moved to or from the VPS |
| ~/files | What FileBrowser serves |
| ~/capi.sh | Coolify API helper (runs curl inside the coolify container) |
Changelog
Maintenance day: 22 packages upgraded (Docker 29.8), Coolify 4.3.18 → 4.3.23, rebooted onto kernel 6.8.0-139, 1.8 GB of unused images pruned, home folder organised. Two things broke and were fixed the same hour: the firewall rule for the proxy was pinned to a container IP and stopped matching after the reboot (now a stable port rule), and the Coolify update left Supabase's and FileBrowser's config files root-only (chmod). Jev trial connector removed. persmon.cloud launched, then rebuilt as this multi-page site.
Uganda Bookshop staging imported (catalogue + covers).
Jasper OS deployed at me.persmon.cloud with webhook deploys and 15-minute jobs; backup scripts revised, Uptime Kuma push heartbeats added for every job.
MHF Votes stack deployed in isolation for the National Sickle Cell Awards 2026.
Build phase closed; operations runbook adopted. Reboots only in chosen windows.
Postgres 17, trimmed Supabase, backups with off-site pull, Uptime Kuma + Telegram, and the utilities toolbox (n8n, Vaultwarden, FileBrowser, Dozzle, Beszel) all brought up in one long day.
VPS provisioned, hardened, Coolify installed, first app (hello) auto-deploying from GitHub.