There was no plan. It started as a backup drive with a Forgejo instance on it, somewhere to keep my own git repos and a copy of my files. Then I started adding more, upgrading the hardware, and seeing what else the server could do. Along the way that turned into actually learning Linux administration, Docker, firewalls, and general security, mostly by taking someone else's guide and reworking it for what I actually had. The security basics started from a Hetzner tutorial written for securing Fedora, which I adapted to openSUSE instead.
That's still how it grows. The most recent addition was Grafana,
after a couple of coworkers mentioned how difficult they'd found
it to learn, which I took as a reason to sit down and actually
give it a go. Before that it was Gentoo. I'd read through the
handbook twice, but the first install (on my laptop) still took
three attempts and about eight hours, tutorials and all. I was
expecting to use it for a month and go back to openSUSE. That was
three months ago. I've grown fond of emerge.
What follows are the four pieces of it I'd actually call engineering rather than just configuration.
Gentoo builds almost everything from source, which is powerful but slow, especially across more than one machine. Instead of every device independently spending hours compiling the same packages, one build server compiles once and the rest pull ready-to-run binaries over the network.
The interesting part isn't the building, it's the validation that happens first. A CI pipeline dry-runs every proposed change (new package, changed build flag) before anything actually gets built. It checks the change resolves cleanly, blocks anything that would touch a protected core package, and automatically reverts a change that fails validation rather than leaving the system in a broken state. Only changes that pass get queued for the next scheduled build.
Every machine on the network targets a shared baseline CPU instruction set rather than the fastest option for any single machine, which sounds like a downgrade until you realise it means a binary built once runs correctly everywhere, instead of needing a separate build per machine.
Not everything I want to run has an existing package, and some upstream projects release new versions often enough that manually repackaging each one would be its own part-time job. A small overlay handles that instead: it watches for new upstream releases, generates the packaging automatically, and pushes the change through the exact same validation pipeline as everything else.
The point isn't the specific packages, it's that packaging stops being a manual chore and becomes something the system does to itself. If a check ever finds a release that doesn't fit the expected shape, it fails loudly instead of shipping something broken.
Most of what runs here has no business being reachable from the open internet, so it isn't. Internal services sit behind a WireGuard VPN and are only reachable once connected to it; a deliberately small set of services that are meant to be public sit on a separate, more exposed layer with its own protections. Traffic that doesn't need to leave the private network never does, general browsing and internal traffic are kept apart at the routing level rather than trusted to stay separate by convention.
DNS resolution for internal services only works once you're actually on the network, so an internal hostname is meaningless to anything outside it.
A couple of services here speak open, federated protocols rather than depending on one company's platform: a Matrix homeserver, and a Fediverse (ActivityPub) instance. Both talk to independent servers the same way any other server on those networks does. Right now that's mostly a personal sandbox for understanding how federation actually behaves in practice, identity, delivery, retries, the parts that only really show up once you're running the server side and not just a client.
It's a different kind of learning than running your own CI pipeline. Federation only works if you get the boring, specific parts of a protocol right, and the only way to find out which parts those are is to actually run it.