How to Configure Nginx as Reverse Proxy for WebSocket


The WebSocket is a protocol which provides a way of creating web applications that supports real-time bi-directional communication between both clients and servers. WebSocket makes it much easier to develop these types of applications. Most modern browsers support WebSocket including Firefox, Internet Explorer, Chrome, Safari, and Opera, and more and more server application frameworks are now supporting WebSocket as well.

For a production environment, where multiple WebSocket servers are needed for getting a good performance and high availability of the website or application, a load balancing layer which understands the WebSocket protocol is required, NGINX supports the use of WebSocket from NGINX version 1.3 and can act as a reverse proxy for doing load balancing of applications.

NGINX supports WebSocket by allowing a tunnel to be set up between both client and back-end servers.  NGINX will send the Upgrade request from the client to the back-end server, the Upgrade and Connection headers must be set explicitly.

location /wsapp/ {
    proxy_pass http://wsbackend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Once this is done, NGINX deals with this as a WebSocket connection.

NGINX Websocket Installation with Example

Here is a live example to show NGINX working as a WebSocket proxy. This example helps in WebSocket implementation built on Node.js. NGINX acts as a reverse proxy for a simple WebSocket application utilizing ws and Node.js. These instructions have been tested with Ubuntu 13.10 and CentOS 6.5 but which needs to be adjusted for other OSs and versions. For this example, the WebSocket server’s IP address is 192.168.1.1 and the NGINX server’s IP address is 192.168.1.2

If you don’t have Node.js and npm installed, then run the following command:

# sudo yum install nodejs npm

Node.js is installed as nodejs on Ubuntu and as node on CentOS. The example uses node, so on Ubuntu we need to create a symbolic link from nodejs to node:

# ln -s /usr/bin/nodejs /usr/local/bin/node

To install Websocket, run the following command:

# sudo npm install ws

Note: If you get an error message like: “Error: failed to fetch from registry: ws”, run the following command to fix the problem

# sudo npm config set registry http://registry.npmjs.org/

Then run the sudo npm install command again

# sudo npm install ws

‘ws’ comes with the program /root/node_modules/ws/bin/wscat that can be used for our client, but we need to create a program to act as the server. Create a file called a server.js with these contents

console.log("Server started");
var Msg = '';
var WebSocketServer = require('ws').Server
    , wss = new WebSocketServer({port: 8010});
    wss.on('connection', function(ws) {
        ws.on('message', function(message) {
        console.log('Received from client: %s', message);
        ws.send('Server received from client: ' + message);
    });
 });

To execute the server program, run the following command:

# node server.js

The server prints an initial “Server started” message and then listens on port 8010, waiting for a client to connect to it. When it receives a client request, it echoes it and sends a message back to the client containing the message it received. To have NGINX proxy these requests, we create the following configuration

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }
    upstream websocket {
        server 192.168.1.1:8010;
    }
    server {
        listen 8020;
        location / {
            proxy_pass http://websocket;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
    }
}

NGINX listens on port 8020 and proxy requests to the back-end WebSocket server. The proxy_set_header directives enable NGINX to properly handle the WebSocket protocol.

To test the server, we run wscat in our client system

# /root/node_modules/ws/bin/wscat --connect ws://192.168.1.2:8020

wscat connects to the WebSocket server through the NGINX proxy. When you type a message for wscat to send to the server, you see it echoed on the server and then a message from the server appears on the client. Here’s a sample interaction

Server: Client:

# node server.js
Server started
# wscat –connect ws://192.168.1.2:8020
Connected (press CTRL+C to quit)
> Hello
Received from client: Hello       
< Server received from client: Hello

Here we see that the client and server are able to communicate through NGINX which is acting as a proxy server and messages can continue to be sent back until either the client or server disconnects. All that is needed to get NGINX configured properly to handle WebSocket, and set the headers correctly to handle the Upgrade request that upgrades the connection from HTTP to WebSocket.

Other Interesting Posts

Advertisements