- question: “What are the minimum specs for 24/7 Docker hosting?” answer: “2GB RAM minimum for a basic setup with 5-10 containers. 4-8GB is comfortable.”
- question: “How do I update Docker containers without downtime?” answer: “Watchtower automates updates. For manual control: pull new image, docker stop, docker rm, docker run with same arguments.”
- question: “Can I run Docker on a Raspberry Pi?” answer: “Yes. Most popular containers have ARM64 images. Performance is limited but fine for DNS filters and lightweight services.”
- question: “How do you handle container crashes?” answer: “Docker restart policies handle most failures (–restart unless-stopped). Check logs with docker logs for persistent issues.”
TL;DR
These five containers run non-stop on my homelab: AdGuard Home (DNS-level ad blocking), Nginx Proxy Manager (reverse proxy + free SSL), Uptime Kuma (real uptime monitoring), Portainer (container management), and Cloudflare Tunnel (secure external access without punching holes in my firewall). Together they cost about 15W idle and have saved me countless hours of manual work.
Why This List Matters
Not every container is worth running 24/7. Some tools you use once, configure once, and never touch again. The containers on this list are different - they’re infrastructure. They earn their keep every single day by doing jobs that would otherwise require constant attention or expose me to security risks.
All of these run on a single Intel NUC with 16GB RAM. Idle power draw is around 15W for the whole stack.
1. AdGuard Home - DNS-Level Ad Blocking
Why I Run It
AdGuard Home blocks ads and trackers at the DNS level, which means it works for every device on my network without needing client-side software. My TV, my phones, my IoT devices - all get ad blocking without any configuration on the devices themselves.
What Makes It Worth It
- Blocks 15-20% of DNS queries on average (that’s CPU and data you didn’t pay for)
- Custom blocklists beyond the defaults - I block known telemetry domains
- Per-device filtering - my gaming machines get different rules than my work machines
- Query logs let me see what every device on my network is actually connecting to
The Setup
services:
adguard:
image: adguard/adguardhome:latest
container_name: adguard
ports:
- "53:53/tcp"
- "53:53/udp"
- "853:853/tcp" # DoT
- "3000:3000/tcp" # Admin UI
volumes:
- ./work:/opt/adguardhome/work
- ./conf:/opt/adguardhome/conf
restart: unless-stopped
network_mode: host
The network_mode: host is important - DNS needs to intercept traffic, and host networking bypasses Docker’s internal DNS which would break filtering.
What I’d Tell Someone Starting Fresh
Start with the default blocklists, then add https://big.oisd.nl after a week. It’s a massive consolidated list that catches most things the default lists miss. Don’t go overboard with lists early - you want to be able to debug when something breaks.
2. Nginx Proxy Manager - Reverse Proxy with Free SSL
Why I Run It
Every service I expose externally goes through Nginx Proxy Manager. It handles SSL certificates automatically via Let’s Encrypt, and the web UI makes managing forwardings much less painful than editing nginx configs by hand.
What Makes It Worth It
- Wildcard SSL certificates with DNS challenge (Cloudflare API integration)
- Access lists for internal-only vs public services
- One-click SSL renewal
- Fail2ban built in for brute-force protection
- Dead simple to add a new service
The Setup
I run it alongside AdGuard because both want port 80/443. Traffic flows: Internet → Router → AdGuard (DNS filter) → Nginx Proxy Manager → Internal Services.
nginx-proxy-manager:
image: jlesage/nginx-proxy-manager:latest
container_name: npm
ports:
- "80:8080"
- "443:8443"
- "81:81" # Admin UI
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
restart: unless-stopped
The Caveat
Nginx Proxy Manager is great until you need something complex. If you need WebSocket support, advanced routing, or request buffering tuning, you’ll still end up editing nginx templates. For 90% of homelab setups though, it’s perfect.
3. Uptime Kuma - Real Uptime Monitoring
Why I Run It
Uptime Kuma tells me when something is down before whoever’s using it tells me. That email at 2am from a user saying “your thing is broken” becomes a notification that I got 15 minutes earlier.
What Makes It Worth It
- 404 monitoring catches more than just “is it up” - it catches broken redirects, missing SSL certs, SSL expiry
- Push monitors let me run health checks from inside containers themselves
- Status pages are shareable - I give these to non-technical people instead of teaching them to read monitoring dashboards
- Notification integrations: Gotify, email, webhooks, Telegram - I route critical alerts to Telegram
The Setup
uptime-kuma:
image: louiscklaw/react-uptime-kuma:latest
container_name: uptime-kuma
ports:
- "3001:3001"
volumes:
- ./uptime-kuma-data:/app/data
restart: unless-stopped
The Tip
Don’t just monitor HTTP - add keyword monitoring. Set it to check that the response contains something specific. A 200 OK with a broken app still looks up to naive monitoring.
4. Portainer - Container Management
Why I Run It
Portainer gives me a GUI for Docker without being as heavy as Kubernetes. I use it for:
- Starting/stopping containers without CLI
- Viewing logs in real-time (grep through logs in the browser is surprisingly useful)
- Quick volume inspection
- Network visualization
What Makes It Worth It
The real value is for the 5% of tasks that are annoying in CLI. Viewing a container’s resource usage visually, dragging to fix a bad compose stack, quickly checking “what environment variables does this thing actually have?” These add up.
The Setup
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
ports:
- "9000:9000"
- "9443:9443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
restart: unless-stopped
The Warning
Portainer has had CVEs. Don’t expose it externally, and keep it updated. I run it on an isolated network segment with no external exposure.
5. Cloudflare Tunnel - External Access Without Port Forwarding
Why I Run It
Cloudflare Tunnel lets me expose services to the internet without opening any ports on my router. No port forwarding, no dynamic DNS, no “my IP changed and now nothing works.” Traffic goes through Cloudflare’s edge, which also means DDoS protection and free TLS.
What Makes It Worth It
- Zero infrastructure exposure - my home IP isn’t directly reachable
- Automatic TLS
- Works great with Nginx Proxy Manager internally
- Tunnel keeps reconnecting automatically even after network hiccups
- Can share access to specific URLs without giving full network access
The Setup
cloudflare-tunnel:
image: cloudflare/cloudflared:latest
container_name: cloudflare-tunnel
restart: unless-stopped
command: tunnel run --token YOUR_TUNNEL_TOKEN
The Catch
Your traffic goes through Cloudflare. For personal homelab use this is fine. For enterprise or privacy-maximizing setups, you might want a different approach.
Comparison Table
| Container | RAM Usage (Idle) | CPU Usage (Idle) | Power Draw | Complexity |
|---|---|---|---|---|
| AdGuard Home | ~150MB | 1-2% | Minimal | Low |
| Nginx Proxy Manager | ~50MB | 1% | Negligible | Low |
| Uptime Kuma | ~200MB | 2-3% | Minimal | Medium |
| Portainer | ~300MB | 2% | Minimal | Low |
| Cloudflare Tunnel | ~80MB | 1% | Negligible | Medium |
Key Takeaways
- AdGuard Home is the first thing I’d install - DNS-level blocking benefits every device
- Nginx Proxy Manager + Cloudflare Tunnel together give you free SSL and external access without router configuration
- Uptime Kuma pays off in early problem detection - the 5 minutes you save multiplied across a year
- Portainer is optional but nice to have for the visual sanity check
All of these run on under 1GB RAM combined and add maybe 5W to your power bill. For the automation and security they provide, that’s a bargain.