nginx and WebSockets

Kommentare

As of version 1.4, nginx is capable of forwarding WebSocket requests, so it can be used as a reverse proxy for HTTP, HTTPS, WS and WSS.

Example Backends

  • WebSocket server, running on ws://ws1.example.com:10080
  • HTTP server (for fallback), running on http://ws1.example.com:10080

This is a typical scenario given by Engine.IO, which provides a WebSocket server with HTTP fallback.

Goal

  1. WebSocket Proxy: forwards ws|http://ws.example.com to ws|http://ws1.example.com:10080 (WebSocket and HTTP requests)
  2. WSS SSL Endpoint: forwards wss|https://ws.example.com to ws|http://ws1.example.com:10080
  3. Path Rewriting: forwards wss|https://ws.example.com/services/myservice to ws|http://ws1.example.com:10080
  4. Load Balancing and Sticky Sessions: like 3., but forwards to three wsX servers, with one client always being forwarded to the same server

1. WebSocket Proxy

Simple forwarding of unencrypted HTTP and WebSocket to a different host:

server {
    listen       80;
    server_name  ws.example.com;

    location / {
        access_log off;
        proxy_pass http://ws.example.com:10080;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # WebSocket support (nginx 1.4)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

2. WebSocketSecure SSL Endpoint

The proxy is also an SSL endpoint for WSS and HTTPS connections. So the clients can use wss:// connections (e.g. from pages served via HTTPS) which work better with broken proxy servers, etc.

server {
    listen       443;
    server_name  ws.example.com;

    ssl on;
    ssl_certificate ws.example.com.bundle.crt;
    ssl_certificate_key ws.example.com.key;
    ssl_session_timeout 5m;
    ssl_protocols  SSLv2 SSLv3 TLSv1;
    ssl_ciphers  HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers   on;

    location / {

        # like above

    }
}

3. WSS Proxy with Path Rewriting

Like above, but HTTPS and WSS endpoints are not “/” but “/services/myservice/”. So something like wss://api.example.com/services/myservice can be done.

server {

    # like above

    location /services/myservice {
        access_log off;
        proxy_pass http://ws1.example.com:10080;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # WebSocket support (nginx 1.4)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Path rewriting
        rewrite /services/myservice/(.*) /$1 break;
        proxy_redirect off;
    }
}

4. Load Balancing

Like 3., but there are three WS backends (ws1, ws2, ws3). Each client must always be forwarded to the same backend (e.g. when using HTTPS requests).

upstream webpush {
    ip_hash;
    server ws1.example.com:10080;
    server ws2.example.com:10080;
    server ws3.example.com:10080;
}

server {

    # like above

    location /services/myservice {

        proxy_pass http://webpush;

        # the rest, like above

}

Issues

  • Old WebSocket versions (hixie-76) are not supported by nginx (this is no issue, because even mobile clients implement hybi-10/RFC 6455 now)
  • Not tested with Engine.IO’s FlashSocket fallback module
  • Not tested how nginx performs with > 30.000 connections