Scheduled volume backups with restic — a periodic Nomad batch job that snapshots the Docker named volumes you list to an S3-compatible repository (e.g. the seaweedfs pack), with encryption and retention/pruning.
Save as values.hcl, edit, then run:
# The name of the Nomad job.
job_name = "backup"
# The Nomad namespace to deploy into.
namespace = "default"
# The datacenters to deploy to.
datacenters = ["*"]
# The restic container image.
image = "restic/restic:latest"
# Docker named volumes to back up (e.g. ["postgres_data", "gitea_data"]). Each is mounted read-only and snapshotted. REQUIRED — an empty list backs up nothing. Named volumes are node-local, so pin this job (constraints) to the node that holds them.
volumes = []
# Backup schedule (Nomad periodic cron). Default: daily at 03:00.
cron = "0 3 * * *"
# Time zone for the cron schedule (IANA name, e.g. Europe/Bratislava).
time_zone = "UTC"
# restic repository URL. For the seaweedfs pack: s3:http://<node-ip>:8333/<bucket>. The bucket/target must already exist. restic init runs automatically on first backup.
repository = "s3:http://127.0.0.1:8333/backups"
# Password that encrypts the restic repository. CHANGE THIS and keep it safe — without it the backups are unrecoverable.
restic_password = "changeme"
# S3 access key for the repository (AWS_ACCESS_KEY_ID). Empty for an open S3 target.
access_key = ""
# S3 secret key for the repository (AWS_SECRET_ACCESS_KEY).
secret_key = ""
# Retention: number of daily snapshots to keep.
keep_daily = 7
# Retention: number of weekly snapshots to keep.
keep_weekly = 4
# Retention: number of monthly snapshots to keep.
keep_monthly = 6
# Placement constraints — REQUIRED in practice: pin to the node holding the named volumes. On a nomploy cluster: attribute = "$${meta.nomploy_control_plane}", operator = "=", value = "true".
constraints = []
# The task resources.
resources = {
cpu = 500
memory = 512
}
| Name | Type | Default | Description |
|---|---|---|---|
| job_name | string | "backup" | The name of the Nomad job. |
| namespace | string | "default" | The Nomad namespace to deploy into. |
| datacenters | list | ["*"] | The datacenters to deploy to. |
| image | string | "restic/restic:latest" | The restic container image. |
| volumes | list | [] | Docker named volumes to back up (e.g. ["postgres_data", "gitea_data"]). Each is mounted read-only and snapshotted. REQUIRED — an empty list backs up nothing. Named volumes are node-local, so pin this job (constraints) to the node that holds them. |
| cron | string | "0 3 * * *" | Backup schedule (Nomad periodic cron). Default: daily at 03:00. |
| time_zone | string | "UTC" | Time zone for the cron schedule (IANA name, e.g. Europe/Bratislava). |
| repository | string | "s3:http://127.0.0.1:8333/backups" | restic repository URL. For the seaweedfs pack: s3:http://<node-ip>:8333/<bucket>. The bucket/target must already exist. restic init runs automatically on first backup. |
| restic_password set me | string | "changeme" | Password that encrypts the restic repository. CHANGE THIS and keep it safe — without it the backups are unrecoverable. |
| access_key key | string | "" | S3 access key for the repository (AWS_ACCESS_KEY_ID). Empty for an open S3 target. |
| secret_key key | string | "" | S3 secret key for the repository (AWS_SECRET_ACCESS_KEY). |
| keep_daily | number | 7 | Retention: number of daily snapshots to keep. |
| keep_weekly | number | 4 | Retention: number of weekly snapshots to keep. |
| keep_monthly | number | 6 | Retention: number of monthly snapshots to keep. |
| constraints | list | [] | Placement constraints — REQUIRED in practice: pin to the node holding the named volumes. On a nomploy cluster: attribute = "$${meta.nomploy_control_plane}", operator = "=", value = "true". |
| resources | object | {
cpu = 500
memory = 512
} | The task resources. |
No variables match.
Scheduled volume backups with restic — a periodic Nomad batch
job that snapshots the Docker named volumes you list to an S3-compatible repository
(pairs with the seaweedfs pack), encrypted and with automatic retention/pruning.
This is the safety net for the stateful packs (postgres, mariadb, gitea, vaultwarden, …).
nomad-pack registry add nomploy github.com/Nomploy/nomad-packs
nomad-pack run backup --registry nomploy \
--var 'volumes=["postgres_data","gitea_data"]' \
--var 'repository=s3:http://<node-ip>:8333/backups' \
--var 'restic_password=<a-strong-secret>' \
--var 'access_key=<s3-key>' --var 'secret_key=<s3-secret>'
In nomploy: create a Compose service, type Nomad Pack, pack backup, set the variables,
then Deploy. Trigger a run immediately with nomad job periodic force backup.
cron (default daily 03:00) as a batch job with
prohibit_overlap.volumes read-only under /data/<name> and runs
restic backup /data.restic inits the repository; afterwards it appends snapshots and
runs restic forget --prune per the retention policy.| Variable | Default | Notes |
|---|---|---|
volumes |
[] |
Required. Named volumes to back up, e.g. ["postgres_data"]. |
repository |
s3:http://127.0.0.1:8333/backups |
restic repo URL (seaweedfs/S3). The bucket must exist. |
restic_password |
changeme |
Change it and keep it safe — no password, no restore. |
access_key / secret_key |
"" |
S3 credentials for the repository. |
cron / time_zone |
0 3 * * * / UTC |
Schedule. |
keep_daily / keep_weekly / keep_monthly |
7 / 4 / 6 |
Retention. |
constraints |
[] |
Pin to the node holding the volumes (they're node-local). |
constraints to the
node where the source packs run — otherwise the volumes won't be there to back up.pg_dump,
mariadb-dump) into a volume and back that up, or quiesce the DB during the window.restic at the same repository + password
(restic snapshots, restic restore <id> --target /restore). Store the password
somewhere safe and separate.aws --endpoint-url … s3 mb s3://backups).