Network backups (restic)
The darkone.service.restic module backs up fleet hosts with
restic 🡕: each host (client) pushes its data to a
repository, either local or remote via a zone REST server.
Principles
Section titled “Principles”Two roles, one module:
- REST server: a host that declares the
resticservice inconfig.yaml. It stores repositories for all hosts and listens on the internal network. - Client: any host with
enable = truethat declarestargets(backup destinations).
Repository layout, by category:
<root>/<host>/system # "system" category (/ minus exclusions)<root>/<host>/srv/nfs # "nfs" category (/srv/nfs/<...>)<root>/<host>/srv/medias # "media" category (/srv/medias/<...>)Setting up a backup server
Section titled “Setting up a backup server”-
In
etc/config.yaml, add theresticservice to the server host:services:restic: -
Attach the backup disk and mount it on
/mnt/backupin the host configuration (usr/machines/<host>/), with thenofailoption:fileSystems."/mnt/backup" = {device = "/dev/disk/by-uuid/<uuid>";fsType = "ext4";options = [ "nofail" ];};# The REST server only starts once the disk is mounted.systemd.services.restic-rest-server = {requires = [ "mnt-backup.mount" ];after = [ "mnt-backup.mount" ];}; -
The repository is stored under
serverDataDir(default/mnt/backup/restic). The firewall opens the REST port on the internal interface automatically.
Adding a client
Section titled “Adding a client”Declare one or more targets in the host configuration:
darkone.service.restic = { enable = true; targets = [ { # Remote repository via the zone REST server. root = "rest:http://restic.zone.domain.tld:8888"; zone = "ag"; categories = [ "system" "nfs" ]; } ];};target fields:
| Field | Role |
|---|---|
name | Identifier (default main), suffix for jobs/units. |
root | Local path or URL rest://. |
zone | Zone selecting the restic-password-<zone> passphrase. |
categories | Data to back up: system, nfs, medias. |
Generating passwords
Section titled “Generating passwords”An idempotent recipe creates missing secrets (never overwrites):
just passwd-resticIt generates, in usr/secrets/secrets.yaml:
- one
restic-password-<zone>passphrase per zone; - one
restic/<host>/rest-passwordcredential per fleet host.
Hardening repository isolation
Section titled “Hardening repository isolation”By default, the server allows any authenticated host to access any
repository. The enableServerPrivateRepos option enforces that each host can
only access its own repository (prefix = hostname). Activate it in two steps
to avoid any disruption:
- Deploy the entire fleet with per-host credentials (clients + servers),
enableServerPrivateRepos = false. Verify that backups work. - Set
enableServerPrivateRepos = trueand redeploy the servers.
Restoring
Section titled “Restoring”On the target host, secrets are already in place. List then restore:
# REST access variables (generated by sops) and repository passphrase.set -a; . /run/secrets/rendered/restic-rest-env; set +aexport RESTIC_PASSWORD_FILE=/run/secrets/restic-password-agexport RESTIC_REPOSITORY=rest:http://restic.zone.domain.tld:8888/$(hostname)/system
restic snapshotsrestic restore latest --target /restoreVerifying
Section titled “Verifying”-
On a server, one account per fleet host in the htpasswd file:
Fenêtre de terminal sudo cut -d: -f1 /run/restic-rest/htpasswd -
On a client, run an on-demand backup:
Fenêtre de terminal systemctl start restic-backups-system-main.servicejournalctl -u restic-backups-system-main.service -e -
Isolation (if
enableServerPrivateRepos = true): access to another host’s repository must be denied (401/403 error).