Behind a reverse proxy
You will find below the configuration needed for deploying a Socket.IO server behind a reverse-proxy solution, such as:
In a multi-server setup, please check the documentation here.
nginx
Content of /etc/nginx/nginx.conf:
http {
server {
listen 80;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
Related:
The value of nginx's proxy_read_timeout (60 seconds by default) must be bigger than Socket.IO's pingInterval + pingTimeout (45 seconds by default), else nginx will forcefully close the connection if no data is sent after the given delay and the client will get a "transport close" error.
If you only want to forward the Socket.IO requests (for example when nginx handles the static content):
http {
server {
listen 80;
root /var/www/html;
location /socket.io/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
Or with a custom path:
http {
server {
listen 80;
root /var/www/html;
location /my-custom-path/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
In that case, the server and the client must be configured accordingly:
Server
import { Server } from "socket.io";
const io = new Server({
path: "/my-custom-path/"
});
Client
import { io } from "socket.io-client";
const socket = io({
path: "/my-custom-path/"
});
Apache HTTPD
Content of /usr/local/apache2/conf/httpd.conf:
Listen 80
ServerName example.com
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule headers_module modules/mod_headers.so
LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
LoadModule unixd_module modules/mod_unixd.so
User daemon
Group daemon
ProxyPass / http://localhost:3000/
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://localhost:3000/$1" [P,L]
# must be bigger than pingInterval (25s by default) + pingTimeout (20s by default)
ProxyTimeout 60
Related:
Node.js http-proxy
Installation: npm i http-proxy
const httpProxy = require("http-proxy");
httpProxy
.createProxyServer({
target: "http://localhost:3000",
ws: true,
})
.listen(80);
Caddy 2
Content of Caddyfile for Caddy 2, if you only want to forward the Socket.IO requests
example.com {
reverse_proxy /socket.io/* localhost:3000
}
Or, if you want a custom path:
example.com {
rewrite /path /path/
handle_path /path/* {
rewrite * /socket.io{path}
reverse_proxy localhost:3000
}
}
Related
Google Cloud Application Load Balancer
If you are using an Application Load Balancer on Google Cloud, you might need to increase the backend service timeout.
The configurable backend service timeout represents the maximum amount of time that the load balancer waits for your backend to process an HTTP request and return the corresponding HTTP response. Except for serverless NEGs, the default value for the backend service timeout is 30 seconds.
This timeout also applies to WebSocket connections:
- For the classic Application Load Balancer, WebSocket connections, whether idle or active, are closed after the backend service timeout.
- For the global external and regional external Application Load Balancers, idle WebSocket connections are closed after the backend service timeout.
You should increase this timeout to a value greater than pingInterval + pingTimeout (45 seconds by default).
This can be done in the Google Cloud Console, by modifying the "Timeout" field of the backend service, or via the gcloud CLI:
gcloud compute backend-services update <BACKEND_SERVICE_NAME> \
--global \
--timeout=60
Source: https://docs.cloud.google.com/load-balancing/docs/https/request-distribution#timeout-bes