Nextcloud
Nextcloud spreads its state across a volume (user files) and a database. Files are written by PHP workers, so a hot tar can capture a file that is still being written — but Nextcloud tolerates that as long as you restore files and database together.
Compose file
services:
nextcloud:
image: nextcloud:30
volumes:
- nextcloud-data:/var/www/html
labels:
dockup.stop: "true"
depends_on: [db]
db:
image: mariadb:11
environment:
MARIADB_ROOT_PASSWORD_FILE: /run/secrets/db-root
MARIADB_DATABASE: nextcloud
volumes:
- nextcloud-db:/var/lib/mysql
labels:
dockup.stop: "true"
dockup.hook: mariadb
volumes:
nextcloud-data:
labels:
dockup.enable: "true"
dockup.schedule: daily
dockup.target: nas,offsite
dockup.keep-daily: "7"
dockup.keep-weekly: "4"
dockup.keep-monthly: "6"
dockup.max-age: "400d"
# Thumbnails and logs are regenerable.
dockup.exclude: "var/log,var/tmp,*/appdata_*/preview,updater-*"
dockup.encrypt: "true"
nextcloud-db:
labels:
dockup.enable: "true"
dockup.schedule: daily
dockup.target: nas,offsite
dockup.keep-daily: "7"
dockup.encrypt: "true"# dockup.yml
hooks:
mariadb:
pre:
- mariadb-dump --single-transaction --quick --databases nextcloud -r /var/lib/mysql/dockup.sql
post:
- rm -f /var/lib/mysql/dockup.sqlWhy both containers are stopped
dockup.stop: "true" on the app keeps PHP from writing to nextcloud-data mid-archive; the same label on db keeps MariaDB from writing to its volume. Dockup only stops containers that mount or declare the source being archived, so backing up nextcloud-data stops nextcloud, and backing up nextcloud-db stops db.
Order matters for restores, not for backups
Restore the database first, then the data volume, and start Nextcloud last. The files carry a maintenance flag in config/config.php; if Nextcloud complains after a restore, put it into maintenance mode once and let it finish:
$ docker compose run --rm nextcloud occ maintenance:mode --on
$ docker compose run --rm nextcloud occ maintenance:repair
$ docker compose run --rm nextcloud occ maintenance:mode --offExcluding what can be rebuilt
dockup.exclude takes a comma-separated list of relative paths or globs. For Nextcloud the interesting ones are previews, logs and the updater's staging directory — often the bulk of the volume and all of it regenerable.
Check what a pattern really matches before relying on it:
$ docker compose run --rm dockup restore --source volume:nextcloud-data --dry-run | head -40The dry run lists the entries of the newest archive without writing anything.