Set up the client

The website handles your account, billing, and finding a buddy. The actual backup happens through a small program you run on your own computer, in Docker. Here's how to get it running.

Before you start

You'll need:

Save your backup passphrase in a password manager. BACKUP_PASSPHRASE is the only key to your backups — files are encrypted with it on your own machine, and nobody else ever has it. If you lose it, what your buddy holds for you can never be decrypted: not by a password reset (that's only your website login), not by support, not by us. It's not stored anywhere but your .env file, which won't help if the machine itself dies.

Steps

  1. Get a device token On your dashboard, under Devices, give this machine a label (e.g. "home desktop") and click Add device. You'll see a token — copy it now, it's only shown once.
  2. Make a folder and save two files into it Create a folder for the client (e.g. backup-buddies-client) and save these two files inside it.

    docker-compose.yml pulls the published client image (no build step, no source code on your machine). Change the left side of the three highlighted lines to your own folders, and leave everything after the colon alone:

    services:
      client:
        image: ghcr.io/mspencerl87/backup-buddies/client:latest
        restart: unless-stopped
        network_mode: host
        env_file: .env
        environment:
          - BACKUP_DIR=/backup
          - BUDDY_FILES_DIR=/buddy-files
          - RESTORE_DIR=/restored
        volumes:
          # The client's own config (identity key, bookkeeping). Small; keep it here.
          - ./config:/data
          # Your files to back up. Read-only (:ro): the client never writes here.
          - /mnt/storage/my-files:/backup:ro
          # What your buddies store with you. Needs the space you pledged.
          - /mnt/storage/buddy-files:/buddy-files
          # Where files you restore from a buddy land.
          - /mnt/storage/restored:/restored

    network_mode: host runs the container directly on this machine's network instead of Docker's usual isolated one — it's what lets this device find a buddy on the same local network and connect directly, skipping the relay entirely. Linux only; if you're on Docker Desktop (Mac/Windows), see the troubleshooting section below.

    Where your files go. The client keeps four folders apart, so nothing of its own ever lands in your data:

    • /backup — your files. Mounted read-only; the client only reads them. If this machine should only receive (hold a buddy's files, back nothing up), use ./empty-backup-dir:/backup:ro instead.
    • /buddy-files — buddy files: what your buddies store with you, encrypted (you can't read them). This is what uses the space you pledged. The client makes one subfolder per buddy inside it, so give it a folder of its own on a drive with room.
    • /restored — files you restore from a buddy. Separate from your files, so a restore never overwrites anything.
    • /data — the client's own config: identity key and small bookkeeping files. Leave it as ./config, next to docker-compose.yml.

    Two common setups (just the three lines you change):

    # A. One data drive, separate folders on it
          - /mnt/storage/my-files:/backup:ro
          - /mnt/storage/buddy-files:/buddy-files
          - /mnt/storage/restored:/restored
    
    # B. Two separate mounts (two disks or NAS shares)
          - /mnt/my-data:/backup:ro
          - /mnt/buddy-data:/buddy-files
          - ./restored:/restored

    Don't put the buddy-files or restore folder inside your own files' folder — you'd end up backing your buddy's files (or your restores) back up to your buddy. Network shares (NFS/SMB) work: mount them on the host first, then use the mount path here.

    .env — your token and passphrase. Only DEVICE_TOKEN and BACKUP_PASSPHRASE need filling in; the rest have sensible defaults:

    API_URL=https://api.filegarden.net
    RELAY_URL=https://relay.filegarden.net
    
    DEVICE_TOKEN=paste_the_token_from_step_1_here
    BACKUP_PASSPHRASE=a few random words only you know
    
    # Run as your own user, so restored files belong to you instead of root.
    # Find your numbers with:  id -u  and  id -g
    PUID=1000
    PGID=1000
    
    # The port the local status dashboard (see below) binds directly on this
    # host. Defaults to 8080 — only set this if 8080 is already taken, or
    # you're running more than one device's client on the same machine (give
    # each its own folder and a DIFFERENT DASHBOARD_PORT here — required,
    # not optional, when sharing a host, since this binds the port directly
    # rather than Docker mapping it for you).
    #DASHBOARD_PORT=8080
    
    # The UDP port used for the actual connection to your buddy (not the
    # dashboard above). Backup Buddies works fine without ever touching this
    # — it just relays through relay.filegarden.net instead of connecting
    # directly — but if you can forward a UDP port on your router, forward
    # this one to this machine for a shot at a faster direct connection.
    # Defaults to 11235; change it if already taken, easier to forward
    # differently, or (same as DASHBOARD_PORT) you're running more than one
    # device's client on this same host.
    #SYNC_PORT=11235

    Example, filled in: DEVICE_TOKEN=bbd_7f3a9c1e2d4b5a6f8e0c1d2b3a4f5e6d and BACKUP_PASSPHRASE=correct horse battery staple woodland — yours will look different; the token comes from step 1, and the passphrase is anything memorable only you know.

  3. Start it
    docker compose pull
    docker compose up -d
    docker compose logs -f
    pull fetches the already-built image — a few seconds, not a build. You should see a line confirming the device registered. Your Devices card on the dashboard will now show this device as connected.
  4. Confirm it found your buddy Once your buddy's client is running too, you'll see a cycle line in the logs roughly every 30 seconds: "backup cycle complete" if there was something to send, or "nothing new to back up" if not — both mean the cycle actually ran and reached your buddy. This happens even on a receive-only device (./empty-backup-dir as its backup folder), since it's still running a cycle against an empty folder (so you'll just see "nothing new to back up" every time, which is expected and confirms your two machines can reach each other — directly, or through the relay if a direct connection isn't possible).
Prefer to build it yourself from source instead?

One command downloads the full source and a docker-compose.yml that builds it locally instead of pulling the published image — useful if you'd rather compile it yourself than trust a prebuilt image, or want to inspect the code first:

curl -fsSL https://app.filegarden.net/client/install.sh | bash
cd backup-buddies-client

Fill in the same two .env values as above (this version sets its folders in .env instead — the *_DIR_HOST lines in its .env.example), then docker compose up -d — the first run builds the image locally (a few minutes); after that, starting is instant.

What this version actually does

This is a real, working backup client, not just a connectivity demo — your buddy's machine genuinely ends up holding a usable, encrypted copy of your files.

Does

  • Scans your folder roughly every 30 seconds and sends only what's new or changed — unchanged files aren't re-sent each cycle
  • Mirrors deletions too, so your buddy's copy matches yours rather than only ever growing
  • Encrypts everything with your BACKUP_PASSPHRASE before it ever leaves this machine — your buddy's device only ever stores ciphertext
  • Connects directly to your buddy's device when possible — including finding them automatically on the same local network and connecting over it, never touching the relay — falling back to the relay automatically when a direct connection isn't possible
  • Keeps a backstop when a file is overwritten or deleted — the live copy plus its last 2 replaced versions are kept on your buddy's disk, so a bad overwrite or an accidental local delete isn't necessarily final
  • A local status dashboard (http://<this device>:8080) showing per-buddy pledge usage, sent/received totals, last cycle result, a file browser with per-file version history, and one-click restore — restored files are never written back over your live folder; they land in your restore folder under <buddy>/, and the dashboard shows the exact path once a restore finishes
  • Enforces your buddy's pledge — won't accept more from them than they've pledged to store

Known limits, for now

  • Checks for changes on a schedule (every 30 seconds by default; set SCAN_INTERVAL_SECS in .env to change it) rather than instantly
  • Backs up the whole folder you point it at — no per-file or pattern-based exclude list yet
  • The local status dashboard has no login of its own — see its section below before exposing that port beyond your own network

Useful docker compose commands

Run these from inside the backup-buddies-client folder (where its docker-compose.yml lives):

Troubleshooting