UniFi OS behind Caddy 2.11 - fixing the permanent loading bar
I proxy my UCG Max through Caddy on a small Ubuntu VM. The login page loaded fine; after signing in, the UI sat on a permanent loading bar.
GET / returns 200, so this does not look like DNS or TLS. The failure is WebSockets: devtools and Caddy logs show /api/users/self → 200 but /api/ws/system → 500.
Cause
From Caddy 2.11, reverse_proxy to an HTTPS upstream sets Host to {upstream_hostport} (e.g. 192.168.1.1:443) instead of the client hostname. UniFi OS nginx accepts the initial page but rejects WebSocket upgrades. See Caddy community thread.
Fix
@unifi host unifi.home.aioue.net
handle @unifi {
reverse_proxy https://192.168.1.1:443 {
transport http {
tls_insecure_skip_verify
versions 1.1
}
flush_interval -1
header_up Origin ""
header_up -Referer
header_up Host {hostport}
}
}
Key points:
header_up Host {hostport}- passunifi.example.com, not the gateway IPheader_up Origin ""- UniFi rejects proxied Origin on WebSocket upgradeversions 1.1- WebSocket upgrade needs HTTP/1.1 upstream- Do not add
header_up Connection/header_up Upgrade- Caddy handles upgrades automatically; those lines caused502withinvalid Upgrade request header: ["{>Upgrade}"]
After deploy, systemctl restart caddy if reload leaves stale config in memory. Success looks like 101 Switching Protocols on /api/ws/system in the browser.
Verify
curl -sk -o /dev/null -w "%{http_code}\n" https://unifi.home.aioue.net/
# WebSocket without auth should be 401, not 502/500:
curl -sk -o /dev/null -w "%{http_code}\n" \
-H "Upgrade: websocket" -H "Connection: Upgrade" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
https://unifi.home.aioue.net/api/ws/system
References: caddy#7454, reverse_proxy docs