Btrfs Remote Backups for Docker Hosts on Debian 12

In my home lab, I run multiple Docker hosts on Debian 12 VMs inside Proxmox. While Proxmox Backup Server (PBS) already handles full VM backups, I wanted an additional layer for my Docker containers — specifically the docker-compose setups and persistent data under /srv/containers/apps. This post explains how I implemented remote Btrfs backups using btrbk, including handling multiple hosts and automating via systemd.

Why Btrfs Backups?

Full VM backups are great for disaster recovery, but they can be overkill if you just need your Docker containers and volumes. With Btrfs, you can snapshot subvolumes incrementally, making restores faster and more flexible. I focused on:

  • /srv/containers/apps — persistent Docker data and docker-compose configs
  • Optional: /srv/containers/dockerdata — Docker volumes (may be skipped to save space)
  • Remote backups across three hosts: docker-host-primary, docker-host-01, and docker-host-02
  • Target: external Btrfs disk for portability in case the main PVE host fails

Setting Up the External Backup Disk

I mounted my Btrfs disk under /srv/backup with the following fstab entry:

UUID=XXX-YYY-AAA-BBB-111 /srv/backup btrfs defaults,nofail,x-systemd.automount,compress=zstd,autodefrag 0 0

This ensures it automounts at boot, even if not present.

Btrbk Configuration

I opted to skip local snapshots, relying solely on the remote/incremental snapshots:

timestamp_format        long
transaction_log         /var/log/btrbk.log
incremental             yes
lockfile                /var/lock/btrbk.lock

target_preserve_min     no
target_preserve         14d 6w 14m
target                  /srv/backup

volume /srv/containers
    group vm docker-host-primary
    subvolume apps
        snapshot_name docker-host-primary_apps

volume ssh://docker-host-01.internal/srv/containers
    group vm docker-host-01
    subvolume apps
        snapshot_name docker-host-01_apps

volume ssh://docker-host-02.internal/srv/containers
    group vm docker-host-02
    subvolume apps
        snapshot_name docker-host-02_apps

Notes on Remote SSH Access

  • Created a dedicated btrbk user on each host
  • Configured SSH keys in /etc/btrbk/ssh/btrbk_ed25519
  • Automate user creation and configuration deployment via Ansible
  • Set proper sudo privileges for Btrfs commands:
btrbk ALL=(ALL) NOPASSWD: /usr/bin/btrfs subvolume *, /usr/bin/btrfs send *, /usr/bin/btrfs receive *, /usr/bin/btrfs subvolume snapshot *, /usr/bin/btrfs subvolume show *, /usr/bin/btrfs subvolume delete *, /usr/bin/readlink *
  • Ensured /srv/containers is readable by btrbk for remote operations

Testing the Backup

  • Dry-run command: sudo btrbk dryrun

Expected output shows local and remote snapshots being created without actually writing data:

/srv/containers/apps
+++ /srv/backup/docker-host-primary_apps.20250903T1312
>>> /srv/backup/docker-host-01_apps.20250903T1312
>>> /srv/backup/docker-host-02_apps.20250903T1312

Automating with Systemd

I created a simple btrbk.service:

[Unit]
Description=Run btrbk backup
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/sbin/btrbk run
StandardOutput=journal

And a daily timer at 03:00:

[Unit]
Description=Run btrbk daily

[Timer]
OnCalendar=03:00
Persistent=true

[Install]
WantedBy=timers.target

Activate with: sudo systemctl daemon-reload sudo systemctl enable --now btrbk.timer

The Persistent=true ensures missed runs are executed once the system is back online.

Retention & Snapshot Cleanup

I let btrbk handle snapshot retention automatically via target_preserve. Manual deletion is generally discouraged because snapshots are incremental and dependent.

Summary

  • Btrbk provides lightweight, incremental backups for Btrfs subvolumes
  • Remote backups via SSH allow multiple hosts to consolidate snapshots
  • Systemd timers automate daily runs and persist missed backups
  • External Btrfs disks provide portability for disaster recovery scenarios
  • This setup complements full VM backups via Proxmox, giving faster recovery for Docker containers without restoring entire VMs.