How to Back Up Linux Servers to Backblaze B2 with Restic and Rclone (Encrypted, Automated, Pruned)

Summary: This guide shows how to back up a Linux server to Backblaze B2 using Restic with Rclone as the transport. You will set up encryption, implement a retention policy, automate runs with systemd timers, and test restores. The result is a fast, encrypted, and low-cost off-site backup that you control.

Why Restic + Rclone + Backblaze B2?

Restic is a modern, deduplicating backup tool with built-in encryption. Rclone provides wide storage compatibility and reliable transfers. Backblaze B2 offers affordable object storage with per-GB pricing. Together, they form a portable, verifiable, and cost-effective backup solution that works on any Linux distribution.

Prerequisites

- A Linux server (Ubuntu/Debian/RHEL/AlmaLinux, etc.) with sudo/root access
- Backblaze B2 account
- Basic terminal familiarity

Step 1: Create a B2 Bucket and Key

1) In Backblaze, create a bucket (e.g., mycompany-backups). Leave it private.
2) Create an Application Key restricted to that bucket. Copy the KeyID and Application Key now; you will not see the secret again.

Step 2: Install Restic and Rclone

sudo apt update && sudo apt install -y restic rclone

On RHEL/Fedora-based systems:
sudo dnf install -y restic rclone

Step 3: Configure Rclone for B2

We will keep Rclone’s config out of your home directory for clarity.

sudo mkdir -p /etc/rclone
sudo chmod 750 /etc/rclone

sudo rclone config create b2 b2 account <KeyID> key <ApplicationKey> hard_delete true --config /etc/rclone/rclone.conf

Verify the config:

sudo rclone lsd b2: --config /etc/rclone/rclone.conf

Step 4: Initialize the Restic Repository (via Rclone)

Create a password file and initialize the repository path inside the bucket.

sudo mkdir -p /etc/restic
echo "choose-a-strong-long-passphrase" | sudo tee /etc/restic/password > /dev/null
sudo chmod 600 /etc/restic/password

Initialize:

sudo env RCLONE_CONFIG=/etc/rclone/rclone.conf restic -r rclone:b2:mycompany-backups/restic --password-file /etc/restic/password init

Step 5: Exclusions and Environment File

Define what not to back up (caches, runtime, VM disks, etc.).

sudo tee /etc/restic/excludes.txt > /dev/null <<'EOF'
/proc/**
/sys/**
/dev/**
/run/**
/tmp/**
/var/tmp/**
/var/cache/**
*.iso
*.img
*.qcow2
EOF

Create an environment file to avoid repeating flags:

sudo tee /etc/restic/restic.env > /dev/null <<'EOF'
RESTIC_REPOSITORY=rclone:b2:mycompany-backups/restic
RESTIC_PASSWORD_FILE=/etc/restic/password
RCLONE_CONFIG=/etc/rclone/rclone.conf
RESTIC_CACHE_DIR=/var/cache/restic
EOF
sudo mkdir -p /var/cache/restic && sudo chown root:root /var/cache/restic && sudo chmod 700 /var/cache/restic

Step 6: Create a Backup Script

This script performs a backup, applies retention, and verifies the repository.

sudo tee /usr/local/bin/restic-backup.sh > /dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

# Sources to back up (adjust to your server)
SOURCES=(/etc /home /var/www)

# Nice/ionice to reduce system impact
nice -n 10 ionice -c2 -n7 \

env $(grep -v '^\s*#' /etc/restic/restic.env | xargs) \\
restic backup "${SOURCES[@]}" --exclude-file /etc/restic/excludes.txt --tag scheduled --one-file-system

# Retention policy: keep last 7 daily, 4 weekly, 6 monthly
env $(grep -v '^\s*#' /etc/restic/restic.env | xargs) \\
restic forget --prune --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --tag scheduled

# Optional consistency check (weekly via timer, or keep here for every run)
env $(grep -v '^\s*#' /etc/restic/restic.env | xargs) restic check --read-data-subset=1/20 || true
EOF
sudo chmod 750 /usr/local/bin/restic-backup.sh

Step 7: systemd Service and Timer

Create a systemd unit to run the script, and a timer to schedule it daily.

sudo tee /etc/systemd/system/restic-backup.service > /dev/null <<'EOF'
[Unit]
Description=Restic backup to Backblaze B2 (via rclone)
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
EnvironmentFile=/etc/restic/restic.env
ExecStart=/usr/local/bin/restic-backup.sh
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7
PrivateTmp=yes
NoNewPrivileges=yes
ProtectSystem=full
ProtectHome=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes

[Install]
WantedBy=multi-user.target
EOF

sudo tee /etc/systemd/system/restic-backup.timer > /dev/null <<'EOF'
[Unit]
Description=Daily Restic backup timer

[Timer]
OnCalendar=03:15
RandomizedDelaySec=20m
Persistent=true

[Install]
WantedBy=timers.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer

Step 8: First Run and Verification

Trigger a manual run and watch the output:

sudo systemctl start restic-backup.service
sudo journalctl -u restic-backup.service -n 200 -f

List snapshots to confirm:

sudo env $(grep -v '^\s*#' /etc/restic/restic.env | xargs) restic snapshots

Step 9: Tune Retention and Costs

Adjust the restic forget policy to meet recovery objectives and budget. More aggressive pruning reduces storage but limits historical versions. Backblaze B2 costs depend on stored GB, transaction counts, and egress; deduplication in Restic helps keep usage low.

Step 10: Test a Restore

Never trust backups you have not restored. Create a temporary restore folder and recover a small file.

sudo mkdir -p /tmp/restore-test
sudo env $(grep -v '^\s*#' /etc/restic/restic.env | xargs) restic restore latest --target /tmp/restore-test --include /etc/hostname
ls -l /tmp/restore-test/etc/hostname

Security Best Practices

- Use a long, unique Restic password stored in a root-only file.
- Restrict the Backblaze Application Key to one bucket with minimal permissions.
- Enable MFA on your Backblaze account.
- Keep /etc/rclone/rclone.conf and /etc/restic/password mode 600 and owned by root.
- Consider server-side encryption on B2 as a secondary layer if required by policy, although Restic already encrypts data client-side.

Performance Tips

- Parallel uploads: Restic auto-tunes, but you can increase concurrency on bigger servers via RESTIC_OPTIONS like --jobs 4 for backups or use Rclone env vars (RCLONE_B2_UPLOAD_CONCURRENCY).
- Bandwidth limits: Add --limit-upload 4MiB to Restic, or --bwlimit via Rclone if needed.
- Exclude large/ephemeral paths to reduce churn.

Troubleshooting

Fatal: wrong password or no key found: The password in /etc/restic/password does not match the repository. Fix the password file or re-init a new repo.

Repository locked: A previous run crashed. Remove stale locks only when you are certain no job is running:
sudo env $(grep -v '^\s*#' /etc/restic/restic.env | xargs) restic unlock

Slow uploads or timeouts: Check outbound bandwidth, raise concurrency, and ensure your firewall allows long-lived HTTPS connections. Try adding a randomized delay (already in the timer) to avoid contention on shared links.

What You Achieved

You now have an automated, encrypted, off-site backup pipeline for Linux using Restic, Rclone, and Backblaze B2. Snapshots are deduplicated, retention is enforced, and restores are provable. Regularly verify snapshots, monitor storage usage, and adjust policies as your data grows.

Build Your Own Encrypted S3 Backup with Restic and MinIO (Docker Compose, 2025 Guide)

If you want fast, encrypted, and deduplicated backups without paying for a public cloud, pairing Restic with MinIO is a powerful option. Restic handles client-side encryption and incremental backups; MinIO provides an S3-compatible object store you fully control. In this hands-on guide, you will deploy MinIO using Docker Compose, initialize a Restic repository, automate backups with a retention policy, and verify restores. The steps work on modern Linux distributions (Ubuntu/Debian/RHEL) and on any host that can run Docker.

Prerequisites

- A Linux server with at least 2 CPU cores, 4 GB RAM, and storage sized to your backup needs.
- Docker and Docker Compose installed.
- A shell user with sudo rights.
- Optional but recommended: a hostname and TLS if exposing MinIO beyond localhost.

Step 1 — Create a Docker Compose file for MinIO

We will run MinIO on ports 9000 (S3 API) and 9001 (web console). Use a strong root user and password. Put the credentials into a .env file so they are not hard-coded in the Compose file.

# .env
MINIO_ROOT_USER=minioadmin_change_me_now
MINIO_ROOT_PASSWORD=SuperStrong_Passw0rd_change_me
MINIO_DATA_PATH=./minio-data
# docker-compose.yml
services:
  minio:
    image: minio/minio:latest
    container_name: minio
    command: server /data --console-address ":9001"
    ports:
      - "9000:9000"   # S3 API
      - "9001:9001"   # Web Console
    environment:
      - MINIO_ROOT_USER=${MINIO_ROOT_USER}
      - MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
    volumes:
      - ${MINIO_DATA_PATH}:/data
    restart: unless-stopped

Start MinIO:

docker compose up -d

Open the web console at http://<server-ip>:9001 and sign in with the root user credentials from the .env file.

Step 2 — Create a bucket and a dedicated access key

For clear separation, create a bucket named restic and generate a dedicated access key limited to that bucket.

Option A (Web Console):

- Storage → Create bucket → Name: restic.
- Identity → Service Accounts → Create access key → Scope: restrict to the restic bucket (read/write). Save the Access Key and Secret Key.

Option B (CLI, quick start):

# Uses MinIO Client without permanent install
docker run --rm --network host \
  -e MC_HOST_local="http://${MINIO_ROOT_USER}:${MINIO_ROOT_PASSWORD}@127.0.0.1:9000" \
  minio/mc mb local/restic

For production, prefer a limited service account rather than using the root keys in automation.

Step 3 — Initialize a Restic repository

Install Restic from your distribution or from the official releases. Then export environment variables for the repository URL and credentials. Replace placeholders with your actual keys.

export RESTIC_REPOSITORY="s3:http://127.0.0.1:9000/restic"
export AWS_ACCESS_KEY_ID="YOUR_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_KEY"
export RESTIC_PASSWORD="Choose_A_Strong_Repo_Password"

Initialize the repository (first time only):

restic init

Restic encrypts data with the password you set, before uploading. Keep this password safe; without it, restores are impossible.

Step 4 — Create a backup script with retention

Let’s script a daily backup with sensible retention (7 daily, 4 weekly, 6 monthly) and basic integrity checks.

sudo tee /usr/local/bin/restic-backup.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

# Environment (consider moving to /etc/restic/.env and source it)
export RESTIC_REPOSITORY="s3:http://127.0.0.1:9000/restic"
export AWS_ACCESS_KEY_ID="YOUR_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_KEY"
export RESTIC_PASSWORD="Choose_A_Strong_Repo_Password"

# What to back up
INCLUDE_DIRS=(
  "/etc"
  "/var/www"
  "/var/lib/docker/volumes/project_data/_data"
  "$HOME"
)

# Exclusions
EXCLUDES=( 
  "--exclude-file=/etc/restic-excludes.txt"
)

# Run backup
restic backup "${EXCLUDES[@]}" "${INCLUDE_DIRS[@]}"

# Retention and pruning
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

# Lightweight consistency check (5% of data)
restic check --read-data-subset=5%
EOF
sudo chmod +x /usr/local/bin/restic-backup.sh

Create a simple exclusions file to skip caches and temporary data:

sudo tee /etc/restic-excludes.txt >/dev/null <<'EOF'
/home/*/.cache
/var/cache
/var/tmp
*.iso
*.qcow2
node_modules
EOF

Schedule the backup with cron:

(crontab -l 2>/dev/null; echo "0 2 * * * /usr/local/bin/restic-backup.sh >> /var/log/restic.log 2>&1") | crontab -

Tip: For long-running servers, a systemd timer is often more reliable than cron. Also consider moving credentials into a protected file (chmod 600) and sourcing it inside the script.

Step 5 — Test listing and restoring

Verify snapshots:

restic snapshots

Restore a file or directory to a safe location:

# Find a snapshot ID from 'restic snapshots'
restic restore latest --target "$HOME/restore-test" --include /etc/hosts

Always test a restore. A backup you cannot restore is not a backup.

Step 6 — Secure access and expose safely

- Use HTTPS for MinIO. Either terminate TLS directly in MinIO (via certificates at /data/.minio/certs) or put MinIO behind a reverse proxy like Caddy or Nginx with automatic Let’s Encrypt.
- If backing up from remote machines, prefer private networks (Tailscale/WireGuard) rather than exposing port 9000 to the internet.
- Set strong passwords and rotate access keys periodically.

Step 7 — Useful maintenance and troubleshooting

- Verify integrity periodically: restic check (run monthly with full read if you can).
- Remove stale locks: restic unlock if a job was interrupted.
- Monitor logs: tail -f /var/log/restic.log for failures or timeouts.
- Storage growth: run restic prune occasionally (already included with forget --prune) and review your exclude list.

Why this stack works in 2025

Restic remains one of the most efficient open-source backup tools thanks to encryption-by-default, deduplication, and built-in S3 support. MinIO provides a modern, high-performance, and S3-compatible backend you can run on-prem or at the edge. With Docker Compose, you can upgrade easily, keep state on mapped volumes, and move the stack between servers without changing your backup commands.

With the steps above, you now have a repeatable, scriptable, and secure backup workflow: data is encrypted before it leaves the host, stored in an S3 bucket you control, and cleaned up automatically with a clear retention policy. Don’t forget to document your RESTIC_PASSWORD location and your MinIO access keys, and test restores on a schedule.

Popular Posts

Install Ollama and Open WebUI on Ubuntu 24.04 with NVIDIA GPU Acceleration (Step-by-Step)

Install Ollama + Open WebUI on Ubuntu 24.04 with NVIDIA GPU Acceleration (Step-by-Step)

Install a Local AI Chatbot on Ubuntu 24.04 with Ollama and Open WebUI (Step-by-Step)

Trending Now

Recovering from Btrfs Boot Failures Using GUI Tools on Fedora

By the end of this guide the reader will be able to identify a Btrfs‑based Fedora installation, boot from a live USB, list and restore snapshots using the graphical utilities btrfs‑assistant and snapper, and verify that the system returns to a functional state without resorting to the command line. Understanding the Btrfs Layout Used by Fedora Fedora Workstation and Fedora KDE install the root filesystem as a single Btrfs partition that contains two default sub‑volumes. One sub‑volume holds the traditional “/” hierarchy, while the second is dedicated to /var/lib/machines . The latter exists to keep container images out of snapshot operations; it remains empty on systems that do not run virtual machines. Because Btrfs stores data in sub‑volumes rather than separate partitions, a snapshot captures the state of an entire sub‑volume at a point in time. The installer (Anaconda) automatically registers these sub‑volumes with the snapper service. Snapper maintains a series of read‑only ...