Backing up

Win 11 made me make the move to finally start using Linux on my daily driver computer after almost 3 decades of using Windows. Six months ago, I’ve ditched Windows for Bluefin (Fedora Silverblue). Linux desktop experience is much different from when I remember it 10-15 years ago. Bluefin is an immutable distro, which essentially ends the fight with the package manager by making critical system files read-only. Obviously this has some tradeoffs as you’re essentially working with homebrew and Flatpak whenever you need to install command line or GUI application that’s not included in the base image.

This is a conscious and opinionated decision by the developers of Bluefin. Silverblue works on OCI images booted as a readonly file system, ensuring reproducibility and stability. Even though it is possible to “layer” your changes, you’re suggested to not do it. Development environments are again based on container technologies and you never install them on your actual system. It’s a fascinating way to work, but that’s for another day.

One of the biggest challenges of moving to a new OS was finding a solution for backing up my files. I was a faithful user of CrashPlan for many years to do incremental, off-site backups. After quite some research I’ve decided to use restic without a GUI. I’ve attempted to set it up via systemd but it was too fiddly. After working on it for a few days, I now had to understand how permissions worked with a unit and I finally decided that was already too much work.

It was a matter of making sure a piece of software is running and considering my distro, next obvious solution was indeed using Docker. Conveniently, resticprofile has a docker image. It is a pretty capable restic manager and it’d be incredibly reproducible once I set it up! This is roughly the config file I use:

version: '1'

global:
  scheduler: crond

main:
  password-file: /run/secrets/restic_password
  repository: 'rclone:drive:restic'
  initialize: false
  force-inactive-lock: true
  backup:
    source: .
    source-base: <path-to-be-backed-up-files>
    source-relative: true
    exclude-caches: true
    one-file-system: true
    tag: 'main'
    schedule: 'hourly'
    schedule-permission: system
    skip-if-unchanged: true
    check-before: true
    dry-run: false
    verbose: true

As the backup server, I’m using Google Drive on a Workspace account via rclone, which is a supported backend for restic and is very cheap in my location. From memory, it let’s you setup an oauth app and manages tokens internally. Obviously, the backup (as well as the rclone config) is encrypted and another problem was keeping those passwords safe. This is important to minimize risk of ransomware attacks (which might access the backup as well if you’re not careful). I use secret-tool to keep them:

secret-tool store --label="Restic Backup" service rclone:drive:restic

Unfortunately docker only supports secrets in swarm mode, so I also need to make it a swarm manager as a one time setup, and deploy to it:

docker swarm init
# Feed passwords to docker
secret-tool lookup service rclone:drive:restic | docker secret create restic_password -
secret-tool lookup service rclone | docker secret create rclone_password -

docker stack deploy --compose-file=./docker-compose.yml restic

And finally this is the compose file:

services:
  restic:
    image: creativeprojects/resticprofile:0.30.1
    volumes:
      # Config locations
      - ./:/resticprofile
      - $HOME/.config/rclone:/root/.config/rclone

      # Backup sources, mapped to same path for consistency in the backup
      - <path-to-be-backed-up-files>:<path-to-be-backed-up-files>:ro

      # Cache locations
      - /tmp
      - /root/.cache/restic
    restart: unless-stopped
    hostname: $HOSTNAME
    secrets:
      - restic_password
      - rclone_password

    entrypoint: "/bin/sh"
    command:
      - "-c"
      - "resticprofile schedule --all && crond -f"

    environment:
      - RCLONE_PASSWORD_COMMAND=cat /run/secrets/rclone_password
      - TZ=Europe/Istanbul
      - GOMAXPROCS=2

secrets:
  restic_password:
    external: true
  rclone_password:
    external: true

All the secrets are mapped to files in /run/secrets, which I configure things to use them. I also mount cache locations to make sure they persist and use my local rclone config file, which is also encrypted. Resticprofile have these send-after-fail and send-after configurations (redacted above) which I use for setting up heartbeats & alerts when things go wrong or things are not backed up on time to let me know via a Telegram bot.

Even though it is capable of supporting all my use cases, it has its flaws. One nuiscance is b/c the container is running as root, rclone keeps changing permissions of my local configuration file. OTOH, I want to share them b/c I sometimes use it on the host machine as well. Other things I want to experiment with are; append only backups, so that it is not possible to delete them and BTRFS snapshots, which would probably not be feasible via docker.

Reach me out for any comments or questions on Twitter.

© Ali Naci Erdem 2025