Skip to content

Reverse Proxy and Subfolder Deployment

bifrost0x edited this page Aug 14, 2026 · 1 revision

Reverse Proxy and Subfolder Deployment

WebSSH uses regular HTTP routes plus Socket.IO/WebSocket traffic. A reverse proxy must preserve the public origin and support connection upgrades.

Required application settings

For one trusted proxy layer:

CORS_ORIGINS=https://ssh.example.com
SESSION_COOKIE_SECURE=true
TRUSTED_PROXIES=1

TRUSTED_PROXIES is the number of trusted forwarding layers, not a Boolean. Keep the WebSSH backend reachable only through those layers.

nginx at the domain root

location / {
    proxy_pass http://webssh:5000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Traefik at the domain root

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.webssh.rule=Host(`ssh.example.com`)"
  - "traefik.http.routers.webssh.tls.certresolver=letsencrypt"
  - "traefik.http.services.webssh.loadbalancer.server.port=5000"

Caddy at the domain root

ssh.example.com {
    reverse_proxy webssh:5000
}

Serve WebSSH under a path prefix

For a public URL such as https://server.example.com/webssh, configure:

APPLICATION_ROOT=/webssh
TRUSTED_PROXIES=1
CORS_ORIGINS=https://server.example.com
SESSION_COOKIE_SECURE=true

The reverse proxy must strip /webssh before forwarding the request and send the original prefix as X-Forwarded-Prefix.

nginx subfolder

location /webssh/ {
    proxy_pass http://webssh:5000/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Prefix /webssh;
}

The trailing slash in both location and proxy_pass is intentional.

Traefik subfolder

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.webssh.rule=Host(`server.example.com`) && PathPrefix(`/webssh`)"
  - "traefik.http.middlewares.webssh-strip.stripprefix.prefixes=/webssh"
  - "traefik.http.middlewares.webssh-prefix.headers.customrequestheaders.X-Forwarded-Prefix=/webssh"
  - "traefik.http.routers.webssh.middlewares=webssh-strip,webssh-prefix"
  - "traefik.http.services.webssh.loadbalancer.server.port=5000"

Caddy subfolder

server.example.com {
    handle_path /webssh/* {
        reverse_proxy webssh:5000 {
            header_up X-Forwarded-Prefix /webssh
        }
    }
}

Containerized proxy

When the proxy runs in Docker:

  1. Attach WebSSH and the proxy to a private shared network.
  2. Remove public port publishing from WebSSH.
  3. Proxy to webssh:5000 over the private network.
  4. Set TRUSTED_PROXIES to the real number of trusted layers.

Do not publish 5000:5000 in parallel with the HTTPS proxy. That would allow clients to bypass TLS and possibly the trusted-proxy boundary.

WebSocket symptoms

If login works but terminal activity disconnects or never starts:

  • confirm HTTP/1.1 on the upstream connection;
  • confirm Upgrade and Connection forwarding;
  • inspect browser network requests to /socket.io/;
  • check that the proxy timeout accommodates long-lived connections;
  • verify that the prefix is applied consistently for both HTTP and Socket.IO;
  • verify CORS_ORIGINS exactly matches the browser-visible origin, including the scheme and non-default port.

Trusted client addresses

WebSSH uses forwarded addresses only within the configured proxy trust depth. An incorrect value can either record the proxy address instead of the client or trust attacker-supplied forwarding headers. Prefer a simple topology and keep the backend network private.

Validation

curl -I https://ssh.example.com/
curl -fsS https://ssh.example.com/health
curl -fsS https://ssh.example.com/ready

For a subfolder:

curl -I https://server.example.com/webssh/
curl -fsS https://server.example.com/webssh/health
curl -fsS https://server.example.com/webssh/ready

Complete the check in a browser by logging in, opening a terminal, resizing it, and transferring a small file.

Clone this wiki locally