Skip to content

Reverse proxy

Kaio streams in two ways that a default proxy configuration breaks:

  • Server-sent events for the dashboard feed and for logs, on /api/events, /api/containers/{id}/logs and /api/stacks/{name}/logs;
  • WebSocket for the in-container shell, on /api/containers/{id}/shell.

The failure is silent. The page loads, the tables fill, and then logs never arrive and the terminal never opens.

location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 1h;
}

With this map at the http level, so that Connection is only set to upgrade for requests that ask for it:

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

proxy_buffering off is the one that matters for logs: with buffering on, nginx holds the event stream until a buffer fills, so lines arrive in bursts or not at all. proxy_read_timeout has to outlive an idle stream, otherwise a quiet container drops its log view after 60 seconds.

kaio.example.com {
reverse_proxy 127.0.0.1:8080 {
flush_interval -1
}
}

Caddy upgrades WebSocket connections on its own. flush_interval -1 disables response buffering, which is what the event streams need.

labels:
- "traefik.http.routers.kaio.rule=Host(`kaio.example.com`)"
- "traefik.http.services.kaio.loadbalancer.server.port=8080"
- "traefik.http.services.kaio.loadbalancer.responseforwarding.flushinterval=-1"

Traefik handles the WebSocket upgrade itself. flushinterval=-1 flushes immediately, again for the event streams.

The application has none. A proxy is the natural place to put it, and the reason the port should not be reachable without one. See Security.

auth_basic "Kaio";
auth_basic_user_file /etc/nginx/.htpasswd;

Basic auth is the floor, not the goal. Anything that terminates a session works, as long as the port itself is never exposed directly.

Terminal window
curl -N -H "Accept: text/event-stream" https://kaio.example.com/api/events

Events should appear as they happen. If the command hangs with nothing, or if lines arrive in blocks after a delay, response buffering is still on somewhere.

Kaio, built by Régis Gaidot