Backup & Restore
NexusHub state lives in Postgres - peers, interfaces, rules, users, sessions, audit log. Everything else reconciles from the database on startup, so a Postgres dump is a complete backup.
What to back up
| Item | Source | Why |
|---|---|---|
| Postgres database | pg_dump nexushub |
Every user-facing configuration |
PEER_KEY_ENCRYPTION_KEY |
Environment | AEAD master for peer private keys + TOTP secrets. Losing this loses every stored key. Back up separately. |
JWT_SECRET |
Environment | Access-token signing. Losing it invalidates all sessions but no user-visible data. |
The WireGuard private keys in the database are encrypted with PEER_KEY_ENCRYPTION_KEY. A DB backup without the key is useless for restoring peer configs. Store the key somewhere durable and separate from the DB backup.
scripts/backup.sh
Auto-detects the deployment shape:
- If
docker/docker-compose.prod.ymlhas a runningpostgresservice,pg_dumpruns inside the container. - Otherwise the script sources
/etc/nexushub/envand runs host-sidepg_dumpagainst$DATABASE_URL.
./scripts/backup.sh
sudo ./scripts/backup.sh
./scripts/backup.sh /srv/backups
The script keeps the 14 most recent dumps per directory and deletes older ones. For longer retention, plug the backup directory into a rotation tool.
Scheduling
systemd timer:
# /etc/systemd/system/nexushub-backup.service
[Unit]
Description=NexusHub daily backup
[Service]
Type=oneshot
ExecStart=/opt/nexushub/scripts/backup.sh
# /etc/systemd/system/nexushub-backup.timer
[Unit]
Description=Run nexushub-backup daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
systemctl enable --now nexushub-backup.timer
cron:
0 3 * * * cd /opt/nexushub && ./scripts/backup.sh >> /var/log/nexushub-backup.log 2>&1
scripts/restore.sh
Refuses to overwrite a non-empty database without --force:
./scripts/restore.sh /var/backups/nexushub/nexushub-20260423T030001Z.sql.gz
sudo ./scripts/restore.sh /var/backups/nexushub/nexushub-...-.sql.gz --force
After a restore:
- Confirm
PEER_KEY_ENCRYPTION_KEYon the target host matches the one used when the dump was taken. - Restart the API (
systemctl restart nexushub-apiordocker compose restart api). - Log in and spot-check a peer config renders.
Point-in-time recovery
The scripts ship plain pg_dump - good enough for nightly snapshots, not enough for sub-daily RPO. For production workloads that care about the last N minutes, run Postgres with WAL archiving or a managed Postgres with automated PITR.
Disaster recovery drill
Once a quarter, restore the most recent backup into a throwaway environment and confirm:
nexushub doctorreports healthy probes.- A known peer’s
peer get <id>returns the expected config. - An audit log query for a recent action shows up.
If any step fails, the backups are not actually working. Fix before you need them.