Post

Implementing the 3-2-1 backup strategy using Borg

Implementing the 3-2-1 backup strategy using Borg

I have been running a home server for a couple of years now, since seizing the opportunity to put something together with spare parts after building a new workstation.

One of the first services I installed was Immich, the self-hosted photo and video management solution, with the dream of finally moving away from Google Photos.

I have been trialing the software ever since. It is fantastic, although warning: it is still under heavy development. The developers are aiming for a stable release within 2025, I believe.

My first stab at implementing backups for my Immich data, consisted of utilising the zfs-auto-snapshot tool for ZFS snapshot generation, and running a cron job that would run a basic bash script that would perform incremental zfs send to an external hard disk.

This was only ever meant to be temporary, and before making Immich my full-time photo solution, I wanted a more robust solution.

3-2-1 Backup Strategy

The 3-2-1 backup rule is a simple, effective strategy for keeping your data safe. It consists of:

  • Three copies of your data: the original and two more copies.
  • Two different media: This made more sense when the rule was created. Today it is enough to have two different devices.
  • One copy off-site: One copy of your data in a remote location e.g., cloud storage.

Borg, Borgmatic and BorgBase

The borg CLI is a powerful tool for deduplication-based backups. borgmatic is a config driven wrapper around borg abstracting away some complexity and simplifying the backup process. BorgBase is to borg, as GitHub is to git.

See installation instructions.

Install from PyPi for the latest release. Pre-compiled binaries on their GitHub release page are discontinued after v1.2.9. Distribution packages are very outdated also.

I started by creating a remote borg repository on BorgBase, at the time of writing I was able to provision 250GB for $24 (billed annually)—which was perfect for me (my current Immich data totals ~210GB). The plan is flexible up to 1TB - $0.01/GB/Month for storage outside the base quota.

BorgBase provides a setup wizard that gives step by step instructions to complete the repository initialization, SSH key setup, and even provides a pre-populated borgmatic config.yml file to get you up and running quickly.

A basic /etc/borgmatic/config.yml file looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# A list of directories to back up
source_directories:
    - /path/to/data/

# List of borg repositories to store backups
repositories:
    - path: ssh://<something>@<repo-name>.repo.borgbase.com/./repo
      label: "backup on BorgBase"
    - path: /path/to/backup/directory
      label: "backup on external hard disk"
      encryption: repokey-blake2

exclude_patterns:
    - '*.pyc'
    - ~/*/.cache


# Enable ZFS Snapshot Integration for this location.
# This tells borgmatic to automatically handle ZFS snapshots
# for the datasets listed in `source_directories` for this location.
# It will create a snapshot before the backup, use it, and then destroy it.
zfs: {}


# Stay in same file system (optional)
# one_file_system: true

compression: auto,zstd
encryption_passphrase: CHANGEME
archive_name_format: '{hostname}-{now:%Y-%m-%d-%H%M%S}'

# Number of times to retry a failing backup before giving up.
retries: 5
retry_wait: 5

keep_daily: 3
keep_weekly: 4
keep_monthly: 12

# Don't read whole repo each time
skip_actions:
    - check

check_last: 3

# Shell commands to execute before or after a backup
commands:
  - before: action
    when: [create]
    run:
      - echo "`date` - Starting backup"

  - after: action
    when: [create]
    run:
      - echo "`date` - Finished backup"

Run a backup based on the above configuration:

1
2
3
4
5
# Run a backup to each listed repository
borgmatic create

# Run a backup to a specific repository and show progress
borgmatic create --repository "immich-backup on BorgBase" --verbosity 1 --progress 

I have been using this setup for a week or so and I have found it to work very well. In 2025 my broadband connection has a paltry 8 Mb/s upload speed, so even though I only have ~210GB of data to backup, the initial backup took ~2.5 days - shameful!

Thankfully, borg is smart enough to only upload new data on subsequent backups.

The source directory configured for backup is linked to a borg repository. borg will create a new archive in the repository for each new backup. Data is stored de-duplicated across the repository, meaning if a long-running backup is interrupted for some reason, then on the next backup to a new archive in the repository, borg can figure out what data is missing rather than uploading everything again.

This post is licensed under CC BY 4.0 by the author.

Trending Tags