Kieran's opinionated (and probably slightly dumb) nix config
Restic Backup System#
Per-service backup system using Restic and Backblaze B2, with automatic backup discovery from mkService data declarations.
Quick Start#
1. Create B2 Bucket#
- Go to Backblaze B2 console
- Create a new bucket (e.g.,
terebithia-backup) - Create an application key with read/write access to this bucket
- Note the Account ID, Application Key, and Bucket name
2. Create Agenix Secrets#
cd ~/dots/secrets
mkdir -p restic
# Repository encryption password
echo "choose-a-strong-encryption-password" | agenix -e restic/password.age
# B2 credentials
cat > /tmp/restic-env << 'EOF'
B2_ACCOUNT_ID="your-account-id"
B2_ACCOUNT_KEY="your-application-key"
EOF
agenix -e restic/env.age < /tmp/restic-env
rm /tmp/restic-env
# Repository URL
echo "b2:your-bucket-name:/" | agenix -e restic/repo.age
3. Add Secrets to Machine Config#
age.secrets = {
"restic/env".file = ../../secrets/restic/env.age;
"restic/repo".file = ../../secrets/restic/repo.age;
"restic/password".file = ../../secrets/restic/password.age;
};
4. Enable Backup System#
atelier.backup.enable = true;
5. Deploy and Verify#
deploy .#terebithia
# Check timers are active
ssh terebithia 'systemctl list-timers | grep restic'
Service Integration#
Automatic (mkService)#
Services using mkService with data.* declarations get automatic backup:
# In your service module
mkService {
name = "myapp";
# ...
extraConfig = cfg: {
atelier.services.myapp.data = {
sqlite = "${cfg.dataDir}/data/app.db"; # Auto WAL checkpoint + stop/start
files = [ "${cfg.dataDir}/uploads" ]; # Just backed up, no hooks
};
};
}
The backup system automatically:
- Checkpoints SQLite WAL before backup
- Stops the service during backup
- Restarts after completion
- Tags snapshots with
service:myappandtype:sqlite
Manual Registration#
For services not using mkService:
atelier.backup.services.myservice = {
paths = [ "/var/lib/myservice" ];
exclude = [ "*.log" "cache/*" ];
preBackup = "systemctl stop myservice";
postBackup = "systemctl start myservice";
};
CLI Usage#
The atelier-backup command provides an interactive TUI:
sudo atelier-backup # Interactive menu
sudo atelier-backup status # Show backup status for all services
sudo atelier-backup list # Browse snapshots
sudo atelier-backup backup # Trigger manual backup
sudo atelier-backup restore # Interactive restore wizard
sudo atelier-backup dr # Disaster recovery mode
See man atelier-backup for full documentation.
Backup Schedule#
- Time: 02:00 AM daily
- Random delay: 0-2 hours (spreads load across services)
- Retention:
- Last 3 snapshots
- 7 daily backups
- 5 weekly backups
- 12 monthly backups
Disaster Recovery#
On a fresh NixOS install:
- Rebuild from flake:
nixos-rebuild switch --flake .#hostname - Run:
atelier-backup dr - All services restored from latest snapshots
A manifest at /etc/atelier/backup-manifest.json tracks all configured backups.
Systemd Units#
Each service gets:
- Timer:
restic-backups-<service>.timer - Service:
restic-backups-<service>.service
# Check timer status
systemctl list-timers | grep restic
# View backup logs
journalctl -u restic-backups-<service>.service
# Manual backup trigger
systemctl start restic-backups-<service>.service
Testing Backups#
Always verify backups work before relying on them:
# Restore to /tmp for inspection
atelier-backup restore
# → Select service → Select snapshot → "Inspect (restore to /tmp)"
# Check restored files
ls -la /tmp/restore-myservice-*/