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.comdocker-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