Backup & Restore — VayuPress Operations
Last reviewed: 2026-06-13
What Must Be Backed Up
| Item | Location | Frequency | Method |
|---|---|---|---|
| SQLite DB | /data/vayupress.db |
Daily + WAL shipping | SQLite Online Backup API |
| Signing private key | /etc/vayupress/signing.key |
On creation/rotation | Encrypted cold storage |
| Plugin binaries | /opt/vayupress/plugins/ |
On install/update | File copy |
| Nginx config | /etc/nginx/conf.d/vayupress.conf |
On change | Git-tracked |
| Systemd unit | /etc/systemd/system/vayupress.service |
On change | Git-tracked |
| TLS certificate | Managed by certbot | Auto-renewed | certbot backup |
| Archive objects | /data/archives/ |
Continuous | Content-addressed; immutable |
Automated Backup (Daily)
The deploy/backup.sh script (or systemd timer) performs:
#!/usr/bin/env bash
set -euo pipefail
DEST="/backup/vayupress/$(date +%Y%m%d-%H%M%S)"
mkdir -p "${DEST}"
# SQLite online backup (safe while DB is live)
sqlite3 /data/vayupress.db ".backup '${DEST}/vayupress.db'"
# Plugin binaries
cp -a /opt/vayupress/plugins/ "${DEST}/plugins/"
# Verify backup integrity
sqlite3 "${DEST}/vayupress.db" "PRAGMA integrity_check;" | grep -q "^ok$"
# Rotate: keep last 30 days
find /backup/vayupress -maxdepth 1 -type d -mtime +30 -exec rm -rf {} +
echo "Backup complete: ${DEST}"
Schedule via systemd timer:
# /etc/systemd/system/vayupress-backup.timer
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
Restore Procedure
# 1. Stop service
systemctl stop vayupress
# 2. Choose backup
BACKUP_DIR=$(ls -td /backup/vayupress/*/ | head -1)
echo "Restoring from: ${BACKUP_DIR}"
# 3. Verify backup before restore
sqlite3 "${BACKUP_DIR}/vayupress.db" "PRAGMA integrity_check;" | grep -q "^ok$"
# 4. Restore DB
cp "${BACKUP_DIR}/vayupress.db" /data/vayupress.db
rm -f /data/vayupress.db-wal /data/vayupress.db-shm
# 5. Restore plugins if needed
cp -a "${BACKUP_DIR}/plugins/" /opt/vayupress/plugins/
# 6. Verify signing key is present (not backed up here — comes from cold storage)
test -f /etc/vayupress/signing.key || echo "WARNING: signing key missing — restore from cold storage"
# 7. Start service
systemctl start vayupress
journalctl -u vayupress -f
# 8. Smoke test
curl -sf http://localhost:8080/healthz | jq .
Restore Verification Checklist
After every restore (planned or emergency):
-
PRAGMA integrity_checkreturnsok - Article count matches expected (compare with monitoring baseline)
-
/healthzreturns 200 - At least one article renders correctly with valid signature
- Plugin subprocess starts (check logs for
started plugin subprocess) - Metrics endpoint responds:
curl http://localhost:8080/metrics - No
level=errorentries in first 5 minutes of logs
Signing Key — Cold Storage Procedure
The Ed25519 signing key is not stored in the automated backup.
It must be stored separately in encrypted cold storage (e.g., age-encrypted file on offline media).
# Encrypt key for cold storage (requires age)
age -r <recipient-public-key> /etc/vayupress/signing.key > signing.key.age
# Decrypt for restore
age -d -i <recipient-private-key> signing.key.age > /etc/vayupress/signing.key
chmod 600 /etc/vayupress/signing.key
chown vayupress: /etc/vayupress/signing.key