My Self-Hosted Stack: Docker, Traefik, and Cloudflare
Running your own infrastructure at home sounds like a weekend project. Mine has been running continuously for four years, handling real workloads, and it’s taught me more about production systems than most enterprise projects.
Why Bother?
After 30 years in enterprise IT, I got tired of paying for SaaS tools I could self-host — and I wanted a sandbox that actually hurt if it broke. Home labs that don’t matter don’t teach you anything. Mine runs services I depend on daily: document storage, password management, monitoring dashboards, and AI inference workloads on my RTX 3090s.
The Core Stack
Docker + Docker Compose is the foundation. Every service runs in a container. I use Compose files with environment variable substitution so configs stay clean and secrets stay out of version control. The key discipline: treat containers as immutable. If you’re SSH-ing into a container to fix something, you’ve already lost.
Traefik handles reverse proxying. It integrates natively with Docker labels, so when I spin up a new container with the right labels, Traefik automatically discovers it, provisions a Let’s Encrypt certificate, and routes traffic. Zero manual Nginx config editing. Zero cert renewals to track.
The label pattern looks like this:
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`myapp.bwai.us`)"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
Cloudflare provides two things: DNS with DDoS protection, and Cloudflare Tunnels for services I don’t want to expose publicly at all. Tunnels let me reach internal services through an encrypted outbound-only connection — no open inbound ports on my router. For anything that touches the public internet, Cloudflare sits in front.
The Network Layout
I run three VLANs: trusted devices, IoT, and lab. Lab machines can reach the internet but not my trusted VLAN. IoT is fully isolated. Traefik listens on the lab VLAN, and Cloudflare Tunnels bridge specific services to the internet without poking holes in the firewall.
What Goes Wrong
Certificate renewal failures — usually DNS propagation timing. Traefik’s ACME DNS challenge needs Cloudflare API permissions scoped correctly. Lesson: scope API tokens to specific zones, not the whole account.
Container dependency ordering — services that start before their databases are ready. The fix is depends_on with condition: service_healthy and proper health checks on every database container.
Disk pressure — Docker log accumulation. Add --log-opt max-size=10m --log-opt max-file=3 or set it globally in /etc/docker/daemon.json. Found that out the hard way after a 2 AM alert.
What 24/7 Uptime Teaches You
Running your own stack with real consequences accelerates your intuition for production systems. You start caring about monitoring because you’re the one who gets paged. You learn to write Compose files that survive reboots because you’re the one who loses work when they don’t.
If you’re in enterprise IT and you don’t have a homelab, you’re leaving skill development on the table. Start with Portainer if Docker Compose feels like too much. Add Traefik when you’re ready to understand reverse proxying at the protocol level. Add Cloudflare when you want to understand edge networking.
The investment pays for itself the first time you troubleshoot a production Traefik configuration and already know exactly what to look for.