Serve /api/ws without Basic auth so the live feed connects
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.
This commit is contained in:
1 parent
97fbd5901e
commit
3e19612cc0
7 files changed
+101
-4
No files matched your search
+14
-1
@@ -8,7 +8,10 @@ server {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
# WebSocket feed. Kept in its own block so the upgrade headers are only set
|
||||
# here, and so the API token is injected server-side on the handshake (the
|
||||
# browser cannot set headers on a WebSocket).
|
||||
location /api/ws {
|
||||
proxy_pass http://backend:8000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
@@ -16,6 +19,16 @@ server {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_send_timeout 3600s;
|
||||
proxy_set_header ${API_TOKEN_HEADER} "${API_TOKEN}";
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://backend:8000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 3600s;
|
||||
# Inject the optional API token server-side so the browser never sees it
|
||||
# and the WebUI keeps working without any client changes.
|
||||
proxy_set_header ${API_TOKEN_HEADER} "${API_TOKEN}";
|
||||
|
||||
+18
-3
@@ -25,17 +25,32 @@ export const deletePreset = (id) => http.delete(`/presets/${id}`).then((r) => r.
|
||||
|
||||
export function openSocket({ onMessage, onOpen, onClose }) {
|
||||
const proto = window.location.protocol === 'https:' ? 'wss' : 'ws'
|
||||
const url = `${proto}://${window.location.host}/api/ws`
|
||||
let socket
|
||||
let retryTimer
|
||||
let closed = false
|
||||
let attempt = 0
|
||||
|
||||
const schedule = () => {
|
||||
if (closed) return
|
||||
// Back off from 2s up to 30s so a persistently failing socket (e.g. auth)
|
||||
// does not hammer the server, while a brief blip still reconnects fast.
|
||||
const delay = Math.min(2000 * 2 ** attempt, 30000)
|
||||
attempt += 1
|
||||
retryTimer = setTimeout(connect, delay)
|
||||
}
|
||||
|
||||
const connect = () => {
|
||||
socket = new WebSocket(`${proto}://${window.location.host}/api/ws`)
|
||||
socket.onopen = () => onOpen?.()
|
||||
if (closed) return
|
||||
socket = new WebSocket(url)
|
||||
socket.onopen = () => {
|
||||
attempt = 0
|
||||
onOpen?.()
|
||||
}
|
||||
socket.onmessage = (event) => onMessage?.(JSON.parse(event.data))
|
||||
socket.onclose = () => {
|
||||
onClose?.()
|
||||
if (!closed) retryTimer = setTimeout(connect, 2000)
|
||||
schedule()
|
||||
}
|
||||
socket.onerror = () => socket.close()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user