🛠️ Tutorials · ⏱ 9 min read

Automated Encrypted Backups with Restic and Backblaze B2 in 2026 (Complete Guide)

2026 tutorial on automating encrypted server backups to Backblaze B2 using restic. Covers encrypted repositories, systemd scheduling, retention policies, integrity checks, and tested restoration procedures.

S By Selfhostr Team · independent tests
Automated Encrypted Backups with Restic and Backblaze B2 in 2026 (Complete Guide)
ⓘ This article may contain affiliate links (no extra cost to you, it supports our tests). See the disclosure.
💰
~$6/TB/month
Cost
🆓
10 GB
Free Tier
🔒
Client-side
Encryption

👍 What we like

  • Client-side encryption ensures provider cannot read data
  • Low cost object storage with free tier for testing
  • Automatic deduplication saves storage space
  • Supports ransomware protection via versioning
  • Integrity verification ensures backup reliability

👎 What to watch

  • Passphrase loss makes data unrecoverable
  • Requires manual setup of environment variables
  • Bucket name must match region endpoint exactly
  • No built-in GUI for management
📑 Contents

There are two types of server administrators: those who back up, and those who will. A VPS hosting your Nextcloud, databases, or website is never immune to a failing disk, a rogue rm -rf command, ransomware, or a provider shutting down. The 3-2-1 rule (three copies, two media types, one off-site) remains the gold standard in 2026, and off-site copying is the one aspect most often neglected.

In this guide, we set up a serious, automatic, and encrypted backup strategy using restic, the Swiss Army knife of backups, to Backblaze B2, one of the cheapest object storage options on the market (approximately $6/TB/month). restic encrypts everything client-side before sending: even Backblaze cannot read your data. We cover repository initialization, deduplication, scheduling via systemd, automatic retention, integrity verification, and most importantly, restoration, because a backup that has never been restored is merely a hypothesis.

Prerequisites

  • A Linux server (Ubuntu 24.04 / Debian 12) to back up. Ideally already hardened; see install and secure an Ubuntu VPS.

  • A Backblaze account: create one at backblaze.com. The first 10 GB of B2 are free, which is more than enough to test.

  • sudo access on the server.

  • A password manager to securely store the repository passphrase and B2 keys. If you lose the passphrase, your backups are unrecoverable by design.

If you are unsure about choosing the tool or object storage, our comparisons restic vs Borg vs Kopia and Backblaze B2 vs Wasabi vs Storj will help you decide.

Step 1: Create a bucket and application key on Backblaze B2

Log in to your Backblaze account, then:

  1. Go to B2 Cloud Storage > Buckets > Create a Bucket.

  2. Give it a globally unique name (e.g., backup-srv-selfhostr-2026), set access to Private, and leave encryption as default.

  3. Note the bucket Endpoint displayed in its details (e.g., s3.eu-central-003.backblazeb2.com).

  4. Go to App Keys > Add a New Application Key.

  5. Restrict the key to your bucket only (principle of least privilege). Check both read and write permissions.

  6. Note the displayed keyID and applicationKey. The applicationKey is shown only once, so copy it immediately into your password manager.

Best practice: Enable versioning on the bucket (or object retention) on the Backblaze side. This provides additional protection against ransomware that encrypts/deletes your backups: even if the attacker accesses the key, previous versions remain recoverable.

Step 2: Install restic

restic is available in the repositories, but a recent version is better for the latest optimizations. On Ubuntu/Debian:


sudo apt update && sudo apt install -y restic

Check the version (aim for 0.16 or higher):


restic version

If the repository version is too old, update restic to the latest official release:


sudo restic self-update

Step 3: Configure environment variables

restic is controlled via environment variables for credentials and the passphrase. We store them in a protected file, readable only by root. Create the directory and file:


sudo mkdir -p /etc/restic

sudo nano /etc/restic/b2.env

restic communicates with Backblaze via the S3-compatible API. Fill in:


# S3 Endpoint for your bucket (from Step 1)

export RESTIC_REPOSITORY="s3:https://s3.eu-central-003.backblazeb2.com/backup-srv-selfhostr-2026"



# B2 Application Key credentials

export AWS_ACCESS_KEY_ID="YOUR_keyID"

export AWS_SECRET_ACCESS_KEY="YOUR_applicationKey"



# Repository encryption passphrase (long and unique!)

export RESTIC_PASSWORD="a-very-long-and-random-passphrase"

Lock down permissions; this file contains critical secrets:


sudo chmod 600 /etc/restic/b2.env

sudo chown root:root /etc/restic/b2.env

Common pitfall: The bucket name in RESTIC_REPOSITORY must match exactly, and the endpoint must be that of your region (the number after eu-central- varies). An error here results in an unhelpful Access Denied.

Step 4: Initialize the restic repository

Load the variables and initialize the encrypted repository (do this only once):


sudo bash -c 'source /etc/restic/b2.env && restic init'

You will receive a confirmation message with the repository ID. This is when the encrypted structure is created on Backblaze. From now on, all data sent is deduplicated and encrypted client-side with AES-256 before transfer.

Verify that the repository responds correctly:


sudo bash -c 'source /etc/restic/b2.env && restic snapshots'

The list is empty for now, but the absence of errors confirms that the credentials and passphrase are correct.

Step 5: First manual backup

Let’s back up typical server directories: application data, configuration, and Docker volumes. Adjust paths to your case:


sudo bash -c 'source /etc/restic/b2.env && restic backup \

  /etc \

  /home \

  /var/lib/docker/volumes \

  --exclude="/var/lib/docker/volumes/*/_data/cache" \

  --tag manual'

restic displays progress, the number of files, and the amount of data actually transferred (thanks to deduplication, only new or modified blocks go over the network). At the end, a new snapshot appears:


sudo bash -c 'source /etc/restic/b2.env && restic snapshots'

Backing up a database properly

Never copy database files while they are running: you risk a corrupted backup. Perform a dump and then back up the stream. Example PostgreSQL in a Docker container, piping directly to restic via stdin:


sudo bash -c 'source /etc/restic/b2.env && \

  docker exec -t mon-postgres pg_dumpall -U postgres | \

  restic backup --stdin --stdin-filename postgres-dump.sql --tag db'

For MySQL/MariaDB, replace with mysqldump --all-databases. This method guarantees a consistent, point-in-time backup.

Step 6: Automate with a script and systemd

We create a backup script that also includes retention cleanup. Create the file:


sudo nano /etc/restic/backup.sh

#!/usr/bin/env bash

set -euo pipefail

source /etc/restic/b2.env



# 1. Database dump

docker exec -t mon-postgres pg_dumpall -U postgres \

  | restic backup --stdin --stdin-filename postgres-dump.sql --tag db



# 2. File backup

restic backup /etc /home /var/lib/docker/volumes \

  --exclude-caches \

  --tag auto



# 3. Apply retention policy

restic forget \

  --keep-daily 7 \

  --keep-weekly 4 \

  --keep-monthly 6 \

  --prune

Make it executable:


sudo chmod 700 /etc/restic/backup.sh

The retention policy above keeps the last 7 daily backups, 4 weekly, and 6 monthly, then --prune truly frees up space for data no longer referenced. A good balance between cost and history.

Create the systemd service and timer

systemd is more robust than a standard cron job (log management, dependencies, failure handling). Create the service unit:


sudo nano /etc/systemd/system/restic-backup.service

[Unit]

Description=Restic backup to Backblaze B2

After=network-online.target docker.service

Wants=network-online.target



[Service]

Type=oneshot

ExecStart=/etc/restic/backup.sh

Nice=10

IOSchedulingClass=best-effort

IOSchedulingPriority=7

Then the timer that triggers it every night:


sudo nano /etc/systemd/system/restic-backup.timer

[Unit]

Description=Launches daily restic backup



[Timer]

OnCalendar=*-*-* 03:30:00

RandomizedDelaySec=900

Persistent=true



[Install]

WantedBy=timers.target

Persistent=true catches up on a missed backup if the server was off at the scheduled time. Enable the timer:


sudo systemctl daemon-reload

sudo systemctl enable --now restic-backup.timer

Check the schedule:


systemctl list-timers restic-backup.timer

Run an immediate execution to test the full script end-to-end:


sudo systemctl start restic-backup.service

journalctl -u restic-backup.service -n 50 --no-pager

Step 7: Verify backup integrity

A silently corrupted backup is worse than no backup. restic can check the repository integrity. A quick metadata check:


sudo bash -c 'source /etc/restic/b2.env && restic check'

For a thorough check that re-downloads and verifies a sample of actual data (recommended once a month):


sudo bash -c 'source /etc/restic/b2.env && restic check --read-data-subset=10%'

Step 8: Test restoration (the step always skipped)

This is the most important and most neglected step. Restore to a temporary location to validate that your data is recoverable:


# List snapshots and identify the desired ID

sudo bash -c 'source /etc/restic/b2.env && restic snapshots'



# Restore the latest snapshot to /tmp/restore-test

sudo bash -c 'source /etc/restic/b2.env && \

  restic restore latest --target /tmp/restore-test'

Inspect /tmp/restore-test and verify that your files are intact. To restore a single file or folder, use --include:


sudo bash -c 'source /etc/restic/b2.env && \

  restic restore latest --target /tmp/restore-test --include /etc/caddy/Caddyfile'

To restore a database dump, either mount the repository read-only or use restic dump:


sudo bash -c 'source /etc/restic/b2.env && \

  restic dump latest postgres-dump.sql | docker exec -i mon-postgres psql -U postgres'

Schedule a real restoration test quarterly. This is the only way to be certain your strategy holds up.

Best practices and security

  • Keep the passphrase off the server. If the server is compromised, the attacker should not be able to read or destroy your backups. Ideally, the B2 key used by the server has only write (append-only) permission, not delete.

  • Enable object retention on Backblaze to make your backups immutable for a given window: ultimate ransomware protection.

  • Monitor failures. Couple the timer with an alert (email, webhook, or a Uptime Kuma “push” probe) to be notified if a backup fails. See our guide monitor your homelab with Uptime Kuma and Grafana.

  • Document the restoration procedure in a place accessible even if the server is dead (password manager, personal wiki).

  • Never put secrets in the script: the .env file with 600/root permissions is the correct place.

FAQ

Why restic instead of rsync or simple tar?

restic provides three things that tar or rsync do not offer natively: deduplication (identical blocks are stored only once, saving massive amounts of space), end-to-end encryption (your data is unreadable on the provider side), and versioning via snapshots with automatic retention. To compare with Borg and Kopia, read restic vs Borg vs Kopia in 2026.

How much does it really cost on Backblaze B2?

B2 charges approximately $6 per TB per month for storage, and outbound traffic (restoration) is free up to 3x the stored size each month. For a server whose deduplicated data fits in 50 GB, you pay a few cents per month. The first 10 GB are free. It is one of the cheapest options, as shown in our B2 vs Wasabi vs Storj comparison.

What if I forget the repository passphrase?

Nothing. This is intentional: restic encrypts everything client-side; without the passphrase, there is no backdoor to decrypt it. Your backups become permanently unusable. This is why this passphrase must be stored in a reliable password manager, separate from the server, right from initialization.

Does the backup slow down my server?

Very little if you follow this guide. The Nice=10 and IOSchedulingClass=best-effort directives in the systemd service give restic low priority, yielding to application processes. By scheduling it at 3:30 AM, the impact is negligible for almost all use cases.

Can I back up multiple servers to the same repository?

Yes, and it is even an advantage: deduplication works across servers, so common files (system binaries, Docker images) are stored only once. Use distinct --tags per machine to keep things organized. However, be aware of concurrency: restic locks the repository during prune, so stagger the schedules.

Your data is now protected by an off-site, encrypted, deduplicated, and verifiable copy. All that remains is to test a restoration occasionally and sleep soundly. To follow new self-hosted tools and security best practices, join our Telegram watch bot.

Tags: resticbackblaze b2backupencryptionsystemdlinuxdata protection

Related

🛠️ Tutorials

Build Your Own WireGuard VPN on a VPS in 2026: The Complete Guide

2026 tutorial on self-hosting a WireGuard VPN on a Linux VPS. Covers installation, key generation, server and client configuration (mobile, PC), routing, NAT, kill switch, and DNS. Includes exact commands and ready-to-use configs.

Read
🛠️ Tutorials

Hosting a Discord Bot 24/7 on a VPS in 2026: Complete Guide (Node/Python, systemd, Docker)

2026 technical guide for hosting a Discord bot continuously on a VPS. Compare Node vs Python, systemd vs Docker, sizing, costs, and token security for developers.

Read
🛠️ Tutorials

Hosting Nextcloud on a VPS in 2026: Complete Guide (Docker, HTTPS, Performance, Backups)

Comprehensive 2026 technical guide for deploying Nextcloud on a VPS using Docker. Covers server sizing, PostgreSQL and Redis optimization, HTTPS configuration, and reliable backup strategies.

Read