Back to projects

09 / Infrastructure · Self-Hosting

Homelab & Self-Hosted Infrastructure

Server: special-k (HP EliteDesk Mini) OS: Ubuntu Server Status: Always on, ongoing

A single small mini PC at home, running my personal services in Docker and reachable from anywhere over a private network. It holds my own photos and documents, replaces a few subscriptions, and doubles as the place I practice building and deploying real software with AI.

The idea: own the data and understand the whole stack. Instead of renting cloud storage and stitching subscriptions together, one machine at home runs everything, and none of it is exposed to the public internet. It is equal parts a set of tools I actually use and a sandbox for learning how software gets built and kept running once it ships.

The machine

The whole lab runs on one HP EliteDesk Mini, a small-form-factor desktop picked for low idle power and a quiet fan rather than raw speed. It runs Ubuntu Server with no desktop environment, so everything is managed over SSH from the terminal.

Each service lives in its own Docker container, described in Compose files that can be torn down and brought back exactly as before. Containers keep the services isolated: one app crashing or hogging memory cannot take the others down with it, and adding something new is a matter of another config block rather than another machine.

What's running

Roughly a dozen containers run side by side. Some are well-known open-source projects; several are web apps I wrote and host here myself.

Photos, Docs & Files

Immich hosts my photo and video library in place of a cloud subscription, Paperless-ngx keeps scanned documents searchable, and Syncthing mirrors files across my laptop, desktop, and the server.

Apps I Built

A personal dashboard that pulls together my calendar, email, and coursework; a grocery and recipe tracker; and a tracker for job applications. Each is a small web app with its own database, running as its own container.

Monitoring

Uptime Kuma watches each service for outages, Beszel graphs host and container health, and a status page I wrote pulls both into one view so I can check the whole lab at a glance.

Photo of the server coming soon
special-k, the mini PC that runs the whole homelab.

Access and backups

Access runs entirely over Tailscale, a private mesh network that connects my own devices directly. Reaching a service from a laptop or phone works from anywhere, but only from a device I have added to the network, which is what keeps the lab off the public internet in the first place. A Caddy reverse proxy sits in front of the containers and gives each app a clean internal address with automatic HTTPS.

Backups run with restic to Backblaze B2, encrypted on my side before anything leaves the house, so the storage provider only ever holds ciphertext. I compared restic against Kopia before settling on it, and the backup set covers the data that would actually hurt to lose: photos, documents, and each app's database.

Built and run with AI

Most of the apps above started as a written spec, not as code. The workflow is to describe what I want in a detailed handoff document, hand that to Claude Code, then read, test, and correct what it produces. The homelab is where I practice that loop on software I rely on every day, which raises the stakes well past a throwaway demo.

That has meant learning where the agent is strong and where it needs a short leash. It moves fast, but a vague spec sends it straight into plausible code that quietly does the wrong thing, so the handoff has to pin down interfaces and failure behavior up front. Reviewing the result matters as much as writing the prompt: one deploy handed back a container that passed every health check and still served a blank page, because the generated code was rejecting the app's own requests. curl could not see the bug; a real browser could. Catching that kind of gap, and knowing to look for it, is the skill I am building here.

What I'm learning

Running this many services on one box teaches things a class project never does. Ports collide, a reverse proxy has to route traffic to the right place, a container that starts is not the same as a service that works, and a backup only counts once a restore has been tested. Most of what I know about operating software, rather than just writing it, came from breaking and fixing this setup.

Self-hosting also means the data is mine to protect. Keeping my own photos and documents instead of renting them puts the whole chain on me: encryption, off-site copies, and a plan for the day a disk dies. Getting that right is more satisfying, and more instructive, than handing it to a provider.

Underneath all of it, the lab has become steady practice with the everyday tools of the trade: Linux and the command line, Docker, networking, and Git.