The dashboard showed "reconnecting": browsers don't reliably replay Basic-auth credentials on a WebSocket upgrade, so /api/ws was 401'd by Traefik and silently retried forever (only the 5s REST poll kept the UI current).
Fix
/api/ws gets its own higher-priority Traefik router without Basic auth.
The WS is still gated by API_TOKEN (nginx injects it on the handshake; backend also accepts ?token=).
Deploy fails closed unless CRYPTO_API_TOKEN is set.
nginx /api/ws block split out so upgrade headers are only set there.
## Problem
The dashboard showed **"reconnecting"**: browsers don't reliably replay Basic-auth credentials on a WebSocket upgrade, so `/api/ws` was 401'd by Traefik and silently retried forever (only the 5s REST poll kept the UI current).
## Fix
- `/api/ws` gets its own higher-priority Traefik router **without** Basic auth.
- The WS is still gated by `API_TOKEN` (nginx injects it on the handshake; backend also accepts `?token=`).
- Deploy **fails closed** unless `CRYPTO_API_TOKEN` is set.
- nginx `/api/ws` block split out so upgrade headers are only set there.
- Reconnect backoff 2s → 30s.
## Testing
- Backend: 79 tests pass (3 new WS auth cases: missing/header/query token), ruff clean.
- Frontend: build + tests pass.
Browsers don't reliably replay Basic-auth credentials on a WebSocket upgrade,
so the dashboard's live feed was stuck on "reconnecting" (only the 5s REST
poll worked). Give /api/ws a higher-priority Traefik router that skips Basic
auth; the backend still requires API_TOKEN, which nginx injects on the
handshake. The deploy now fails closed unless CRYPTO_API_TOKEN is set.
Also: split the nginx /api/ws block so upgrade headers are only set there, and
add reconnect backoff (2s -> 30s) so a failing socket stops hammering.
matitos
merged commit c9ee3e3aef into main2026-09-19 15:11:18 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
The dashboard showed "reconnecting": browsers don't reliably replay Basic-auth credentials on a WebSocket upgrade, so
/api/wswas 401'd by Traefik and silently retried forever (only the 5s REST poll kept the UI current).Fix
/api/wsgets its own higher-priority Traefik router without Basic auth.API_TOKEN(nginx injects it on the handshake; backend also accepts?token=).CRYPTO_API_TOKENis set./api/wsblock split out so upgrade headers are only set there.Testing