The goal for the session was simple: get Home Assistant accessible from outside the network without opening ports. Added cloudflared as a Docker service in the Home Assistant compose file, configured a Cloudflare Zero Trust tunnel to route ha.n5hq.me to localhost:8123, and expected it to just work. It did not just work.
The Silent 502
The first 502 Bad Gateway was easy enough — the service URL in the Cloudflare dashboard was set to homeassistant:8123 (the container name). Since both containers run with network_mode: host, Docker's internal DNS doesn't resolve container names — that only works on bridge networks. Changed it to http://localhost:8123 and restarted.
Still 502. But this time cloudflared wasn't logging anything at all. No requests showing up, no errors, nothing. The tunnel showed connected but the logs were completely silent. That silence is what cost the most time — it looked like traffic wasn't arriving at all, and without evidence of where it was failing there wasn't much to go on. Eventually added --protocol http2 --loglevel debug to the cloudflared command. With debug logging on, the picture became clear: requests were arriving, but HA was returning 400.
The 400 Stack
Three causes, all stacked on top of each other. First, trusted_proxies was set to 172.20.0.3 — an old Docker bridge IP that was no longer valid. Second, when correcting it, typed 172.0.0.1 instead of 127.0.0.1. One wrong digit, another restart, still broken. Third, external_url wasn't set at all — Home Assistant rejects requests where the Host header doesn't match a configured external URL, so every request through ha.n5hq.me was being rejected regardless.
Fixed all three: trusted_proxies corrected to 127.0.0.1 and ::1, external_url set to https://ha.n5hq.me, HA restarted. Tunnel came up cleanly.
What's Next
- Expose Immich the same way — same cloudflared instance, second public hostname
- Consider Cloudflare Access in front of HA for authentication layer
About 1.5 hours total — almost all of it on the silent 502 before debug logging was enabled. The lesson that stuck: on a host network, you always use localhost, and debug logging should be the first thing you turn on when there's nothing to look at.