Installation

Docker installation

Full Docker stack setup for fsbackup including volumes, web UI, SSH keys, and first-run steps.

Docker is the recommended deployment method. The fsbackup image is published to ghcr.io/fsbackup/fsbackup.

Prerequisites

  • Ubuntu/Debian Linux
  • Docker Engine + Docker Compose v2
  • Dedicated backup drive(s) mounted (e.g. /backup, /backup2)

One-time host setup

Create the fsbackup user

sudo useradd -r -m --uid 993 -d /var/lib/fsbackup -s /bin/bash fsbackup

The UID must be 993 — it matches the user baked into the Docker image. The container runs as user: "993:993" and requires matching ownership on bind-mounted directories.

Generate the SSH keypair

sudo -u fsbackup ssh-keygen -t ed25519 \
  -f /var/lib/fsbackup/.ssh/id_ed25519_backup -N ""

The public key (id_ed25519_backup.pub) is installed on each remote host you want to back up.

Create directories

sudo mkdir -p /etc/fsbackup/db
sudo mkdir -p /backup/snapshots/{daily,weekly,monthly,annual}
sudo mkdir -p /backup2/snapshots/{daily,weekly,monthly,annual}
sudo chown -R fsbackup:fsbackup /backup/snapshots /backup2/snapshots /var/lib/fsbackup

Set up Prometheus textfile collector (optional)

If you're running node_exporter:

sudo groupadd nodeexp_txt
sudo usermod -aG nodeexp_txt fsbackup
sudo mkdir -p /var/lib/node_exporter/textfile_collector
sudo chown root:nodeexp_txt /var/lib/node_exporter/textfile_collector
sudo chmod 2775 /var/lib/node_exporter/textfile_collector

Docker Compose setup

Create /docker/stacks/fsbackup/docker-compose.yml:

services:
  fsbackup:
    image: ghcr.io/fsbackup/fsbackup:latest
    container_name: fsbackup
    restart: unless-stopped

    # Must match the fsbackup UID/GID on the host
    user: "993:993"

    ports:
      - "8080:8080"

    env_file:
      - stack.env

    volumes:
      # Config (fsbackup.conf, targets.yml, crontab, age.pub)
      - /etc/fsbackup:/etc/fsbackup

      # State (SSH keys, AWS creds, logs)
      - /var/lib/fsbackup:/var/lib/fsbackup

      # Snapshot storage
      - /backup/snapshots:/backup/snapshots
      - /backup2/snapshots:/backup2/snapshots

      # Prometheus metrics
      - /var/lib/node_exporter/textfile_collector:/var/lib/node_exporter/textfile_collector

    extra_hosts:
      # Pin hostnames to IPs — avoids DNS failures during backup runs
      - "myhost:192.168.1.10"

If you back up databases running inside Docker containers, fs-db-export.sh uses docker exec to run the dump and requires the Docker socket and docker group:

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    group_add:
      - docker

If your database runs natively on the host, no socket mount is needed — the export script calls pg_dump/mysqldump directly.

Create /docker/stacks/fsbackup/stack.env:

# Web UI authentication
AUTH_ENABLED=true
AUTH_PASSWORD_HASH=<bcrypt-hash>    # generate with: htpasswd -nbB "" password | cut -d: -f2

bcrypt $ characters in AUTH_PASSWORD_HASH must be escaped as $$ in Docker Compose env files to prevent variable interpolation.

Start the stack

cd /docker/stacks/fsbackup
docker compose up -d
docker logs -f fsbackup

Trust remote SSH host keys

For each host fsbackup will pull from:

docker exec -it fsbackup /opt/fsbackup/utils/fs-trust-host.sh <hostname>

Verify and run first snapshot

docker exec -it fsbackup /opt/fsbackup/bin/fs-doctor.sh --class class1
docker exec -it fsbackup /opt/fsbackup/bin/fs-runner.sh daily --class class1 --dry-run
docker exec -it fsbackup /opt/fsbackup/bin/fs-runner.sh daily --class class1

Upgrading

cd /docker/stacks/fsbackup
docker compose pull
docker compose up -d

Images are tagged by version (e.g. 0.9.1) and latest. Pin to a specific version for production stability.