Caddyfile config for kasm websocket

1. The problem I’m having:

Hello all, I have setup caddy with cloudflare tls in order to run my internal domains, and I’m having trouble getting caddy to work with kasm workspaces.

I have defined the GUI on port 4443 in the docker compose file, and am able to access the workspaces via my fqdn (https://monolith.lan:4443).

But, when I try to use my domain, I’m having what I think is websocket issues where the Host is and the origin is Considering the domain with the port on the end is invalid, the workspace won’t load. I’ve included my Caddyfile with my attempted websocket matchers, but I’m not able to get the site to load with them.

Other than checking on the web browser, I’m not sure how to diagnose this issue.

2. Error messages and/or full log output:

Here is the docker compose logs output

caddy  | {"level":"info","ts":1689631840.8412552,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy  | {"level":"info","ts":1689631840.8455288,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//"]}
caddy  | {"level":"info","ts":1689631840.8462577,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc0002a1dc0"}
caddy  | {"level":"info","ts":1689631840.8464887,"logger":"http","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
caddy  | {"level":"info","ts":1689631840.8465333,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
caddy  | {"level":"info","ts":1689631840.8478963,"logger":"tls","msg":"cleaning storage unit","description":"FileStorage:/data/caddy"}
caddy  | {"level":"info","ts":1689631840.8478951,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
caddy  | {"level":"info","ts":1689631840.8479931,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See for details."}
caddy  | {"level":"info","ts":1689631840.8480375,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
caddy  | {"level":"info","ts":1689631840.8480716,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
caddy  | {"level":"info","ts":1689631840.8480766,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["","","","","","","","","","","","","","","","","","",""]}
caddy  | {"level":"info","ts":1689631840.8519728,"logger":"tls","msg":"finished cleaning storage units"}
caddy  | {"level":"info","ts":1689631840.8553364,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
caddy  | {"level":"info","ts":1689631840.8553464,"msg":"serving initial configuration"}

3. Caddy version:

v2.6.4 h1:2hwYqiRwk1tf3VruhMpLcYTg+11fCdr8S3jhNAdnPy8=

4. How I installed and ran Caddy:

a. System environment:

OS: Pop!_OS 22.04
Arch: amd64
local DNS: Unbound

Built using xcaddy via this dockerfile:


FROM caddy:${VERSION}-builder AS builder

RUN xcaddy build \


COPY --from=builder /usr/bin/caddy /usr/bin/caddy

b. Command:

To start caddy:

docker compose up -d

c. Service/unit/compose file:

version: "3.9"


    build: ./dockerfile-dns
    container_name: caddy
    hostname: caddy
    restart: unless-stopped
      - caddy.env
      - "80:80"
      - "443:443"
      - "443:443/udp"
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./data:/data
      - ./config:/config

d. My complete Caddy config:

$ cat caddy.env               # replace with your domain
MY_HOST_IP=redwood.lan                      # replace with your Docker host's IP address
CLOUDFLARE_API_TOKEN=<api-token>           # add your token
kasm.{$MY_DOMAIN} {
	@websockets {
		header Connection *Upgrade*
		header Upgrade websocket
	reverse_proxy @websockets monolith.lan:4443 {
		transport http {
	tls {
		dns cloudflare {env.CLOUDFLARE_API_TOKEN}

It doesn’t make sense to use a request matcher here. Matchers are for when you want to separate the traffic in some way to route things based on a condition (e.g. proxy websockets to one server, and proxy regular HTTP to another server).

With this config, only websocket requests will make it to your upstream, and not regular HTTP traffic, and you’ll get an empty 200 status response for regular HTTP traffic.

Change it to simply this, to allow all traffic including HTTP and websockets to be proxied.

reverse_proxy monolith.lan:4443 {
	transport http {

Thank you for the response! That is actually how I had it initially, but your proposed configuration makes the host in the websocket.

I’m wondering if this is actually an issue with my kasm configuration.

The answer was indeed in the kasm configuration. you need to set the proxy port to 0 in the zone settings per: Reverse Proxy — Kasm 1.13.1 documentation

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.