The volume is the policy
Opt a volume in with dockup.enable=true and set its schedule, targets and retention right where the data is declared. The policy is versioned with the app that owns it.
One container per host. Every volume declares its own backup policy with labels — destinations, keys and schedules stay in one place.
# compose.yaml
services:
app:
image: ghcr.io/example/app
volumes:
- appdata:/var/lib/app
dockup:
image: gitea.vladfaust.com/vladfaust/dockup:latest
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- dockup-state:/var/lib/dockup
- ./dockup.yml:/etc/dockup/dockup.yml:ro
- ./backups:/backups
volumes:
appdata:
labels:
dockup.enable: "true"
dockup.schedule: daily
dockup.target: nas
dockup.keep-daily: "7"
dockup-state:# dockup.yml
targets:
nas:
type: local
path: /backupsThat is the whole setup. The volume is discovered, archived on schedule, uploaded and pruned. Volumes created after Dockup started are picked up automatically.
$ docker compose run --rm dockup plan
KIND SOURCE SCHEDULE NEXT RUN TARGETS RETENTION ENCRYPT STOP
volume appdata daily (23 3 * * *) 2026-11-03T03:23Z nas last=7 no -
$ docker compose run --rm dockup backup --dry-run
$ docker compose run --rm dockup status --history 5plan reads the Docker daemon and prints the resolved policy without touching anything. backup --dry-run shows the exact object keys a run would create. status merges the live plan with the recorded history and works even when Docker is unreachable.