# [[Websocket friendly proxy config for Nginx and Caddy]] _Created: 2025-10-05_ | #nginx #reverseproxy #caddy| [[010 System Administration MOC|System Administration]] Some backend apps need the proxy to be aware of websockets transport. ## Nginx This configuration allows Nginx to act as a reverse proxy to an application running on port `3000`. It supports both **normal HTTP traffic** and **WebSocket upgrades**. ```nginx server { listen 80; server_name app.example.com; location / { proxy_http_version 1.1; 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; # Upgrade headers only matter if client requests upgrade proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_pass http://localhost:3000; } } ``` ### **Explanation of directives** - **`proxy_http_version 1.1;`** Ensures Nginx speaks HTTP/1.1 with the backend. This is required for WebSockets and other upgraded connections, because HTTP/1.0 does not support them. - **`proxy_set_header Host $host;`** Preserves the original Host header (e.g., app.example.com) instead of replacing it with localhost. Useful when the backend app does host-based routing or generates absolute URLs. - **`proxy_set_header X-Real-IP $remote_addr;`** Passes the actual client IP address to the backend. Without this, the backend would only see Nginx’s IP. - **`proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;`** Adds the client’s IP to the X-Forwarded-For chain. This is important if multiple proxies are in the path and you want to track the original source. - **`proxy_set_header X-Forwarded-Proto $scheme;`** Indicates whether the original request came in as http or https. Helps apps generate correct redirects or absolute links. - **`proxy_set_header Upgrade $http_upgrade;`** Forwards the Upgrade header from the client (e.g., Upgrade: websocket). Required to initiate protocol upgrades. - **`proxy_set_header Connection $connection_upgrade;`** Works with the Upgrade header. It automatically sets `Connection: upgrade` if an upgrade is requested, or `Connection: close` otherwise. This avoids sending upgrade headers to backends that don’t expect them. - **`proxy_pass http://localhost:3000;`** Sends all traffic to the backend service running on port 3000. ## Caddy Caddy handles most of the headers for proxy automatically. The `X-Real-IP` is apparently non-standard and mostly seen in nginx configs. Caddy follows the more popular `X-Forwarded-For` header convention, which has a list of IP addresses in case a request is proxied by more than one host. ``` app.example.com { reverse_proxy localhost:3000 { # Caddy already sets X-Forwarded-For # Only keep this if your app requires it header_up X-Real-IP {remote_host} } } ``` In fact, you don't need a config at all. Caddy can do it from commandline. ```bash caddy reverse-proxy --from http://app.example.com --to http://localhost:3000 ```