Skip to main content
← Back to list
01Issue
BugClosedSwamp CLITeam
AssigneesNone

Relationships

#1363 Remote --server wss:// fails through an HTTP/2 TLS reverse proxy (WS client ALPN is h2-only)

Opened by magistr · 7/23/2026

Summary

swamp <cmd> --server wss://<host> --token <name>.<secret> cannot open a WebSocket to swamp serve when serve sits behind a TLS reverse proxy that advertises HTTP/2 via ALPN (Traefik v3, and likely nginx/Caddy with http2 enabled). The client's TLS ClientHello appears to offer h2 without http/1.1, so the wss handshake either negotiates h2 — which has no WebSocket upgrade mechanism — or fails ALPN outright. Plain ws:// (no TLS) works end to end.

This is the reverse-proxy deployment that PR #1717 ("skip Host header validation on loopback bind to support reverse proxy deployments") was meant to enable: the serve side now accepts proxied requests, but the client still can't complete the wss handshake through an h2-capable TLS proxy.

Environment

  • swamp 20260722.210030.0-sha.7ff1e2f0 (both client and serve)
  • serve: swamp serve --auth-mode token --admins ... --host [IP-1] --port 9091 --trust-proxy (binds loopback)
  • proxy: Traefik v3.3 terminating TLS (Let's Encrypt cert), ALPN advertising h2 + http/1.1 on :443, forwarding to serve

Reproduction / observed

  1. Proxy ALPN = {h2, http/1.1} (Traefik default): client error -> NetworkError: failed to connect to WebSocket: stream error received: unspecific protocol error detected (an HTTP/2 stream error — the client negotiated h2)
  2. Proxy TLS option pinned to alpnProtocols=[http/1.1]: client error -> received fatal alert: NoApplicationProtocol (the client's ClientHello ALPN does NOT contain http/1.1, so there is no common protocol)
  3. curl --http1.1 performing the WS upgrade to the same URL reaches serve correctly — 401 without a token, 101/authenticated with a valid one. So the proxy and serve are both fine.
  4. Plain ws:// to serve (no TLS/ALPN, via an SSH tunnel) works end to end: a valid token authenticates and the command returns results; a bogus token returns 401.

So serve, the proxying, and token auth are all correct — only the client's wss ALPN is incompatible with an h2-capable TLS proxy.

Expected

A WebSocket client connecting over wss:// should offer http/1.1 in its TLS ALPN (WebSocket is an HTTP/1.1 Upgrade), so it interoperates with standard h2-capable TLS reverse proxies — the exact deployment #1717 enabled on the serve side.

Likely fix

In the client's wss WebSocket / TLS connection setup, set ALPN to include (or restrict to) http/1.1 for --server wss:// connections (Deno WebSocket-over-TLS / Deno.connectTls alpnProtocols).

Impact

Blocks all remote --server wss:// usage through a TLS reverse proxy — the intended production shape for a hosted serve. Current workarounds are a non-h2 TCP-passthrough entrypoint or a plain-ws tunnel. Likely the same root cause behind earlier "remote --server blocked through a proxy" reports.

02Bog Flow
OPENTRIAGEDIN PROGRESSCLOSED

Closed

7/23/2026, 10:42:52 PM

No activity in this phase yet.

03Sludge Pulse
Editable. Press Enter to edit.

shelson commented 7/23/2026, 8:39:37 AM

I've seen this behaviour too, but i didn't get it written up nearly this well - thanks!

stack72 commented 7/23/2026, 10:42:51 PM

This was the same issue as 1345 - it has been fixed by https://github.com/swamp-club/swamp/pull/1941

Sign in to post a ripple.