WebSocket Pass-Through¶
VibeWarden proxies WebSocket connections transparently. No configuration is required — it just works.
How it works¶
Caddy, the embedded reverse proxy, handles the HTTP Upgrade mechanism
automatically. When a client sends an HTTP request with:
Caddy forwards the upgrade handshake to the upstream application and then bridges the resulting TCP connection bi-directionally. VibeWarden does not inspect or buffer individual WebSocket frames.
Security checks on the upgrade request¶
All security checks run on the initial HTTP upgrade request — the standard
HTTP GET that initiates the handshake. Once the connection is established,
the raw TCP stream is forwarded unchanged.
Authentication¶
Auth is enforced on the upgrade request using the same mechanism as any other request:
- Kratos mode: the
ory_kratos_sessioncookie must be present and valid. - JWT mode:
Authorization: Bearer <token>must be present and pass JWKS validation. - API key mode: the configured key header (default:
X-API-Key) must contain a valid key.
If the upgrade request fails auth, VibeWarden returns 401 Unauthorized and
the WebSocket connection is never opened. The upstream application never sees
the request.
Rate limiting¶
Rate limiting applies to the upgrade request, not to individual WebSocket frames. Each new WebSocket connection consumes one token from the per-IP and per-user buckets. Messages sent over an already-established connection are not counted.
This means a client that sends many messages over a single WebSocket connection will not be rate limited on those messages. Rate limiting remains effective at preventing a flood of new connection attempts.
Timeouts¶
HTTP request timeouts configured in VibeWarden do not apply to established WebSocket connections. Caddy keeps the connection alive until either side closes it or a network error occurs. Your application controls the connection lifetime.
The read/write timeout applies only to the upgrade handshake itself (the initial HTTP round-trip). If your app needs idle timeouts on WebSocket connections, implement them in the application layer (e.g. send periodic pings and close on missed pongs).
Example config¶
No special configuration is needed. A standard reverse-proxy setup works:
upstream:
url: "http://localhost:3000"
plugins:
rate-limiting:
enabled: true
user-management:
enabled: true
With the config above, WebSocket connections to VibeWarden are automatically
proxied to http://localhost:3000. The upgrade handshake is authenticated and
rate-limited; individual frames are not.
Structured log events¶
The upgrade request is logged like any other HTTP request
(event_type: request.proxied). There is no separate event type for
WebSocket frame activity because frames are not inspected.
A failed upgrade due to auth is logged as event_type: auth.denied.
A failed upgrade due to rate limiting is logged as
event_type: rate_limit.blocked.
Summary¶
| Concern | Behaviour |
|---|---|
| Upgrade handshake | Caddy handles Connection: Upgrade automatically |
| Authentication | Checked on the upgrade request; deny = 401, connection never opened |
| Rate limiting | One token consumed per new connection, not per frame |
| Timeouts | Not applied to established connections; only to the upgrade handshake |
| Frame inspection | Not performed; Caddy bridges the raw TCP stream |
| Config changes needed | None |