$linuxjunkies
>

Back Up Linux with Borg or restic

Set up encrypted, deduplicated backups with BorgBackup or restic: local and remote repos, retention pruning, restoring files, and systemd timer scheduling.

IntermediateUbuntuDebianFedoraArch10 min readUpdated June 7, 2026

Before you start

  • SSH key-based authentication configured if using a remote backup server
  • Sufficient disk space on the backup destination (estimate 1.5× source size for initial run)
  • Root or sudo access on the machine being backed up
  • Remote host has BorgBackup installed if using Borg over SSH

Backups fail silently or not at all until you need them. Borg and restic are two modern, deduplicating backup tools that encrypt data at rest, handle remote repositories efficiently, and integrate cleanly with systemd timers for scheduling. This guide covers both tools side-by-side: initializing repos locally and over SSH, running pruned backups, restoring files, and automating everything with systemd.

Choosing Between Borg and restic

Both tools deduplicate and encrypt. The key differences:

  • BorgBackup: requires Borg on both client and server; faster for large sequential workloads; single-binary on most distros.
  • restic: backend-agnostic (local, SFTP, S3, Backblaze B2, rclone targets); no server-side binary needed for SFTP mode; slightly simpler syntax for multi-destination use.

If your remote target is a plain SSH server you control, either works. If you need S3 or a cloud backend, use restic. Both are solid choices for day-to-day use.

Installation

BorgBackup

# Debian / Ubuntu
sudo apt install borgbackup

# Fedora / RHEL 9+ (with EPEL on RHEL)
sudo dnf install borgbackup

# Arch
sudo pacman -S borg

restic

# Debian / Ubuntu
sudo apt install restic

# Fedora / RHEL
sudo dnf install restic

# Arch
sudo pacman -S restic

After installing, run restic self-update or check your distro's version against upstream releases; packaged versions sometimes lag by several minor versions.

Initializing a Repository

Borg — Local Repo

borg init --encryption=repokey-blake2 /mnt/backup/borg-repo

You will be prompted for a passphrase. Store it somewhere safe—losing it means losing access to every archive. Export a copy of the key immediately:

borg key export /mnt/backup/borg-repo ~/borg-key.txt

Borg — Remote Repo over SSH

borg init --encryption=repokey-blake2 \
  user@backuphost:/srv/borg/myhostname

Borg must be installed on the remote server. Use SSH key authentication; password prompts break unattended backups.

restic — Local Repo

restic init --repo /mnt/backup/restic-repo

restic — Remote Repo over SFTP

restic init --repo sftp:user@backuphost:/srv/restic/myhostname

restic — S3-Compatible Bucket

export AWS_ACCESS_KEY_ID=your-key
export AWS_SECRET_ACCESS_KEY=your-secret
restic init --repo s3:https://s3.amazonaws.com/your-bucket-name

Running a Backup

Borg

Archive names conventionally embed a timestamp. The :: separator divides repo path from archive name.

borg create \
  --verbose \
  --filter AME \
  --list \
  --stats \
  --show-rc \
  --compression lz4 \
  --exclude-caches \
  --exclude '/home/*/.cache' \
  --exclude '/home/*/.local/share/Trash' \
  /mnt/backup/borg-repo::'{hostname}-{now:%Y-%m-%dT%H:%M}' \
  /home \
  /etc \
  /var/lib

restic

restic backup \
  --repo /mnt/backup/restic-repo \
  --verbose \
  --exclude-caches \
  --exclude '/home/*/.cache' \
  --exclude '/home/*/.local/share/Trash' \
  /home /etc /var/lib

Pass --password-file /root/.backup-passphrase (file mode 600) to avoid interactive prompts in automated runs.

Retention and Pruning

Without pruning, repos grow unboundedly. Both tools support keeping a defined number of snapshots per time window.

Borg — Prune

borg prune \
  --list \
  --glob-archives '{hostname}-*' \
  --show-rc \
  --keep-daily 7 \
  --keep-weekly 4 \
  --keep-monthly 6 \
  /mnt/backup/borg-repo

After pruning, run borg compact /mnt/backup/borg-repo (Borg 1.2+) to actually free disk space. Prune only marks archives as deletable.

restic — Forget and Prune

restic forget \
  --repo /mnt/backup/restic-repo \
  --keep-daily 7 \
  --keep-weekly 4 \
  --keep-monthly 6 \
  --prune

The --prune flag combines forgetting and reclaiming space in one step. Omit it to do a dry-run that shows what would be removed.

Restoring Files

Borg — List and Extract

# List all archives
borg list /mnt/backup/borg-repo

# List contents of a specific archive
borg list /mnt/backup/borg-repo::myhostname-2024-06-01T02:00

# Extract a single directory to current working directory
borg extract \
  /mnt/backup/borg-repo::myhostname-2024-06-01T02:00 \
  home/alice/Documents

borg extract strips leading slashes; run it from the restore target or use --strip-components as needed.

restic — List and Restore

# List snapshots
restic snapshots --repo /mnt/backup/restic-repo

# Restore a full snapshot to a target directory
restic restore latest \
  --repo /mnt/backup/restic-repo \
  --target /mnt/restore

# Restore a specific path from a snapshot ID
restic restore 3a7f2c1b \
  --repo /mnt/backup/restic-repo \
  --include /home/alice/Documents \
  --target /mnt/restore

Scheduling with systemd Timers

systemd timers replace cron for managed services. Create a service unit and a timer unit for each backup job. The example below uses restic; adapt paths and the ExecStart line for Borg.

Service Unit

sudo tee /etc/systemd/system/restic-backup.service <<'EOF'
[Unit]
Description=restic backup
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
EnvironmentFile=/etc/restic/env
ExecStart=/usr/bin/restic backup \
  --repo ${RESTIC_REPOSITORY} \
  --password-file /etc/restic/passphrase \
  --exclude-caches \
  --exclude '/home/*/.cache' \
  /home /etc /var/lib
ExecStartPost=/usr/bin/restic forget \
  --repo ${RESTIC_REPOSITORY} \
  --password-file /etc/restic/passphrase \
  --keep-daily 7 --keep-weekly 4 --keep-monthly 6 \
  --prune
EOF

Create /etc/restic/env (mode 600) with your repository URL and any cloud credentials:

RESTIC_REPOSITORY=sftp:user@backuphost:/srv/restic/myhostname

Timer Unit

sudo tee /etc/systemd/system/restic-backup.timer <<'EOF'
[Unit]
Description=Run restic backup daily at 02:30

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer

Persistent=true means if the machine was off at 02:30, the backup runs at next boot rather than being skipped.

Verification

Both tools provide integrity checks. Run these periodically—monthly at minimum—or after any hardware concern.

# Borg
borg check /mnt/backup/borg-repo

# restic
restic check --repo /mnt/backup/restic-repo

Check the timer status and last run outcome:

systemctl status restic-backup.timer
journalctl -u restic-backup.service -n 50

Troubleshooting

  • Borg: "Repository already exists" — You ran borg init twice. List archives with borg list to confirm the repo is intact and skip init.
  • Borg: stale lock file — If a backup was interrupted, run borg break-lock /path/to/repo. Only do this when no other Borg process is actively using the repo.
  • restic: "Fatal: unable to open config file" — The repo path is wrong or the repo was never initialized. Double-check RESTIC_REPOSITORY in your environment file.
  • SSH authentication failures in timer — The service runs as root by default. Ensure root's SSH key (or the key specified via ssh-agent / IdentityFile) is authorized on the remote host. Test with ssh -i /root/.ssh/id_ed25519 user@backuphost.
  • Timer never fires after boot — Confirm the timer is enabled (systemctl is-enabled restic-backup.timer) and check systemctl list-timers for next trigger time.
  • Disk space not freed after Borg prune — Run borg compact after borg prune. Borg 1.2 split these into separate operations.
tested on:Ubuntu 24.04Debian 12Fedora 40Arch rolling

Frequently asked questions

Can I back up to multiple destinations simultaneously?
restic makes this straightforward: initialize two separate repos and run two backup commands (or two service units). Borg supports multiple remotes via separate init/create calls as well, though there is no built-in multi-target flag in either tool.
What happens if I forget the repository passphrase?
There is no recovery path—the encryption is strong by design. Store the passphrase in a password manager and keep an offline copy. For Borg, also export and store the key file separately from the repo.
How much extra storage does deduplication save in practice?
For typical home directories with incremental daily changes, deduplication usually reduces cumulative storage by 60–90% compared to full copies. Repos with large, frequently changing binary files (databases, VMs) see less benefit.
Should I exclude /proc, /sys, /dev, and /run?
Both tools skip virtual filesystems by default when you specify real paths like /home and /etc. If you back up /, explicitly exclude /proc, /sys, /dev, /run, /tmp, and any mounted bind or overlay filesystems to avoid errors and useless data.
Is the systemd timer approach better than cron?
For backup jobs, yes. systemd timers log output to the journal automatically, support missed-run catchup via Persistent=true, and integrate with dependency ordering (e.g., After=network-online.target). cron has no equivalent built-in logging or catch-up behavior.

Related guides