Duplicati to Google Drive: Homelab Backup and Restore
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:1Wretention (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:1Wmeans 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
Dockhand Multi-Host Dashboard
Why I run Dockhand across my Docker hosts, how the Gitea-first deploy flow works, and the API that lets an agent manage containers without SSH.
Docker Compose Basics
The five ideas behind every compose.yaml on this site: images vs containers, volumes, networks, restart policies, and PUID/PGID conventions.
Bitwarden Secrets Manager for AI Agents
How I set up bws (Bitwarden Secrets Manager's CLI) so Claude can fetch homelab credentials itself, no master password, no pasting secrets into chat.
If this saved you some time, a coffee keeps the lights on and the posts coming.
☕ Buy me a coffee