What I Would Do Differently Self-Hosting From Scratch
A checkpoint, not a victory lap
Ten parts in, the core build works. It’s quiet, it’s mostly local, and it does what I wanted: keeps my media, photos, and documents in tools I chose. But “it works” hides a lot of small detours I took to get here. The best lessons from this whole project didn’t come from the big wins. They came from the little annoyances and rough edges I created early and had to clean up later.
So this is a checkpoint. The series keeps growing whenever a new service earns its place, so this post exists as “lessons so far.” I plan to revisit it as the build picks up more pieces. If I wiped the laptop tomorrow and started over, here’s what I’d do differently. None of it is dramatic. It’s mostly about deciding a few conventions up front instead of discovering them halfway through.
What this solves
- Names the early decisions that paid off and the ones that cost me.
- Front-loads the boring choices that make everything else easier.
- Keeps every service I add after this one calmer to live with.
I’d lock the folder layout on day one
The single best decision I made, mostly by luck, was splitting config and data: /srv/appdata/ for app config and /srv/storage/ for big user media. I stumbled into that around part 5, and it paid off everywhere afterward. Backups, in particular, get trivial because of it: I can point at two trees and know exactly what I’m protecting.
What I’d change: I’d decide that split before installing the very first service, not a few services in. The first couple of apps I set up didn’t follow the pattern cleanly, and I had to move things around later. Moving a running service’s data is exactly the kind of fiddly, slightly risky chore I started this project to avoid. Pick the layout first, then never think about it again.
I’d keep appdata organized per service
Related, but worth its own point. Inside /srv/appdata/, the convention that aged well was one folder per service, each holding its own docker-compose.yml, its .env, and its config. When everything for a service lives in one predictable place, I can back it up, move it, or rebuild it without hunting.
Where I slipped early: a couple of services had their compose file in one place and their data somewhere else, because I followed a tutorial without translating it to my own layout. Months later, that inconsistency is exactly what makes you nervous to touch a service. The fix is a rule I’d set from the start: every service is fully described by its own folder, no exceptions. If I can’t back up a service by copying one directory, I set it up wrong.
I’d set up local DNS much earlier
I didn’t add Pi-hole and Caddy until part 10, and for nine parts I typed IP-and-port URLs like 192.168.1.50:2283. It worked, but it made the whole thing feel like a pile of experiments instead of a system. The day I switched to clean hostnames, the server suddenly felt real.
I’d front-load that. Clean local URLs aren’t a finishing touch. They’re a quality-of-life upgrade that makes every other step nicer, including writing things down, sharing access with my household, and adding new services. The cost of doing it early is one afternoon. The cost of doing it late is months of small friction and a stack of bookmarks I had to redo. Easy call in hindsight.
I’d set up backups before the data, not after
As I write this checkpoint, I still haven’t taken backups seriously, which means Immich and Paperless are holding irreplaceable data with no protection right now. Nothing bad has happened. But “nothing bad happened” is luck, not a strategy, and I know it every time I think about it.
If I started over, backups would come before the first service that holds anything I can’t recreate. Not after. The honest version of this project is that the most important infrastructure, storage layout and backups, is the least fun to set up, so it’s the easiest to defer. Deferring it is the mistake. I’d rather have an empty backup job running and ready than a full server I’m quietly hoping won’t die.
I’d standardize Docker conventions from the start
Across the series, some services run as Docker Compose stacks and a couple run as plain systemd units, and even among the Compose ones, my early files weren’t consistent. Different restart policies, different ways of handling environment variables, ports declared in slightly different styles. None of it breaks anything. All of it adds tiny friction every time I revisit a file.
What I’d standardize next time, on day one:
- Every containerized service uses Compose, even single-container ones.
restart: unless-stoppedeverywhere, so things come back after a reboot.- Config and secrets always in a
.envnext to the compose file. - The same folder shape for every service.
Consistency isn’t about elegance. It’s about being able to open any service’s folder a year later and instantly know how it works, because they all work the same way. Future me is the main beneficiary, and future me has a worse memory than I’d like to admit.
I’d resist app sprawl harder
This is the one that’s more about discipline than technique. Self-hosting has a gravity to it: there’s always one more cool service to add, one more arr-app, one more dashboard widget. I added a reasonable set across this series, but I felt the pull toward more, and more is the enemy of calm.
The reframe that helped: every service I add is something I now have to back up, monitor, update, and eventually troubleshoot at the worst possible time. A service has to earn its keep against that ongoing cost, not just look interesting on a Saturday. The goal was never a maximal homelab. It was a quiet one that makes my digital defaults better. Half the skill in self-hosting is knowing when to stop adding things.
What this series is actually about
The technical thread is real, Debian to Jellyfin to Immich to Pi-hole and beyond. But the project was never really about the software. It’s about building a digital environment I chose on purpose, where the path of least resistance leads to my own library, my own photos, my own documents.
If you’re starting your own spare-laptop server, take the boring lessons first. Decide your folders, set up DNS and backups early, keep your conventions consistent, and add services slowly. Do that, and the fun parts get to stay fun, because the foundation underneath them is calm. That’s the point, and it’s why this old laptop is still humming in the corner, still picking up the occasional new service.
I’ll keep adding to this list as the build grows. Each new part teaches me something I’d have wanted to know earlier, so this checkpoint is meant to be revisited, not closed. For the full map of how it fits together, the series index collects every part in order.