Homelab Haven

Duplicati to Google Drive: Homelab Backup and Restore

September 21, 202610 min read

Most people running a homelab already have a Google account with storage sitting in it. That makes Google Drive one of the lowest-friction 3-2-1 backup targets there is: no new account, no new bill, no new vendor to trust. Most guides stop right there, at "connect your Google account and pick a folder." I've been running Duplicati to Google Drive daily for months now, and the interesting part starts after that: what a real restore actually requires.

Google Drive is what I happen to point it at, and one of the two restore traps below is genuinely specific to that choice. The rest is not. How you set retention, why a green "Success" doesn't mean your data restores, and where the encryption passphrase has to live are the same questions whether you back up to Backblaze, an S3 bucket, or a NAS in the other room. Duplicati speaks to all of them, and there's a section at the end on which backend to pick if Google Drive isn't your answer.

Summary

  • Duplicati 2.4.0.0 in Docker, one job, daily schedule, AES encryption, 4W:1W retention (one restore point per week, four weeks of history).
  • Two restore traps most Google Drive guides don't mention: the encryption passphrase can't live inside the encrypted backup, and a from-scratch restore needs you to re-authorize Google Drive access by hand.
  • 4W:1W means at most four weeks of history. Pick retention against how long your own mistakes take to notice, not against how much disk (or cloud quota) you have.
  • One Google account is a single point of failure for the whole backup. I'm considering a second, Google-independent path.
  • Duplicati supports two dozen other backends. Only Google Drive is actually tested here.

Why Google Drive

The 3-2-1 rule wants three copies, on two kinds of media, one offsite. Offsite is the part that trips people up in a homelab, because it usually means either paying for object storage you've never used before, or building a second physical location you don't have. Google Drive skips both problems if you're already paying for storage there for other reasons. The marginal cost of pointing a backup job at it is zero.

It's not the cheapest option per gigabyte at scale, and it's not the fastest to restore from over a home connection. What it is: the thing you can set up in one sitting, with an account you already trust with other data. For a homelab that's usually the right trade.

The Duplicati setup

I run Duplicati as a container (lscr.io/linuxserver/duplicati), web UI on port 8200. If the shape of this file is unfamiliar, I've written up what every line in a compose file is doing separately:

services:
  duplicati:
    image: lscr.io/linuxserver/duplicati
    container_name: duplicati
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
    volumes:
      - ./config:/config
      - /path/to/app-data:/source/apps
      - /path/to/compose-files:/source_compose
      - /path/to/caddy-config:/source/caddy
    ports:
      - 8200:8200
    restart: unless-stopped

One job, named Google Drive. Three source paths: app data, compose files, and the reverse-proxy config that gives every internal app its name and certificate. That last one is small and easy to forget, and rebuilding it by hand is a miserable afternoon, so it goes in the backup with everything else. Schedule is every day, all seven weekdays. Encryption is AES with a passphrase, set once at job creation and never stored in the compose file or an env var, only typed into the UI.

Worth knowing: Duplicati 2.4 doesn't store the Google Drive target URL in plaintext anywhere on disk. It lives encrypted in Duplicati's own settings database, prefixed enc-v1:. So even if someone got read access to the container's config volume without the passphrase, the backend target and credentials aren't just sitting there in a config file. That's a small detail, but it's the kind of thing that matters more the longer a backup job runs unattended.

Retention: 4W:1W, and what that actually buys you

My retention policy is 4W:1W: keep one restore point per calendar week, going back four weeks. In practice that means my current state, checked today, is 4 restore points, oldest from 2026-08-31, newest from 2026-09-21.

Read that plainly: at most four weeks of history, one snapshot per week. If something silently corrupts a file and nobody notices for five weeks, it's gone. If a mistake happens and gets noticed within the same week it happened, there's a real chance the only restore point for that week already includes the mistake, because Duplicati only keeps one point per week, not one per day.

That's a deliberate trade against storage cost, not an oversight. Every extra restore point Duplicati keeps costs remote storage and dedup overhead. The question to ask yourself isn't "how much history can I afford," it's "how long do my own mistakes typically stay unnoticed." If you tend to catch problems within a day or two, 4W:1W is probably fine. If you're the type to not check a service for a month, it isn't, and you should keep daily points for longer before falling back to weekly.

The two restore traps

These showed up during a disaster-recovery review, not during normal operation. Normal operation looks perfect: green checkmarks, daily runs, verified remote files. None of that tells you whether a from-scratch restore actually works.

Trap one: the passphrase can't be inside the backup

The AES passphrase encrypts everything in the job, including Duplicati's own settings database. That's circular: restoring from scratch needs the passphrase to decrypt anything, but the passphrase itself isn't recoverable from the backup it protects. It has to exist somewhere else entirely, before the disaster.

My answer was to memorize it, and deliberately not put it in the password vault next to everything else. That's a real trade-off, not a universal recommendation: the vault is redundant and backed up itself (I lean on Bitwarden heavily elsewhere), my memory isn't. If I forget the passphrase or I'm not around to type it, there's exactly one copy and it's gone with me. I made that choice knowing the residual risk, not by accident. Write down what you'd do if the one person who remembers isn't available, and decide if that's acceptable for your setup.

Trap two: the Google Drive AuthID needs re-authorizing from scratch

Duplicati's Google Drive backend uses an AuthID token, generated through an OAuth flow in a browser the first time you set up the job. That token lives in Duplicati's settings database, which on a bare machine you don't have yet, because it's inside the backup.

Follow that around: to restore the settings database you have to reach Google Drive, and to reach Google Drive you need an AuthID, which is in the settings database. So a from-scratch restore always starts by authorizing Google Drive again by hand, in the restore wizard, before Duplicati can list a single file. You need a working browser and a live login to the same Google account, at exactly the moment everything else is down.

That's the hidden cost of "the storage you already have." The convenience of reusing an existing account cuts both ways: if that account is locked, suspended, or you can't log into it right now, the reauthorization step blocks the whole restore until it's resolved.

Verifying it works

A green "Success" status tells you the run completed. It doesn't tell you the data restores. So I look past the summary text at the state of the remote data itself.

The web UI's job log breaks down error and warning counts per run, and separately reports remote verification: how many remote volumes Duplicati checked against their expected hash, and how many failed or went missing. That's the first place to look.

The number I care about most is the count of remote volumes sitting in a state other than Verified. Duplicati keeps a per-job SQLite database under /config, named for the job's internal hash, and every uploaded volume has a state in it. One caveat if you go digging: the linuxserver image does not ship the sqlite3 command line tool, so docker exec duplicati sqlite3 ... gets you exec: "sqlite3": executable file not found in $PATH rather than a prompt. It does ship Python, which has SQLite built in:

docker exec duplicati python3 -c "
import sqlite3, glob, os
for db in glob.glob('/config/*.sqlite'):
    if 'Duplicati-server' in db: continue          # skip the settings DB
    c = sqlite3.connect(f'file:{db}?mode=ro', uri=True)
    print(os.path.basename(db))
    for state, n, size in c.execute(
        'SELECT State, COUNT(*), SUM(Size) FROM Remotevolume GROUP BY State'):
        print(f'  {state:12} {n:5}  {(size or 0)/1e9:.2f} GB')
    print('  restore points:', c.execute('SELECT COUNT(*) FROM Fileset').fetchone()[0])
"

Opening it read-only matters: that database belongs to a running service, and you are a visitor in it.

For my job that prints 200 volumes Verified totalling about 4.95 GB, 144 already Deleted by the 4W:1W retention, and 4 restore points. Across 79 runs the job tracks 81,625 files. What I'm looking for is that everything is Verified and nothing is stuck: volumes lingering in Uploading or Deleting long after a run finished mean Duplicati and Google Drive disagree about what's actually up there, and a run summary can still say "Success" while that's true.

None of that replaces an actual restore test. I schedule one periodically: pick a handful of files, restore them to a scratch location, and open them. "It says success" and "it restores" are different claims, and only one of them is the one you need to be true during an actual incident.

Other backends, if Google Drive isn't right for you

Duplicati ships a lot more than Google Drive. Listing the backend modules inside my 2.4.0.0 container turns up: AliyunOSS, AzureBlob, Backblaze, Box, DrimeCloud, Dropbox, FTP, File, Filejump, Filen, GoogleServices, Idrivee2, Jottacloud, Mega, MovistarCloud, OneDrive, OpenStack, Rclone, S3, SMB, SSHv2, SharePoint, Storj, TahoeLAFS, TencentCOS, WEBDAV, and pCloud.

Grouped by what they're actually good for:

  • Storage you probably already have: Google Drive, OneDrive, Dropbox, Box, pCloud. Same pitch as this whole post, zero marginal cost if you're already paying for the space.
  • Purpose-built object storage, cheaper per TB at scale: Backblaze B2, S3, Storj, Azure Blob, IDrive e2. Worth it once your backup set outgrows what a consumer cloud drive's free or bundled tier gives you.
  • Your own hardware, no third party: SMB, SSH/SFTP, FTP, WebDAV (which is also how you'd point Duplicati at a self-hosted Nextcloud instance). No account dependency at all, but you own the offsite problem yourself.
  • Rclone as the escape hatch: if a target isn't natively listed, Rclone supports dozens more backends and Duplicati can shell out to it.

I want to be honest about that list: only the Google Drive backend is actually running here. The rest are supported by Duplicati, I haven't tested any of them myself, and I'm not going to pretend otherwise just to make this section longer.

What I'd do differently

Google Drive as a single backend is a single point of failure for the whole backup, not just a target. Account loss, suspension, or a lockout takes the backup with it, same moment it takes everything else in that account. I'm actively considering a second, Google-independent path: a local Duplicati repository, replicated to a second machine with Syncthing, so a Google account problem doesn't leave me with zero recent backups. That's not built yet, just under consideration.

If I were setting this up again from nothing, I'd write the disaster-recovery steps down before the first backup job ever ran, not after a DR review found the two traps above the hard way. "Where does the passphrase live, and where does the AuthID come from on a from-scratch restore" are questions worth answering while everything still works, not during the incident where you actually need the answer.

Related

If this saved you some time, a coffee keeps the lights on and the posts coming.

☕ Buy me a coffee

Comments

Comments are checked before they appear.