Off-site Backups from NixOS to Hetzner Storage Box with Restic
I run a small NAS at home built on NixOS and ZFS. While ZFS gives me local redundancy and snapshots, I wanted true off-site protection in case of disasters like fire, theft, or hardware failure. After evaluating a few options, I settled on Hetzner’s Storage Box: it’s affordable, reliable, and supports SFTP out of the box. Using Restic for encrypted, deduplicated backups seemed like the perfect match.
I initially considered using ZFS snapshots as the backup source, but ultimately decided against it—I needed straightforward file-level backups of specific directories, and snapshots added complexity I didn’t require for this use case.
Prerequisites #
You’ll need:
- Hetzner Storage Box with a subaccount created:
- Main account:
u123456 - Subaccount:
u123456-sub1 - Hostname:
u123456-sub1.your-storagebox.de - SFTP/SSH runs on port 23 (not the standard 22)
- Main account:
- SSH keypair generated on your NixOS machine for passwordless authentication
- Restic password stored securely (we’ll use
/run/keys/restic-password.txt) - Directories to back up, for example:
/storage/photos/storage/files
Step 1: Configure SSH for the Storage Box subaccount #
Hetzner Storage Box uses port 23 for SFTP, and subaccounts are chrooted into their home directory. Since the NixOS Restic service runs as root by default, we’ll configure SSH in root’s profile.
Create or edit /root/.ssh/config:
Host u123456-sub1.your-storagebox.de
User u123456-sub1
Port 23
IdentityFile /root/.ssh/id_storagebox
StrictHostKeyChecking yes
Generate an SSH key if you don’t have one:
ssh-keygen -t ed25519 -f /root/.ssh/id_storagebox -C "Backup to Hetzner"
chmod 600 /root/.ssh/id_storagebox
Add the public key to your Storage Box subaccount:
- Log into the Hetzner Console
- Navigate to your Storage Box
- Select the subaccount
- Add the contents of
/root/.ssh/id_storagebox.pubas an authorized key (OpenSSH format for port 23)
Step 2: Trust the Storage Box host key #
To enable non-interactive backups via systemd, we need to trust the Storage Box’s SSH host key. Connect once as root:
sudo -i
ssh -p 23 u123456-sub1@u123456-sub1.your-storagebox.de
Type yes when prompted to save the host key to /root/.ssh/known_hosts.
Alternatively, use ssh-keyscan (but verify the fingerprint matches what Hetzner provides):
ssh-keyscan -p 23 u123456-sub1.your-storagebox.de >> /root/.ssh/known_hosts
Step 3: Create the repository directory #
Subaccounts on Hetzner Storage Box are restricted to their home directory. The repository must be created inside /home, not at the filesystem root.
Connect to your Storage Box and create the directory:
ssh -p 23 u123456-sub1@u123456-sub1.your-storagebox.de
mkdir -p /home/nas-backup
exit
Important: Paths like /nas-backup (at root) will fail with SSH_FX_FAILURE errors. Always use /home/<directory> for subaccounts.
Step 4: Configure Restic in NixOS #
Add the following to your configuration.nix:
services.restic.backups.nas-backup = {
# Repository location on Hetzner Storage Box (subaccount)
repository = "sftp:u123456-sub1@u123456-sub1.your-storagebox.de:/home/nas-backup";
# File containing your Restic repository password (not SSH password)
passwordFile = "/run/keys/restic-password.txt";
# Paths to back up (file-level, not snapshots)
paths = [
"/storage/photos"
"/storage/files"
];
# Automatically initialize the repository if it doesn't exist
initialize = true;
# Backup schedule: daily at midnight, with persistence for missed runs
timerConfig = {
OnCalendar = "daily";
Persistent = true;
};
# Retention policy: keep 7 daily, 4 weekly, and 12 monthly snapshots
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 12"
];
};
Create the password file:
echo "your-secure-restic-password" > /run/keys/restic-password.txt
chmod 600 /run/keys/restic-password.txt
For best practices, consider using a proper secrets management solution like agenix or sops-nix.
Make sure to keep a copy of your Restic password in a safe place, as losing it means losing access to your backups.
Step 5: Apply configuration and test #
Rebuild your NixOS configuration:
sudo nixos-rebuild switch
Start the backup service manually to test:
sudo systemctl start restic-backups-nas-backup
Warning: this is going to take some time, it’s not asynchronous. Do not kill the process.
Monitor the logs:
journalctl -u restic-backups-nas-backup -f
If everything is configured correctly, you should see Restic initializing the repository (if needed) and starting the first backup.
Restoring data #
List available snapshots:
restic -r sftp:u123456-sub1@u123456-sub1.your-storagebox.de:/home/nas-backup snapshots
Restore the latest snapshot:
restic -r sftp:u123456-sub1@u123456-sub1.your-storagebox.de:/home/nas-backup restore latest --target /restore-target
Restore a specific file:
restic -r sftp:u123456-sub1@u123456-sub1.your-storagebox.de:/home/nas-backup restore latest --target /restore-target --include /storage/photos/vacation.jpg
Common issues and solutions #
“Host key verification failed”
- Solution: Connect manually once as root to add the host key, or use
ssh-keyscan
“SSH_FX_FAILURE” when creating repository
- Solution: Ensure your repository path is under
/home(e.g.,/home/nas-backup), not at root
Restic can’t connect on the correct port
- Solution: Verify
/root/.ssh/confighasPort 23set for the host. Restic relies on SSH config, not URL syntax
“Permission denied” errors
- Solution: Verify your SSH key is correctly added to the subaccount in Hetzner Console, and the private key has correct permissions (600)
Service uses wrong SSH key
- Solution: The NixOS Restic service runs as root by default. Keys must be in
/root/.ssh/
Why not ZFS snapshots? #
ZFS snapshots provide point-in-time consistency, which is valuable for databases and other rapidly-changing data. For my use case—backing up relatively static file directories like photos and documents—file-level backups were simpler and sufficient. If you need crash-consistent backups of live databases or VMs, consider backing up from ZFS snapshot paths like /storage/data/.zfs/snapshot/daily.
Conclusion #
With this setup, I have automated, encrypted, off-site backups running daily from my NixOS NAS to a Hetzner Storage Box. The configuration is fully declarative, easy to reproduce, and leverages NixOS’s built-in Restic service module. The key gotchas—port 23, host key trust, and subaccount home directory restrictions—are all handled cleanly in the SSH config and repository path.
Total setup time: about 15 minutes. Peace of mind: priceless.