From 6a54f1f66ce6a760a605c40d07d7ff2deec3898d Mon Sep 17 00:00:00 2001
From: Corey <corey@coreyalan.me>
Date: Wed, 28 May 2025 04:46:04 -0500
Subject: [PATCH] Add WebSocket guide

---
 docs/content/user-guides/websocket.md | 355 ++++++++++++++++++++++++++
 docs/mkdocs.yml                       |   1 +
 2 files changed, 356 insertions(+)
 create mode 100644 docs/content/user-guides/websocket.md

diff --git a/docs/content/user-guides/websocket.md b/docs/content/user-guides/websocket.md
new file mode 100644
index 000000000..cb122d90f
--- /dev/null
+++ b/docs/content/user-guides/websocket.md
@@ -0,0 +1,355 @@
+---
+title: "Traefik WebSocket Documentation"
+description: "How to configure WebSocket and WebSocket Secure (WSS) connections with Traefik Proxy."
+---
+
+# WebSocket
+
+Configuring Traefik to handle WebSocket and WebSocket Secure (WSS) connections.
+{: .subtitle }
+
+## Overview
+
+WebSocket is a communication protocol that provides full-duplex communication channels over a single TCP connection.
+WebSocket Secure (WSS) is the encrypted version of WebSocket, using TLS/SSL encryption.
+
+Traefik supports WebSocket and WebSocket Secure (WSS) out of the box. This guide will walk through examples of how to configure Traefik for different WebSocket scenarios.
+
+## Basic WebSocket Configuration
+
+A basic WebSocket configuration only requires defining a router and a service that points to your WebSocket server.
+
+```yaml tab="Docker & Swarm"
+labels:
+  - "traefik.http.routers.my-websocket.rule=Host(`ws.example.com`)"
+  - "traefik.http.routers.my-websocket.service=my-websocket-service"
+  - "traefik.http.services.my-websocket-service.loadbalancer.server.port=8000"
+```
+
+```yaml tab="Kubernetes"
+apiVersion: traefik.io/v1alpha1
+kind: IngressRoute
+metadata:
+  name: my-websocket-route
+spec:
+  entryPoints:
+    - web
+  routes:
+    - match: Host(`ws.example.com`)
+      kind: Rule
+      services:
+        - name: my-websocket-service
+          port: 8000
+```
+
+```yaml tab="File (YAML)"
+http:
+  routers:
+    my-websocket:
+      rule: "Host(`ws.example.com`)"
+      service: my-websocket-service
+  
+  services:
+    my-websocket-service:
+      loadBalancer:
+        servers:
+          - url: "http://my-websocket-server:8000"
+```
+
+```toml tab="File (TOML)"
+[http.routers]
+  [http.routers.my-websocket]
+    rule = "Host(`ws.example.com`)"
+    service = "my-websocket-service"
+
+[http.services]
+  [http.services.my-websocket-service]
+    [http.services.my-websocket-service.loadBalancer]
+      [[http.services.my-websocket-service.loadBalancer.servers]]
+        url = "http://my-websocket-server:8000"
+```
+
+## WebSocket Secure (WSS) Configuration
+
+WebSocket Secure (WSS) requires TLS configuration.
+The client connects using the `wss://` protocol instead of `ws://`.
+
+```yaml tab="Docker & Swarm"
+labels:
+  - "traefik.http.routers.my-websocket-secure.rule=Host(`wss.example.com`)"
+  - "traefik.http.routers.my-websocket-secure.service=my-websocket-service"
+  - "traefik.http.routers.my-websocket-secure.tls=true"
+  - "traefik.http.services.my-websocket-service.loadbalancer.server.port=8000"
+```
+
+```yaml tab="Kubernetes"
+apiVersion: traefik.io/v1alpha1
+kind: IngressRoute
+metadata:
+  name: my-websocket-secure-route
+spec:
+  entryPoints:
+    - websecure
+  routes:
+    - match: Host(`wss.example.com`)
+      kind: Rule
+      services:
+        - name: my-websocket-service
+          port: 8000
+  tls: {}
+```
+
+```yaml tab="File (YAML)"
+http:
+  routers:
+    my-websocket-secure:
+      rule: "Host(`wss.example.com`)"
+      service: my-websocket-service
+      tls: {}
+  
+  services:
+    my-websocket-service:
+      loadBalancer:
+        servers:
+          - url: "http://my-websocket-server:8000"
+```
+
+```toml tab="File (TOML)"
+[http.routers]
+  [http.routers.my-websocket-secure]
+    rule = "Host(`wss.example.com`)"
+    service = "my-websocket-service"
+    [http.routers.my-websocket-secure.tls]
+
+[http.services]
+  [http.services.my-websocket-service]
+    [http.services.my-websocket-service.loadBalancer]
+      [[http.services.my-websocket-service.loadBalancer.servers]]
+        url = "http://my-websocket-server:8000"
+```
+
+## SSL Termination for WebSockets
+
+In this scenario, clients connect to Traefik using WSS (encrypted), but Traefik connects to your backend server using WS (unencrypted).
+This is called SSL termination.
+
+```yaml tab="Docker & Swarm"
+labels:
+  - "traefik.http.routers.my-wss-termination.rule=Host(`wss.example.com`)"
+  - "traefik.http.routers.my-wss-termination.service=my-ws-service"
+  - "traefik.http.routers.my-wss-termination.tls=true"
+  - "traefik.http.services.my-ws-service.loadbalancer.server.port=8000"
+```
+
+```yaml tab="Kubernetes"
+apiVersion: traefik.io/v1alpha1
+kind: IngressRoute
+metadata:
+  name: my-wss-termination-route
+spec:
+  entryPoints:
+    - websecure
+  routes:
+    - match: Host(`wss.example.com`)
+      kind: Rule
+      services:
+        - name: my-ws-service
+          port: 8000
+  tls: {}
+```
+
+```yaml tab="File (YAML)"
+http:
+  routers:
+    my-wss-termination:
+      rule: "Host(`wss.example.com`)"
+      service: my-ws-service
+      tls: {}
+  
+  services:
+    my-ws-service:
+      loadBalancer:
+        servers:
+          - url: "http://my-ws-server:8000"
+```
+
+```toml tab="File (TOML)"
+[http.routers]
+  [http.routers.my-wss-termination]
+    rule = "Host(`wss.example.com`)"
+    service = "my-ws-service"
+    [http.routers.my-wss-termination.tls]
+
+[http.services]
+  [http.services.my-ws-service]
+    [http.services.my-ws-service.loadBalancer]
+      [[http.services.my-ws-service.loadBalancer.servers]]
+        url = "http://my-ws-server:8000"
+```
+
+## End-to-End WebSocket Secure (WSS)
+
+For end-to-end encryption, Traefik can be configured to connect to your backend using HTTPS.
+
+```yaml tab="Docker & Swarm"
+labels:
+  - "traefik.http.routers.my-wss-e2e.rule=Host(`wss.example.com`)"
+  - "traefik.http.routers.my-wss-e2e.service=my-wss-service"
+  - "traefik.http.routers.my-wss-e2e.tls=true"
+  - "traefik.http.services.my-wss-service.loadbalancer.server.port=8443"
+  # If the backend uses a self-signed certificate
+  - "traefik.http.serversTransports.insecureTransport.insecureSkipVerify=true"
+  - "traefik.http.services.my-wss-service.loadBalancer.serversTransport=insecureTransport"
+```
+
+```yaml tab="Kubernetes"
+apiVersion: traefik.io/v1alpha1
+kind: ServersTransport
+metadata:
+  name: insecure-transport
+spec:
+  insecureSkipVerify: true
+
+---
+apiVersion: traefik.io/v1alpha1
+kind: IngressRoute
+metadata:
+  name: my-wss-e2e-route
+spec:
+  entryPoints:
+    - websecure
+  routes:
+    - match: Host(`wss.example.com`)
+      kind: Rule
+      services:
+        - name: my-wss-service
+          port: 8443
+          serversTransport: insecure-transport
+  tls: {}
+```
+
+```yaml tab="File (YAML)"
+http:
+  serversTransports:
+    insecureTransport:
+      insecureSkipVerify: true
+
+  routers:
+    my-wss-e2e:
+      rule: "Host(`wss.example.com`)"
+      service: my-wss-service
+      tls: {}
+  
+  services:
+    my-wss-service:
+      loadBalancer:
+        serversTransport: insecureTransport
+        servers:
+          - url: "https://my-wss-server:8443"
+```
+
+```toml tab="File (TOML)"
+[http.serversTransports]
+  [http.serversTransports.insecureTransport]
+    insecureSkipVerify = true
+
+[http.routers]
+  [http.routers.my-wss-e2e]
+    rule = "Host(`wss.example.com`)"
+    service = "my-wss-service"
+    [http.routers.my-wss-e2e.tls]
+
+[http.services]
+  [http.services.my-wss-service]
+    [http.services.my-wss-service.loadBalancer]
+      serversTransport = "insecureTransport"
+      [[http.services.my-wss-service.loadBalancer.servers]]
+        url = "https://my-wss-server:8443"
+```
+
+## EntryPoints Configuration for WebSockets
+
+In your Traefik static configuration, you'll need to define entryPoints for both WS and WSS:
+
+```yaml tab="File (YAML)"
+entryPoints:
+  web:
+    address: ":80"
+  websecure:
+    address: ":443"
+```
+
+```toml tab="File (TOML)"
+[entryPoints]
+  [entryPoints.web]
+    address = ":80"
+  [entryPoints.websecure]
+    address = ":443"
+```
+
+## Testing WebSocket Connections
+
+You can test your WebSocket configuration using various tools:
+
+1. Browser Developer Tools: Most modern browsers include WebSocket debugging in their developer tools.
+2. WebSocket client tools like [wscat](https://github.com/websockets/wscat) or online tools like [Piesocket's WebSocket Tester](https://www.piesocket.com/websocket-tester).
+
+Example wscat commands:
+
+```bash
+# Test standard WebSocket
+wscat -c ws://ws.example.com
+
+# Test WebSocket Secure
+wscat -c wss://wss.example.com
+```
+
+## Common Issues and Solutions
+
+### Headers and Origin Checks
+
+Some WebSocket servers implement origin checking. Traefik passes the original headers to your backend, including the `Origin` header.
+
+If you need to manipulate headers for WebSocket connections, you can use Traefik's Headers middleware:
+
+```yaml tab="Docker & Swarm"
+labels:
+  - "traefik.http.middlewares.my-headers.headers.customrequestheaders.Origin=https://allowed-origin.com"
+  - "traefik.http.routers.my-websocket.middlewares=my-headers"
+```
+
+```yaml tab="Kubernetes"
+apiVersion: traefik.io/v1alpha1
+kind: Middleware
+metadata:
+  name: my-headers
+spec:
+  headers:
+    customRequestHeaders:
+      Origin: "https://allowed-origin.com"
+
+---
+apiVersion: traefik.io/v1alpha1
+kind: IngressRoute
+metadata:
+  name: my-websocket-route
+spec:
+  routes:
+    - match: Host(`ws.example.com`)
+      kind: Rule
+      middlewares:
+        - name: my-headers
+      services:
+        - name: my-websocket-service
+          port: 8000
+```
+
+### Certificate Issues with WSS
+
+If you're experiencing certificate issues with WSS:
+
+1. Ensure your certificates are valid and not expired
+2. For testing with self-signed certificates, configure your clients to accept them
+3. When using Let's Encrypt, ensure your domain is properly configured
+
+For backends with self-signed certificates, use the `insecureSkipVerify` option in the ServersTransport configuration as shown in the examples above.
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index fe10e3740..d8d50cd10 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -171,6 +171,7 @@ nav:
       - 'Kubernetes and Let''s Encrypt': 'user-guides/crd-acme/index.md'
       - 'Kubernetes and cert-manager': 'user-guides/cert-manager.md'
       - 'gRPC Examples': 'user-guides/grpc.md'
+      - 'WebSocket Examples': 'user-guides/websocket.md'
       - 'Docker':
         - 'Basic Example': 'user-guides/docker-compose/basic-example/index.md'
         - 'HTTPS with Let''s Encrypt':
-- 
GitLab