Last updated: 2026-05-31
Cloudflare Tunnel (cloudflared) exposes nine internal services to the internet without any open port forwards on the UDM. All external HTTPS traffic enters through Cloudflare's edge and is delivered to the backend via an outbound-only encrypted tunnel.
Internet
→ Cloudflare edge (SSL terminated, Bot Fight Mode, TLS 1.2+)
→ cloudflared daemon (outbound connection from LXC 101)
→ backend IP:port (plain HTTP, direct — does NOT go through NPM)
Why backends are direct, not through NPM:
NPM has Force SSL enabled on all proxy hosts, which redirects any incoming HTTP to HTTPS. Cloudflare Tunnel delivers plain HTTP to backends. If traffic went through NPM, it would get an HTTP→HTTPS redirect loop. Each tunnel route goes directly to the backend instead.
On-network access is completely separate. Pi-hole routes *.pittsfamily.me to NPM at 10.0.2.14. Cloudflare is not involved in any on-network request.
| Container | npm-cloudflared-1 — Docker in LXC 101 on proxmox2 |
| Compose | Shared with NPM in LXC 101 |
| Tunnel token | Vaultwarden → Cloudflare — Tunnel Token — pittsfamily.me |
| Dashboard | Cloudflare Zero Trust → Networks → Tunnels |
Nine services exposed externally. Each route points directly to the backend, bypassing NPM.
All public subdomains are orange-clouded (proxied). The pittsfamily.me root A record is removed.
| Setting | Value |
|---|---|
| SSL/TLS mode | Full Strict |
| Always HTTPS | On |
| Minimum TLS | 1.2 |
| Bot Fight Mode | On |
| Port forwards | None (80/443 removed from UDM) |
Two separate Cloudflare credentials in Vaultwarden:
# Is the daemon running?
ssh proxmox2 'pct exec 101 -- docker ps | grep cloudflared'
# Recent logs — config updates, connection state, backend errors:
ssh proxmox2 'pct exec 101 -- docker logs npm-cloudflared-1 --tail 50'
The tunnel config is managed in the Cloudflare dashboard. The daemon polls and applies changes without restart; each config change logs a line starting with Updated to new configuration config=.
ERR_SSL_UNRECOGNIZED_NAME_ALERT externally:
Cloudflare doesn't recognize the hostname. Verify the public hostname exists in Zero Trust → Networks → Tunnels → [tunnel] → Public Hostname tab.
502 Bad Gateway externally:
Tunnel is up but backend unreachable. Check logs: docker logs npm-cloudflared-1 --tail 20 — look for Unable to reach the origin service. Verify the backend IP:port in the tunnel route and that the backend is running.
vault.pittsfamily.me 502 (historical, 2026-05-30):
Tunnel route was set to https://10.0.2.17:443 but Vaultwarden only serves http://10.0.2.17:80. Correct route is http://10.0.2.17:80. NPM and Vaultwarden have no SSL — Cloudflare terminates TLS at the edge.
On-network clients resolving to Cloudflare IPs:
Pi-hole DNS issue, not a tunnel issue. See Pi-hole → DNS Architecture.
new-service, Domain: pittsfamily.meHTTP, URL: <backend-ip>:<port>