Skip to content
NullString1 edited this page Jan 13, 2026 · 2 revisions

Backup and Restore

Guide to NullOS's automated backup system using Restic.

Overview

NullOS includes Restic for encrypted, incremental backups to various backends.

Configuration File: modules/services/backup.nix

Features:

  • Encrypted backups
  • Incremental (only changed files)
  • Automated scheduling
  • Multiple retention policies
  • Various storage backends

Current Configuration

Backup Job: nsdata

Backs up:

  • /mdata directory
  • /home/${username} directory

Schedule:

  • 1 minute after boot
  • Every hour thereafter

Retention:

  • Last 10 backups
  • Daily for 7 days
  • Weekly for 4 weeks
  • Monthly for 6 months

Configuration

Basic Setup

# modules/services/backup.nix
{
  services.restic.backups.nsdata = {
    repository = vars.resticRepository;
    passwordFile = "/etc/nixos/secrets/restic-password";
    
    paths = [
      "/home/${vars.username}"
    ];
    
    exclude = [
      "/home/${vars.username}/.cache"
      "**/node_modules"
    ];
    
    pruneOpts = [
      "--keep-last 7"
      "--keep-daily 7"
      "--keep-weekly 4"
      "--keep-monthly 6"
    ];
    
    timerConfig = {
      OnCalendar = "daily";
    };
  };
}

Repository Configuration

In variables.nix:

resticRepository = "sftp:user@server:/backups/laptop";

Supported backends:

  • Local: /mnt/backup
  • SFTP: sftp:user@server:/path
  • S3: s3:s3.amazonaws.com/bucket
  • B2: b2:bucket-name
  • Azure: azure:container-name:/
  • REST: rest:https://backup.server

Setting Up Backups

1. Create Password File

sudo mkdir -p /etc/nixos/secrets
echo "your-strong-password" | sudo tee /etc/nixos/secrets/restic-password
sudo chmod 600 /etc/nixos/secrets/restic-password

2. Configure Repository

# In variables.nix
resticRepository = "sftp:user@backup-server.com:/backups/nslapt";

3. Rebuild System

sudo nixos-rebuild switch --flake .#hostname

4. Verify Backup

systemctl status restic-backups-nsdata

Manual Backup Operations

Run Backup Now

sudo systemctl start restic-backups-nsdata

Check Backup Status

systemctl status restic-backups-nsdata
journalctl -u restic-backups-nsdata -f

List Backups

sudo restic -r sftp:user@server:/backups snapshots

Check Repository

sudo restic -r sftp:user@server:/backups check

Restoring Files

List Files in Backup

sudo restic -r sftp:user@server:/backups ls latest

Restore Specific File

sudo restic -r sftp:user@server:/backups restore latest \
  --target /tmp/restore \
  --include /home/user/important-file.txt

Restore Entire Backup

sudo restic -r sftp:user@server:/backups restore latest \
  --target /tmp/restore

Restore to Original Location

sudo restic -r sftp:user@server:/backups restore latest \
  --target /

Warning: Be careful with this! It will overwrite files.


Exclusions

Current Exclusions

The default configuration excludes:

  • Cache directories
  • Build artifacts (target/, node_modules/)
  • IDE files
  • Temporary files
  • Large development tools

Adding Exclusions

exclude = [
  # Existing exclusions...
  "/home/${vars.username}/Downloads"
  "**/.git"
  "*.tmp"
];

Retention Policies

Understanding Retention

pruneOpts = [
  "--keep-last 10"     # Keep last 10 backups
  "--keep-daily 7"     # Keep 7 daily backups
  "--keep-weekly 4"    # Keep 4 weekly backups
  "--keep-monthly 6"   # Keep 6 monthly backups
  "--keep-yearly 2"    # Keep 2 yearly backups
];

Conservative Policy (More Backups)

pruneOpts = [
  "--keep-last 14"
  "--keep-daily 14"
  "--keep-weekly 8"
  "--keep-monthly 12"
  "--keep-yearly 5"
];

Aggressive Policy (Less Storage)

pruneOpts = [
  "--keep-last 5"
  "--keep-daily 3"
  "--keep-weekly 2"
  "--keep-monthly 3"
];

Backup Schedule

Current Schedule

timerConfig = {
  OnBootSec = "1m";        # 1 minute after boot
  OnUnitActiveSec = "1h";  # Every hour
};

Daily Backups

timerConfig = {
  OnCalendar = "daily";
  Persistent = true;
};

Specific Time

timerConfig = {
  OnCalendar = "02:00";    # 2 AM daily
  Persistent = true;
};

Multiple Times

timerConfig = {
  OnCalendar = [ "02:00" "14:00" ];  # 2 AM and 2 PM
};

Remote Backup Setup

SFTP Backup

  1. Generate SSH key:
ssh-keygen -t ed25519 -f /root/.ssh/restic_backup
  1. Copy to server:
ssh-copy-id -i /root/.ssh/restic_backup user@backup-server
  1. Configure repository:
resticRepository = "sftp:user@backup-server:/backups";

S3 Backup

resticRepository = "s3:s3.amazonaws.com/my-backup-bucket";

# Set credentials
environmentFile = "/etc/nixos/secrets/restic-s3-env";

Content of /etc/nixos/secrets/restic-s3-env:

AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key

Performance Tuning

Reduce Resource Usage

systemd.services.restic-backups-nsdata.serviceConfig = {
  Nice = 19;                      # Lowest CPU priority
  IOSchedulingClass = "idle";     # Lowest I/O priority
};

Increase Performance

extraOptions = [
  "--limit-upload 1000"   # KB/s upload limit
  "--limit-download 1000"
  "--pack-size 32"        # MB pack size
];

Monitoring

Email Notifications

services.restic.backups.nsdata = {
  # ... existing config ...
  
  # Run script after backup
  backupPrepareCommand = "echo 'Backup starting'";
  backupCleanupCommand = "echo 'Backup finished'";
};

Check Backup Age

#!/usr/bin/env bash
LAST_BACKUP=$(sudo restic -r $REPO snapshots --json | jq -r '.[0].time')
AGE_HOURS=$(( ($(date +%s) - $(date -d "$LAST_BACKUP" +%s)) / 3600 ))

if [ $AGE_HOURS -gt 48 ]; then
  notify-send "Backup Warning" "Last backup was $AGE_HOURS hours ago"
fi

Multiple Backup Jobs

Separate Jobs for Different Paths

services.restic.backups = {
  home = {
    repository = "sftp:server:/backups/home";
    paths = [ "/home" ];
    timerConfig.OnCalendar = "daily";
  };
  
  projects = {
    repository = "s3:bucket/projects";
    paths = [ "/mdata/projects" ];
    timerConfig.OnCalendar = "hourly";
  };
  
  config = {
    repository = "/mnt/external/config";
    paths = [ "/etc/nixos" ];
    timerConfig.OnCalendar = "weekly";
  };
};

Disaster Recovery

Full System Restore

  1. Boot from NixOS live USB
  2. Mount partitions:
mount /dev/sdXn /mnt
mount /dev/sdXm /mnt/boot
  1. Restore NixOS config:
restic -r sftp:server:/backups restore latest \
  --target /mnt \
  --include /etc/nixos
  1. Restore home:
restic -r sftp:server:/backups restore latest \
  --target /mnt \
  --include /home
  1. Reinstall NixOS:
nixos-install --root /mnt

Best Practices

  1. Test Restores Regularly - Verify backups work
  2. Monitor Backup Success - Check logs weekly
  3. Off-site Backups - Use remote repository
  4. Encrypt Repository - Always use password
  5. Document Recovery - Keep recovery notes
  6. Version Configuration - Git for NixOS config
  7. Multiple Destinations - Redundant backups

Troubleshooting

Backup Failing

Check logs:

journalctl -u restic-backups-nsdata -n 50

Permission Denied

Ensure service runs as correct user:

services.restic.backups.nsdata.user = vars.username;

Repository Locked

sudo restic -r sftp:server:/backups unlock

Out of Space

Prune old backups:

sudo restic -r sftp:server:/backups prune

Next Steps

Clone this wiki locally