Skip to content

Offsite to S3 ​

The usual homelab shape: a fast local copy on a NAS, and an encrypted copy somewhere else. Dockup uploads the same archive to every target you name, so this costs one tar pass and two uploads.

yaml
# dockup.yml
host: nas-01
state-dir: /var/lib/dockup

defaults:
  schedule: daily
  keep-daily: 7
  keep-weekly: 4
  keep-monthly: 12
  encrypt: true

targets:
  nas:
    type: local
    path: /backups

  offsite:
    type: s3
    endpoint: https://s3.eu-central-003.backblazeb2.com
    region: eu-central-003
    bucket: dockup-nas-01
    prefix: dockup
    force-path-style: true
    access-key: ${S3_ACCESS_KEY}
    secret-key-file: /run/secrets/s3-secret

encryption:
  age:
    recipients: [age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p]
    identity: /run/secrets/age-identity

Then any volume that does not name targets uses defaults:

yaml
volumes:
  appdata:
    labels:
      dockup.enable: "true"          # schedule, retention and targets come from defaults

Pointing a single volume elsewhere ​

yaml
volumes:
  media:
    labels:
      dockup.enable: "true"
      dockup.target: nas             # local only: too large to upload nightly
      dockup.schedule: weekly
      dockup.keep-weekly: "8"
      dockup.encrypt: "false"        # not worth encrypting 400 GB of films

Verifying what actually landed ​

console
$ docker compose run --rm dockup list --source volume:appdata
SOURCE           TARGET   ARCHIVED           SIZE      COMPRESSION  ENCRYPTED  KEY
volume:appdata   nas      2026-11-02 03:23   48.2 MiB  zstd         yes        dockup/nas-01/volume/appdata/daily/appdata_20261102T032300Z.tar.zst.age
volume:appdata   offsite  2026-11-02 03:23   48.2 MiB  zstd         yes        dockup/nas-01/volume/appdata/daily/appdata_20261102T032300Z.tar.zst.age

Add dockup.verify: "true" to re-read each uploaded archive and compare its SHA-256 — worth the bandwidth on an offsite target you do not control.

Cost control ​

Retention applies per target, so an offsite bucket can be shorter-lived than the local copy without touching the local archives. Set it per volume:

yaml
labels:
  dockup.keep-last: "7"      # local

…and, if you need different policies per target, split the source in two (for example a weekly local-only source and a daily offsite source of the same volume) rather than bending retention.

Credentials

Never put keys in labels — anything that can read the Docker socket can read them. Use ${VAR} interpolation or a *-file secret; Dockup redacts both from config show, status and every log line.

Which S3 endpoints work ​

Any S3-compatible service: AWS, Backblaze B2, Cloudflare R2, Wasabi, MinIO, Hetzner, Scaleway, Garage. Set endpoint and force-path-style: true for everything that is not AWS. Without credentials in the config, Dockup falls back to the standard AWS chain (environment, shared config, instance role), which is what you want on EC2.

Released under the Mozilla Public License 2.0.