The convenient place to put files is someone else’s computer
File sync is one of those things that works so well out of the box that you stop thinking about where your files actually are. You drop something in a folder, it appears on your other devices, and the question of whose disk it’s sitting on never comes up—until it’s a client’s documents, or something you’d rather not have quietly mined, retained, or held hostage behind a subscription.
That’s the same discomfort I keep running into: the easy option makes the decision for you, and the decision it makes is “give the data to whoever’s most convenient.” I wanted the opposite—to decide, on purpose, that my files live somewhere I understand and control.
Why self-host the sync, not just the storage
Plain storage is the easy part. The reason I reached for Nextcloud rather than a bare file server is that the thing I actually use day to day isn’t storage—it’s the sync, sharing, and collaboration layer on top of it. Versioning, share links, clients on every device, a web UI when I’m away from my own machine. That layer is exactly what you give up when you self-host naively, and it’s exactly what makes people crawl back to the convenient option.
So the bar was: own the whole thing, sync layer included, without it becoming a second job to run. The deployment reflects that—the official image via Docker Compose, Postgres and Redis alongside it, a cron sidecar for background jobs. Boring, standard pieces I can reason about and rebuild.
Keeping the files off the box that serves them
The decision I’m actually glad I made is a less obvious one: the files don’t live on the server. User data is configured as primary storage in Hetzner’s S3-compatible object storage, so the box that runs Nextcloud only ever holds the database, Redis, the app config, and a temp buffer for uploads in flight—never the file corpus itself.
That split changes what the server is. It stops being precious. If the VM dies, I haven’t lost anything that matters; the corpus is sitting in object storage, and the box is a rebuildable front end for it. Storage scales on its own terms instead of being capped by whatever NVMe I happened to put in the machine, and backups stop being “image the whole disk” and start being two cleanly separated problems—a small, structured database and a large, boring bucket.
Reachable only from inside
The instance isn’t on the public internet. It’s reachable over WireGuard and the LAN, with no public 80/443 forward at all. The one wrinkle that creates is TLS: the domain is HSTS-preloaded, so a real certificate is non-negotiable, but there’s no inbound HTTP path for the usual challenge. The answer is a DNS-01 ACME challenge—Caddy proves control over the domain by writing a DNS record through the registrar’s API, and gets a publicly trusted cert for a host that the public can’t actually reach.
I like that shape a lot: a service that’s private by construction, but still speaks proper TLS so nothing on my own network has to learn to trust a homemade certificate.
The pattern underneath
This is the same move I keep making. Certificates that renew themselves. Traffic that has exactly one door. And now files that live somewhere I chose on purpose, served by a box I can throw away and rebuild without flinching.
The day-to-day experience is just “file sync, like always.” The difference is underneath: I know where the data is, I know who can reach it, and I know what happens when a piece of it fails—because I drew those lines myself instead of inheriting whatever the convenient option decided for me.