Dockup reads one YAML file, by default /etc/dockup/dockup.yml (override with --config or DOCKUP_CONFIG). Per-source policy is not configured here: it lives on volume and container labels, see Labels reference.
host: nas-01
listen: ":9779"
state-dir: /var/lib/dockup
tmp-dir: /var/lib/dockup/tmp
timezone: Europe/Berlin
log-level: info
log-format: json
max-concurrent: 1
helper-image: gitea.vladfaust.com/vladfaust/dockup:latest| Key | Default | Description |
|---|---|---|
host | container hostname | Identifies this host in archive keys. Set it explicitly (compose hostname:) — the default is the container id. |
listen | :9779 | Address for /healthz, /readyz and /metrics. |
state-dir | /var/lib/dockup | SQLite state, the instance lock and the spool directory. Use a persistent volume. |
tmp-dir | <state-dir>/tmp | Where archives are spooled before upload. Must hold the largest compressed archive. |
timezone | UTC | IANA name used by cron schedules and retention buckets. |
log-level | info | debug, info, warn, error. |
log-format | json | json or text. |
max-concurrent | 1 | How many backups may run at once. |
helper-image | current image | Image used for short-lived archive/restore containers. |
stop-timeout | 30s | Grace period before a container stopped for a backup is killed. |
defaults
Applied to every source that does not override them with labels.
defaults:
schedule: daily
targets: [nas]
filename: "{source}_{timestamp}"
compression: zstd
encrypt: false
verify: false
catch-up: false
keep-last: 7
keep-daily: 0
keep-weekly: 0
keep-monthly: 0
max-age: 0When targets is empty and exactly one target is configured, that target is used.
schedules
Named cron expressions referenced by dockup.schedule. Five field syntax plus @daily, @hourly, @weekly, @monthly, @yearly, @every <duration>.
schedules:
hourly: "17 * * * *"
daily: "23 3 * * *"
weekly: "41 4 * * 0"
monthly: "13 5 1 * *"The four names above are built in and can be overridden. A dockup.schedule value that is not a configured name is parsed as an inline cron expression.
targets
Each target is a destination. local and s3 are supported.
targets:
nas:
type: local
path: /backups
prefix: dockup
s3:
type: s3
endpoint: https://s3.example.com # omit for AWS
region: eu-central-1
bucket: dockup
prefix: dockup
access-key: ${S3_ACCESS_KEY}
secret-key: ${S3_SECRET_KEY}
session-token: ""
force-path-style: true # needed by MinIO and most S3 clones| Key | Applies to | Description |
|---|---|---|
type | both | local or s3. |
prefix | both | Key prefix. Defaults to dockup. |
path | local | Directory that receives the archives. |
endpoint | s3 | Custom S3 endpoint URL. |
region | s3 | Signing region. |
bucket | s3 | Bucket name. |
access-key, secret-key, session-token | s3 | Credentials. Prefer the -file variants or environment variables. |
force-path-style | s3 | Use endpoint/bucket/key instead of bucket.endpoint/key. |
Secrets
Every secret accepts three forms, in order of precedence:
secret-key: literal # wins when set
secret-key-file: /run/secrets/s3 # read at startup, trailing whitespace trimmed
secret-key: ${S3_SECRET_KEY} # environment interpolation${VAR} fails fast when the variable is unset. ${VAR:-fallback} supplies a default.
Secrets never appear in logs, dockup config show or dockup status: they are replaced with **redacted**.
encryption
encryption:
age:
recipients:
- age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
identity: /run/secrets/age-identity # for restores
# or, for passphrase encryption:
passphrase-file: /run/secrets/age-passphraserecipientsencrypt. A source only encrypts whendockup.encrypt=true(ordefaults.encrypt).identitydecrypts X25519 archives,passphrasedecrypts passphrase archives.identityandpassphraseare mutually exclusive.- Archives are compressed first, then encrypted, and get a
.agesuffix.
hooks
Named command sets, referenced by a container's dockup.hook label. Commands run inside that container with sh -c.
hooks:
postgres:
pre:
- pg_dump -Fc -f /var/lib/postgresql/dump.pgcustom app
post:
- rm -f /var/lib/postgresql/dump.pgcustomA failing pre command aborts the backup for that source; post commands always run, including after a failure.
notify
notify:
on-success: false
webhook:
url: https://example.com/dockup
headers:
Authorization: Bearer ${WEBHOOK_TOKEN}
healthcheck:
success: https://hc-ping.com/<uuid>
fail: https://hc-ping.com/<uuid>/fail
telegram:
token-file: /run/secrets/telegram-token
chat-id: "123456789"| Key | Description |
|---|---|
on-success | Also notify when a run succeeds (failures are always notified). |
| — | Every channel is independent: a failing notification is logged and never fails the backup. |
webhook.url | Receives a JSON run summary via POST. |
webhook.headers | Extra request headers; values are redacted from output. |
healthcheck.success / .fail | GET pings in the healthchecks.io style. |
telegram.token / .chat-id | Bot API message delivery. |
Environment overrides
| Variable | Configuration key |
|---|---|
DOCKUP_CONFIG | configuration file path |
DOCKUP_HOST | host |
DOCKUP_LISTEN | listen |
DOCKUP_STATE_DIR | state-dir |
DOCKUP_TMP_DIR | tmp-dir |
DOCKUP_TIMEZONE | timezone |
DOCKUP_LOG_LEVEL | log-level |
DOCKUP_LOG_FORMAT | log-format |
DOCKUP_MAX_CONCURRENT | max-concurrent |
DOCKUP_HELPER_IMAGE | helper-image |
DOCKUP_STOP_TIMEOUT | stop-timeout |
DOCKUP_DEFAULT_SCHEDULE | defaults.schedule |
DOCKUP_DEFAULT_TARGETS | defaults.targets (comma separated) |
DOCKUP_DEFAULT_FILENAME | defaults.filename |
DOCKUP_DEFAULT_COMPRESSION | defaults.compression |
DOCKUP_DEFAULT_ENCRYPT | defaults.encrypt |
DOCKUP_DEFAULT_VERIFY | defaults.verify |
DOCKUP_DEFAULT_CATCH_UP | defaults.catch-up |
DOCKUP_DEFAULT_KEEP_LAST | defaults.keep-last |
DOCKUP_DEFAULT_KEEP_DAILY | defaults.keep-daily |
DOCKUP_DEFAULT_KEEP_WEEKLY | defaults.keep-weekly |
DOCKUP_DEFAULT_KEEP_MONTHLY | defaults.keep-monthly |
DOCKUP_DEFAULT_MAX_AGE | defaults.max-age |
DOCKUP_AGE_RECIPIENTS | encryption.age.recipients (comma separated) |
DOCKUP_AGE_IDENTITY | encryption.age.identity |
DOCKUP_AGE_PASSPHRASE | encryption.age.passphrase |
DOCKUP_NOTIFY_ON_SUCCESS | notify.on-success |
DOCKUP_NOTIFY_WEBHOOK_URL | notify.webhook.url |
DOCKUP_NOTIFY_HEALTHCHECK_OK | notify.healthcheck.success |
DOCKUP_NOTIFY_HEALTHCHECK_FAIL | notify.healthcheck.fail |
DOCKUP_NOTIFY_TELEGRAM_TOKEN | notify.telegram.token |
DOCKUP_NOTIFY_TELEGRAM_CHAT_ID | notify.telegram.chat-id |
Targets and hooks are map-valued, so they are configured in YAML and use ${VAR} interpolation plus -file secrets rather than a long list of environment variables.
Example
host: nas-01
state-dir: /var/lib/dockup
defaults:
schedule: daily
targets: [nas]
keep-daily: 7
keep-weekly: 4
keep-monthly: 12
max-age: 400d
encrypt: true
targets:
nas:
type: local
path: /backups
offsite:
type: s3
endpoint: https://s3.example.com
region: us-east-1
bucket: dockup-nas-01
force-path-style: true
access-key: ${S3_ACCESS_KEY}
secret-key-file: /run/secrets/s3-secret
encryption:
age:
recipients: [${AGE_RECIPIENT}]
identity: /run/secrets/age-identity
hooks:
postgres:
pre: ["pg_dump -Fc -f /var/lib/postgresql/dump.pgcustom app"]
post: ["rm -f /var/lib/postgresql/dump.pgcustom"]
notify:
healthcheck:
success: ${HC_PING_URL}
fail: ${HC_PING_URL}/fail
telegram:
token-file: /run/secrets/telegram-token
chat-id: ${TELEGRAM_CHAT_ID}