Skip to main content

Cheap, Encrypted Offsite Backup with Backblaze B2 and Rclone

·1825 words·9 mins
Author
Shane Blaufuss, CISSP

My Proxmox server runs a 4TB /u01 drive that gets shared out to the home network via SMB and NFS. It also hosts VM disk images. Between the shared storage and the VMs, there’s about 350GB of data worth keeping: documents, photos, ISOs, and VM backups. For a long time it had no offsite backup, which is the kind of thing you’re fine with right up until you’re not. Getting that data off-site used to mean either paying AWS S3 prices or trusting a consumer backup service with your data. Backblaze B2 changed the math. This is how I set up encrypted, automated offsite backups for about $2.50 a month.


Key Takeaways
#

  • Backblaze B2 costs $6.95/TB/month with free egress (up to 3x your storage) and free transactions, roughly a third of S3 Standard pricing for the same workload
  • Rclone’s crypt remote layers client-side encryption on top of B2 storage; Backblaze never sees your plaintext data or filenames
  • This is meaningfully different from B2’s built-in encryption setting, where Backblaze holds your keys
  • The crypt config wizard handles the hard parts; what you must do is save your two passwords somewhere safe before you close it
  • A systemd timer handles the nightly schedule cleanly, with no cron involved

Why B2 Instead of S3
#

The pricing is the whole story. AWS S3 Standard runs about $23/TB/month, plus egress fees that can easily double your bill if you ever need to restore a large amount of data. B2 at $6.95/TB has free egress up to three times your stored data per month and charges nothing for API transactions. For 350GB, that’s roughly $2.43/month versus about $8 on S3 (about a third of the price), and the egress situation is dramatically better.

Backblaze also doesn’t have the complexity tax that comes with AWS. There’s no IAM policy to untangle, no 47 storage classes to reason about, and no surprise bills from Lambda functions you forgot were touching S3.

The one thing B2 lacks compared to S3 is ecosystem depth. If you need Lambda triggers, S3 Batch Operations, or tight integration with other AWS services, B2 is not the right answer. For “store my files durably and cheaply,” it is.


Architecture
#

The setup is two rclone remotes, one stacked on the other:

Proxmox fileserver (/path/to/your/data)
    |
    v
rclone crypt remote  <-- encrypts/decrypts everything in flight
    |
    v
rclone B2 remote    <-- talks to Backblaze over HTTPS
    |
    v
Backblaze B2 bucket

The source path is wherever your data lives — in this case a mount under /u01. The crypt remote sits between rclone and B2. When you write, rclone encrypts the data and the filename before it ever leaves your machine. When you read, it decrypts on the way back. Backblaze stores encrypted blobs with scrambled names and has no way to read your data without your passwords.


Step 1: Create a B2 Bucket and API Keys
#

1a. Create the bucket
#

Sign up at backblaze.com if you haven’t. Under B2 Cloud Storage, create a bucket. Set visibility to private and leave server-side encryption off (you’re handling encryption yourself). Name it something you’ll recognize.

1b. Create an application key
#

Go to App Keys and create a new key. Scope it to the bucket you just created, with read and write permissions. When you save it, Backblaze shows you the application key exactly once. Copy it immediately.

Put the key ID and the application key in your password manager right now, before you do anything else.


Step 2: Install Rclone
#

On Debian:

sudo apt install rclone

Or pull the latest release directly from rclone.org if you want a newer version than what’s in the repos. Either works.


Step 3: Configure the B2 Remote
#

rclone config

Walk through the wizard:

No remotes found, make a new one?
n) New remote
n> n

Enter name for new remote.
name> b2-homelab

Type of storage to configure.
Storage> Backblaze B2

Option account (Backblaze Account ID).
account> YOUR_KEY_ID_HERE

Option key (Backblaze Application Key).
key> YOUR_APP_KEY_HERE

The resulting section in ~/.config/rclone/rclone.conf looks like:

[b2-homelab]
type = b2
account = your_key_id_here
key = your_application_key_here
hard_delete = false
lifecycle = 14

hard_delete = false tells rclone to hide deleted files rather than permanently remove them, which is what lets B2’s versioning retain them. lifecycle = 14 sets the retention window to 14 days before hidden versions are purged.

Test it:

rclone ls b2-homelab:your-bucket-name

Empty bucket, no errors. Good.


Step 4: Configure the Crypt Remote
#

This is the part that matters most. Run rclone config again and create a new remote:

Note: filename_encryption and directory_name_encryption are optional config that the wizard may not prompt for by default. When the wizard asks if you want to edit advanced config, say yes. If you skip past it, you can add these directly to ~/.config/rclone/rclone.conf under the crypt remote section afterward.

Walk through the wizard:

Current remotes:

Name                 Type
====                 ====
b2-homelab           b2

e) Edit existing remote
n) New remote
d) Delete remote
n> n

Enter name for new remote.
name> b2-homelab-crypt

Type of storage to configure.
Storage> crypt

Option remote (Remote to encrypt/decrypt).
remote> b2-homelab:your-bucket-name

Option filename_encryption.
filename_encryption> standard

Option directory_name_encryption.
directory_name_encryption> true

Option password (Password or pass phrase for encryption).
password> YOUR_STRONG_PASSWORD_HERE

Option password2 (Password or pass phrase for salt).
password2> YOUR_SECOND_PASSWORD_HERE

Rclone calls the second one a “salt” but functionally it’s a second password. Using both means an attacker needs both to decrypt anything. Neither can be recovered if you lose it. Write them both down somewhere offline and put them in your password manager.

The config entry looks like:

[b2-homelab-crypt]
type = crypt
remote = b2-homelab:your-bucket-name
filename_encryption = standard
directory_name_encryption = true
password = RCLONE_OBSCURED_VALUE
password2 = RCLONE_OBSCURED_VALUE

Rclone stores the passwords in its own obscured format in the config file. The config file itself should not be world-readable:

chmod 600 ~/.config/rclone/rclone.conf

Test a sync to the crypt remote:

rclone sync /path/to/a/test/directory b2-homelab-crypt: --progress

Then browse your B2 bucket in the web console. You should see files with names that look like garbled nonsense. That’s correct. Nothing in the bucket is readable without the passwords.


A Note on B2’s Built-In Encryption
#

Backblaze offers a server-side encryption option in the bucket settings. It is not the same as what we’re doing here and it is worth understanding why.

With B2’s built-in encryption, Backblaze manages the keys. Your data is encrypted at rest, which protects you from someone physically stealing a hard drive from a Backblaze data center. It does not protect you from Backblaze itself, from a legal request served to Backblaze, or from a breach of Backblaze’s key management infrastructure.

With rclone crypt, the encryption and decryption happen on your machine before anything is transmitted. Backblaze receives only ciphertext. They cannot decrypt it. Your keys never leave your environment. If Backblaze gets a subpoena for your data, they hand over encrypted blobs that are useless without passwords they don’t have.

For home lab data, this distinction probably isn’t your primary threat model. For anything sensitive (client files, legal documents, medical records), it matters a lot.


Step 5: Automate with a Systemd Timer
#

A cron job would work, but systemd timers give you better logging and automatic catch-up if the machine was off at the scheduled time (via Persistent=true).

Create the service file:

# /etc/systemd/system/rclone-b2-backup.service
[Unit]
Description=Rclone backup to Backblaze B2
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
User=root
ExecStart=/usr/bin/rclone sync /srv/backup b2-homelab-crypt: \
    --log-file=/var/log/rclone-b2-backup.log \
    --log-level INFO \
    --stats-log-level DEBUG

And the timer:

# /etc/systemd/system/rclone-b2-backup.timer
[Unit]
Description=Daily Backblaze B2 backup at 2am

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

[Install]
WantedBy=timers.target

Enable and start the timer:

systemctl daemon-reload
systemctl enable --now rclone-b2-backup.timer

Verify it’s scheduled:

systemctl list-timers rclone-b2-backup.timer

The first run will upload everything. Subsequent runs only transfer changed or new files. For 350GB of mostly static content (ISOs, old VM disks), nightly runs are fast once the initial upload completes.


What the Bill Looks Like
#

First full day of storage: $0.04. At steady state, 350GB at $6.95/TB/month works out to about $2.43/month. Egress is free up to 1.05TB per month (three times your stored data), which covers any realistic restore scenario short of a total loss.

For context, the same data on S3 Standard would run roughly $8/month in storage alone, before egress. If you ever needed to restore all 350GB, you’d pay an additional $31 in data transfer out on S3. On B2, that restore is free.


Don’t Lose Your Passwords
#

This bears repeating because it’s the one way this setup fails catastrophically. Rclone’s crypt remote cannot be recovered without both passwords. There is no “forgot my password” flow, no key escrow, and no support ticket that will help you. Backblaze can hand you your encrypted files and you will be completely unable to read them.

Store the passwords and your B2 API key in a password manager. Consider keeping an offline copy somewhere physically separate from your homelab. If your homelab burns down and you lost your password database with it, you’ve just discovered that your backup was not actually a backup.

The rclone config file itself contains obscured versions of the passwords and should be backed up too, or at least the passwords should be stored in their plaintext form somewhere you control.


What This Doesn’t Cover
#

This setup syncs files. It is not a snapshot-based backup and does not give you point-in-time recovery. If you accidentally delete a directory and rclone runs before you notice, the deletion propagates to B2.

Backblaze offers object versioning and a lifecycle rule system that can keep deleted files around for a configurable window. Setting hard_delete = false and lifecycle = 14 in the B2 remote config tells rclone to hide deleted files rather than permanently remove them, and instructs B2 to purge those hidden versions after 14 days. A file that gets accidentally deleted or overwritten can be recovered from an earlier version within that window, turning a sync-based backup into something closer to point-in-time recovery. There’s a small storage cost for the retained versions, but for home lab data it’s negligible.

For VM disk images specifically, rclone will happily upload a disk image mid-write from a running VM, and what you get back may not be bootable. The correct approach is to use Proxmox’s built-in backup (vzdump) to take consistent snapshots first, then point rclone at the directory where Proxmox writes those .vma.zst archives. That’s how this is currently set up: Proxmox runs nightly vzdump jobs to a local directory, and rclone syncs that directory to B2. The snapshots are properly quiesced; rclone is just the transport layer.


The initial upload of 350GB took a few hours over a home internet connection. Everything after that has been quiet background noise at 2am. At this price point, there’s no reason to leave data sitting around with no offsite copy.


This is not a sponsored post. Greymantle Risk Advisory has no affiliation with Backblaze. I just use the product and think it’s good.