Borgmatic Mount Container — Mounting a Remote Borg Backup via Docker

This is a Docker container that uses Borg Backup (via the b3vis/borgmatic image) to mount a remote Borg repository into your local system as a filesystem, using FUSE.

Specifically, this container:

  • Connects to a remote Borg repository hosted on a Hetzner Storage Box (YOUR_BOX_ID.your-storagebox.de) over SSH (port 23).
  • Uses borg mount to mount the entire contents of the backup archives (snapshots) in that repository into /mnt/restore inside the container, which is mapped to /mnt/hetzner on the host (thanks to rshared propagation).
  • Lets you browse / restore files from old backups like a regular directory, without extracting the whole backup.
  • Authenticates with an SSH private key + the passphrase of the Borg repo (end-to-end encryption).

In short: this is a tool that “opens” a remote backup repository like a disk so you can view/copy the files you need to restore, instead of running borg extract by hand.

⚠️ Note: this container is only for mounting/restoring — it does not run scheduled backups (there is no cron/schedule for borgmatic create here).

The docker-compose.yml file

The original file had one line that mixed a tab instead of spaces (restart: unless-stopped), which causes a YAML indentation error in docker compose. The version below has been fixed to use spaces consistently.

💡 Before running anything, replace the placeholders in the compose file with your own values:

  • YOUR_BOX_ID → your Hetzner customer number (the one in your Storage Box address)
  • YOUR_BORG_PASSPHRASE → the passphrase you set when creating the Borg repository
services:
  borgmatic:
    image: b3vis/borgmatic:2.1.3
    container_name: borgmatic
    restart: unless-stopped
    cap_add:
      - SYS_ADMIN
    devices:
      - /dev/fuse
    security_opt:
      - apparmor:unconfined
    environment:
      TZ: Asia/Ho_Chi_Minh
      BORG_RSH: "ssh -p 23 -i /root/.ssh/id_ed25519_hetzner -o StrictHostKeyChecking=accept-new"
      BORG_REPO: "ssh://YOUR_BOX_ID@YOUR_BOX_ID.your-storagebox.de:23/./backup/0"
      BORG_PASSPHRASE: "YOUR_BORG_PASSPHRASE"
    volumes:
      - /root/.ssh/id_ed25519_hetzner:/root/.ssh/id_ed25519_hetzner:ro
      - ./config/keys/YOUR_BOX_ID_your_storagebox_de__backup_0:/root/.config/borg/keys/YOUR_BOX_ID_your_storagebox_de__backup_0:ro
      - ./cache:/root/.cache/borg
      - /mnt/hetzner:/mnt/restore:rshared
    entrypoint: >
      sh -c "
        mkdir -p /mnt/restore &&
        borg mount \$$BORG_REPO /mnt/restore -f
      "      

Key points explained:

  • cap_add: SYS_ADMIN + devices: /dev/fuse + apparmor:unconfined → the required trio for the container to use FUSE (the foundation of borg mount).
  • BORG_RSH → specifies the SSH key and the Storage Box’s port 23; accept-new automatically accepts the host key on first contact.
  • rshared on the mount volume → so the FUSE mount inside the container propagates out to the host.
  • \$$BORG_REPO$$ is how you escape $ in compose, so BORG_REPO is resolved by the container rather than by compose.
  • -f → keeps the mount running in the foreground, keeping the container in a running state.

Installation guide

Step 1 — Create the directory structure

mkdir -p ~/docker/borgmatic/config/keys
mkdir -p ~/docker/borgmatic/cache
cd ~/docker/borgmatic

Explanation:

  • config/keys → where the encryption key file of the Borg repository lives (required if the repo uses keyfile encryption).
  • cache → where Borg stores its metadata cache (makes mounting/listing faster, avoids re-downloading the whole index every time).

Step 2 — Prepare the SSH key

You need an SSH private key for connecting to the Hetzner Storage Box:

ls -la /root/.ssh/id_ed25519_hetzner

If you don’t have one yet, generate a key and add the public key to the Hetzner Storage Box (via the Hetzner panel):

ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519_hetzner -N ""

Then copy the public key (id_ed25519_hetzner.pub) into the SSH keys section of the Hetzner Storage Box control panel.

Step 3 — Copy the Borg repo key file (if the repo uses keyfile encryption)

If the repository was created with --encryption keyfile (not repokey), you need to copy the corresponding key file to:

~/docker/borgmatic/config/keys/YOUR_BOX_ID_your_storagebox_de__backup_0

This file is usually located in ~/.config/borg/keys/ on the machine that originally initialized the repository. If you use repokey (key stored in the repo, no separate file), you can skip this step and remove the corresponding key volume mount line from the compose file.

Step 4 — Create the docker-compose.yml file

nano ~/docker/borgmatic/docker-compose.yml

Paste the indentation-fixed content from above and save it.

⚠️ Security: it’s recommended to move BORG_PASSPHRASE into a .env file instead of hardcoding it in the compose file, for example:

echo "BORG_PASSPHRASE=YOUR_BORG_PASSPHRASE" > ~/docker/borgmatic/.env

and in the compose file use:

    environment:
      BORG_PASSPHRASE: "${BORG_PASSPHRASE}"

Step 5 — Create the mount directory on the host

sudo mkdir -p /mnt/hetzner

Step 6 — Start the container

cd ~/docker/borgmatic
docker compose up -d

Step 7 — Verify

docker logs -f borgmatic

If the mount succeeded, you’ll see the backup archives appear as subdirectories at:

ls /mnt/hetzner

Each subdirectory corresponds to an archive (snapshot) — you can cd into them to browse and copy the files you need to restore.

Step 8 — Unmount when you’re done

docker compose down

(since the entrypoint runs borg mount -f in the foreground, stopping the container automatically unmounts).

Notes

  • This container is strictly for mount/restore purposes. If you also need scheduled automatic backups (running borgmatic create on a cron schedule), the next step is to write a config.yaml for borgmatic — replacing the mount entrypoint with the image’s service mode.
  • Keep the cache directory between runs so subsequent mounts are faster; only delete it if you suspect the cache is corrupted.

See also: