Your Home Server Can Have a Production Networking Stack

Series: You Don’t Need a VPC | Post 1 of 5


You have a PC lying around doing nothing? Use it. An old laptop? Even better — that’s basically a PC with a built-in UPS now.

When I left India in 2021 I sold all my belongings including my 1080 Ti (big mistake in retrospect). I ended up buying a cute little Dell 8940 just so I had a graphics card (1660 Super). After a quick cpu cooler upgrade, that machine ended up being a very capable server and has been running 24 containers without any hiccups ever since.

Thesis: A Cloudflare Tunnel + nginx-proxy + rootless Podman stack gives you everything a VPC buys you — private routing, SSL, access control, secrets — for ~$0/month on hardware you already own.


What a VPC Actually Gives You

When people reach for AWS, they’re often really reaching for:

  • Private networking — services that talk to each other but aren’t exposed to the internet
  • SSL termination — HTTPS without managing certs manually
  • Access control — only certain users/IPs can reach certain services
  • Load balancing / service discovery — traffic gets routed to the right container
  • Secrets management — no hardcoded credentials

Every single one of these has a home equivalent. This series covers how to build it.


The Two-Path Model

This stack uses two distinct access paths that share the same nginx backend:

Public:  User → Cloudflare Edge → Tunnel → nginx-proxy → service
LAN:     User → Router:8080 → nginx-proxy:80 → service

Public path (Cloudflare Tunnel): For services you want accessible from anywhere. Free SSL, DDoS protection, no port forwarding needed.

LAN path (direct UPnP): For services that only need to be reachable at home. Lower latency, no SSL overhead, no Cloudflare dependency.

Services don’t know or care which path was used — they just see requests from nginx.


Zero-Config Service Discovery with nginx-proxy + docker-gen

A single line of config needed to put up a new website on a new subdomain. Wild-card domains are amazing! This will generate all the nginx vhost config for you.

environment:
  - VIRTUAL_HOST=myservice.mukulhase.com

docker-gen watches the Podman socket, detects container starts/stops, and regenerates nginx config from a Go template. New service up in seconds, no manual config.


The Exception: LiveKit TURN

Not everything can go through Cloudflare. WebRTC TURN servers need UDP traffic on port 3478, which Cloudflare Tunnel doesn’t support. That service gets a direct DNS record (DNS-only, not proxied) pointing to the home IP via DDNS.

This is the main real-world constraint of the tunnel approach — pure TCP/HTTP services work perfectly, but anything needing raw UDP needs a different path.


What’s Coming in This Series

  • Post 2: Cloudflare Tunnel setup and Terraform-managed DNS
  • Post 3: Rootless Podman + SELinux on Fedora
  • Post 4: Secrets management with 1Password CLI
  • Post 5: OAuth2 in front of everything, for free