“It’s also a financial blackhole.”
Let’s Build a Homelab
Welcome to this caffeine-infused, late-night-inspired, and Ethernet-tangled edition of “We Got AWS at Home.” Today, we’re diving deep into the chaotic, glorious world of homelabbing; a place where enterprise tech collides with domestic clutter and your workspace slowly morphs into a blinking, whirring server closet with commitment issues.
Forget hyperscalers. Forget cloud bills that look suspiciously like your student loans. This is the real cloud or at least the foggy, blinking approximation of it; built from salvaged hardware, RGB-lit dreams, and whatever you managed to wrestle off OLX and Facebook Marketplace.
Here, you are the architect, the sysadmin, the network engineer, the DevOps team, and yes; the janitor. It’s like AWS, but with more personality, more zip ties, and a far greater chance of electrocuting yourself if you unplug the wrong thing.
Every DNS misfire, every 2AM iptables meltdown, every Raspberry Pi melting under a tower of switches; it’s all part of the sacred rite. You’ll curse at YAML. You’ll question your life choices. You’ll give your NAS a name and possibly talk to it when things go wrong.
But through the chaos, you’ll learn infrastructure no Udemy course could ever teach.
What Is a Homelab, Anyway?
A homelab is your personal tech space to learn, break, fix, and repeat until mastery (or burnout). It’s a miniature cloud on your desk, a playground where you’re free to deploy and destroy at will; no permissions, no approval tickets, no one from IT asking “why is this in prod?”
Your setup might be an ancient Dell server wheezing through its last uptime, or a lovingly zip-tied cluster of Raspberry Pis humming beneath your desk. Maybe it’s all running on a dusty ThinkPad rescued from the recycling bin. Regardless of the hardware, the goal is the same: learn by doing.
You’ll self-host tools, orchestrate networks, experiment with services, and possibly discover a love-hate relationship with YAML. This is hands-on infrastructure. It’s your testing ground, your resume builder, and your chaos lab.
Why Even Bother with a Homelab?
Sure, you could spin up a VPS or wring every last drop from some free-tier cloud credits. But where’s the drama in that? There’s a unique, almost primal satisfaction in hearing a hard drive clunk to life under your desk while you stare into the void of a docker-compose.yml written by your sleep-deprived past self.
Homelabs deliver:
-
Total control: No telemetry. No nagging EULAs. No data siphoned off to parts unknown. Just you and your stack. You’re not beholden to some faceless SaaS platform that might decide to go paywalled next quarter. Everything lives and dies on your terms, in your home, powered by your chaotic energy.
-
Safe chaos: Want to delete /etc in the name of science? Go nuts. (Just… maybe inside a container, yeah?) The homelab gives you a sandbox where breaking things is expected—and honestly encouraged. It’s the kind of environment where failure teaches more than success ever could, and “oops” moments become case studies.
-
Hard-won knowledge: From Docker to DNS, firewalls to filesystem hell—this is learning the hard, glorious way. You’re not just following tutorials, you’re troubleshooting in real time, untangling logs at 1AM, and slowly becoming the kind of person who knows why things break, not just how to fix them.
And let’s not forget the community. Online spaces like r/selfhosted are goldmines of advice, encouragement, and shared failures. You’re not alone in this madness.
Laying the Groundwork
Before your network resembles a bowl of spaghetti:
- Install Docker and Docker Compose. Seriously.
- Learn your networking: NAT, VLANs, DNS, TLS, and ports beyond 80 and 443.
- Hardware tips: A 6th-gen Intel CPU, 16GB RAM, and an SSD will serve you well.
- Claim a free DuckDNS domain. It’ll save you a headache later.
- Get a post-it notes. Label your cables. Label everything.
Planning saves you from future migraines—and possibly an accidental self-DDoS.
Hardware: Choosing Your Warhorse
Start humble. You don’t need a server that sounds like a jet engine.
My top picks:
- Lenovo ThinkCentre
- HP EliteDesk
- Dell OptiPlex
All are small, quiet, and affordable workhorses. Toss in 16GB of RAM and an SSD. For the OS, Ubuntu Server is a great balance of usability and power. Want to suffer for speed? Try Alpine Linux; it’s tiny, fast, and has zero fluff—but beware, you’ll be compiling more than you’re used to.
Then, install Docker and Docker Compose. These will become your most-used tools.
What’s Docker
Docker wraps your app into a neat little container. It runs anywhere, fails fast, and cleans up nicely.
Why Docker?
- Portability: Move containers between machines with ease.
- Isolation: Keep apps from stomping on each other.
- Reproducibility: Build, break, rebuild. All from a YAML file.
Hot tip: Avoid :latest
like the plague. Pin your versions.
The Core Stack: Your Starter Services
⚠️ Heads up: This guide is opinionated. It’s one way to do things; not the way. There are many valid paths in the homelab rabbit hole. Consider this a launchpad, not a checklist. The following is a hand-picked homelab starter pack: compact, powerful, and beautifully chaotic.
Also; these configs work, but the goal isn’t just to copy/paste. Read, tweak, break, fix. That’s how you’re actually supposed to learn
AdGuard Home
DNS-level ad blocker. Keeps your devices tracker-free.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
services:
adguard:
image: adguard/adguardhome # The official AdGuard Home image from Docker Hub
container_name: adguard # Name of the running container (makes CLI management easier)
restart: unless-stopped # Ensures the container restarts on reboot unless manually stopped
ports:
- "53:53/tcp" # DNS over TCP (standard DNS port)
- "53:53/udp" # DNS over UDP (used by most DNS queries)
- "8080:80" # Maps container's HTTP port 80 to host port 8080 (web UI)
- "3000:3000" # AdGuard setup wizard and optional second admin port
- "8443:443" # HTTPS port mapped to 8443 to avoid conflicts with other services
volumes:
- ./conf:/opt/adguardhome/conf # Persistent config files live here (whitelists, settings, etc.)
- ./work:/opt/adguardhome/work # Internal runtime data (query logs, temporary state)
networks:
- homelab # Puts AdGuard on the custom 'homelab' Docker network
networks:
homelab:
external: true # Uses a pre-existing Docker network so services can talk to each other
Portainer
Docker with a GUI. Great for visual learners or those afraid of CLI typos.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
services:
portainer:
image: portainer/portainer-ce # Community Edition image for Portainer – a Docker UI dashboard
container_name: portainer # Easy to reference in CLI
restart: unless-stopped # Auto-starts unless manually stopped
ports:
- "9000:9000" # Web UI port (http://localhost:9000)
volumes:
- /var/run/docker.sock:/var/run/docker.sock # Mounts Docker socket to let Portainer manage the host's containers
- portainer_data:/data # Persists settings and user data
networks:
- homelab # Same custom network for inter-container communication
networks:
homelab:
external: true # Assumes the homelab network is already defined outside this file
Vaultwarden
Self-hosted Bitwarden alternative. Elegant, secure, and lightweight.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
services:
vaultwarden:
image: vaultwarden/server # Lightweight, self-hosted Bitwarden-compatible password manager
container_name: vaultwarden # Named for easy reference
ports:
- "8081:80" # Maps internal HTTP port to 8081 externally (so it won't clash with others)
volumes:
- vaultwarden_data:/data # Persists user vaults, config, and encryption keys
networks:
- homelab
networks:
homelab:
external: true
Use HTTPS. Protect your secrets. Vaultwarden won’t even open without HTTPS—because password managers handle your keys to your kingdom. Vaultwarden encrypts everything server-side using Argon2 and strong hashing—you don’t want that exposed over plain HTTP.
Filebrowser
Slick, web-based file management. Makes FTP feel prehistoric.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
services:
filebrowser:
image: filebrowser/filebrowser # The official lightweight image for the web-based file manager
container_name: filebrowser # Container name for identification
user: "1000:1000" # Runs as a specific UID:GID — matches the host user to avoid permission hell
volumes:
- /your/files:/srv # This is the folder you'll browse via the UI
- filebrowser_config:/config # Stores settings, user database, and UI preferences
ports:
- "8082:80" # Exposes Filebrowser on port 8082 externally (internally still port 80)
networks:
- homelab
networks:
homelab:
external: true
Nginx Proxy Manager (NPM)
Easy reverse proxy with SSL support. Pretty UI, powerful backend.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
services:
npm:
image: jc21/nginx-proxy-manager:latest # Official image for NPM with GUI support
container_name: npm # Named "npm" because typing "nginxproxymanager" every time is a crime
restart: unless-stopped # Auto-restarts unless manually stopped
ports:
- "80:80" # HTTP — standard web traffic
- "443:443" # HTTPS — secure web traffic
- "81:81" # NPM admin dashboard UI (because port 80 is already taken)
volumes:
- npm_data:/data # Stores config: proxy hosts, settings, credentials
- npm_letsencrypt:/etc/letsencrypt # Houses SSL certs from Let's Encrypt
networks:
- homelab
networks:
homelab:
external: true
The homelab network
You might’ve noticed all services are joined to a custom docker network called homelab. Here’s why:
-
Custom networks enable clean container-to-container communication by name. So instead of figuring out IPs, you can just connect to vaultwarden:80, adguard:3000, etc., via DNS
-
It isolates your stack from Docker’s default bridge network, which is a bit… messy if you’re running multiple stacks or doing port mappings across projects.
-
external: true means we’re telling Docker Compose not to manage this network—it should already exist. This way, multiple compose files can plug into the same network without redefining it, keeping things modular and sane.
If you’re running all services in one file, Docker Compose can also create the network for you without external: true. But when you split things up (which you eventually will), defining a shared external network keeps your stack scalable and clean.
Let’s Encrypt + DuckDNS
Free SSL, because browsers shouldn’t yell at you.
- Register at duckdns.org.
- Add domain in NPM.
- Select DNS Challenge > DuckDNS.
- Paste in your DuckDNS token.
- Turn on HSTS, HTTP/2, and force SSL.
Boom. Trusted encryption.
TL;DR
We’ve setup :
- AdGuard Home for DNS-level filtering
- Portainer for Docker management
- Vaultwarden to safeguard your passwords
- Filebrowser for sleek file navigation
- Nginx Proxy Manager to tie it all together
- Let’s Encrypt + DuckDNS for free, automatic SSL
It is again important to understand every project has different needs; what I’m showing here is just a baseline. Customize it to suit your workflow, your hardware, and your level of masochism.
Wrapping Up
You’ve officially taken the plunge. Cables are plugged in, containers are spinning, and your digital domain is live. Whether you’re self-hosting for privacy, learning, or just the thrill of it; this is only the beginning.
Got a better way to structure your services? Prefer Podman over Docker? Want to use systemd-nspawn or run your own DNS resolver stack? Go for it. The homelab world is wide, weird, and wonderful. This blog isn’t a rulebook—it’s just an archive
Next up? Monitoring with Prometheus and Grafana. Backups with Restic. Maybe a bit of automation magic with Ansible or a dive into home automation with Home Assistant. The rabbit hole is deep, and it’s lined with blinking LEDs.
Welcome to the homelab life. It’s educational, empowering, and just the right amount of unhinged.