Learn about Centmin Mod LEMP Stack today
Become a Member

Nginx NGINX as a WebSockets Proxy

Discussion in 'Nginx and PHP-FPM news & discussions' started by eva2000, May 25, 2014.

Tags:
  1. eva2000

    eva2000 Administrator Staff Member

    50,450
    11,658
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,077
    Local Time:
    2:15 AM
    Nginx 1.25.x
    MariaDB 10.x
    The WebSocket protocol provides a way of creating web applications that support realtime bi-directional communications between clients and servers. Part of HTML5, WebSockets makes it much easier to develop these types of applications then the methods previously available. Most modern browsers support WebSockets including Firefox, Internet Explorer, Chrome, Safari and Opera and more and more server application frameworks are now supporting WebSockets as well.

    For enterprise production use, where multiple WebSocket servers are needed for performance and high availability, a load balancing layer that understands the WebSocket protocol is required, and NGINX has supported WebSockets since NGINX 1.3 and can act as a reverse proxy and do load balancing of WebSocket applications.

    The WebSocket protocol is different than the HTTP protocol, but the WebSocket handshake is compatible with HTTP, using the HTTP Upgrade facility to upgrade the connection from HTTP to WebSocket. This allows WebSocket applications to more easily fit into existing infrastructures. For example, WebSocket applications can use the standard HTTP ports 80 and 443, thus allowing the use of existing firewall rules.

    A WebSockets application keeps a long running connection open between the client and the server, facilitating the development of real-time applications. The HTTP Upgrade mechanism used to upgrade the connection from HTTP to WebSocket uses the Upgrade and Connection headers. There are some challenges that a reverse proxy server faces in supporting WebSockets. One is that WebSocket is a hop-by-hop protocol, so when a proxy server intercepts an Upgrade request from a client it needs to send its own Upgrade request to the backend server, including the appropriate headers. Also, since WebSocket connections are long running, as opposed to the typical short running connections used by HTTP, the reverse proxy needs to allow these connections to remain open, rather then closing them, believing them to be idle.

    NGINX supports WebSockets by allowing a tunnel to be setup between a client and a backend server. In order for NGINX to send the Upgrade request from the client to the backend server, Upgrade and Connection headers must be set explicitly. For example:

    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 will deal with this as a WebSocket connection.

    NGINX Websockets Example


    Here is a live example to show NGINX working as a WebSockets proxy. This example will use ws, a WebSockets implementation built on node.js. NGINX will be acting as a reverse proxy for a simple WebSockets application utilizing ws and node.js. These instructions have been tested with Ubuntu 13.10 and CentOS 6.5 and may need to be adjusted for other OS versions. For this example, the WebSockets server has an IP address of 192.168.100.10 and the NGINX server has an IP address of 192.168.100.20. If you don’t already have node.js and npm installed, you can do so with the following command:

    For Debian/Ubuntu:​

    sudo apt-get install nodejs npm

    For RHEL/CentOS:​

    sudo yum install nodejs npm

    On Ubuntu, node.js will be installed as “nodejs”, but on CentOS as “node”. We will use “node” for the example, so we will create a link on Ubuntu to allow us to use “node”:

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

    And then to install ws:

    sudo npm install ws

    Note: If you get the error: “Error: failed to fetch from registry: ws” then running the following command should fix the problem:​

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

    Then you can rerun sudo npm install ws

    ws comes with the program /root/node_modules/ws/bin/wscat that we will use for our client, but we need to create a program to act as our server. The following should be put into the file server.js:

    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);
    });
    });​

    The program can then be executed with:


    node server.js

    It will print an initial “Server started” message and will then listen on port 8010, waiting for a client to connect to it and will process any requests it receives by echoing the message received from the client and sending a message back to the client containing the message it received. We want NGINX to proxy these requests so for that we will use the following configuration:

    map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
    }​

    upstream websocket {
    server 192.168.100.10:8010;
    }​

    server {
    listen 8020;
    location / {
    proxy_pass http://websocket;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    }
    }​

    This will cause NGINX to listen on port 8020 and proxy any requests received to the backend WebSockets server and to properly handle the WebSocket protocol. To test this we will use wscat as our client:

    /root/node_modules/ws/bin/wscat –connect ws://192.168.100.20:8020

    This will connect to the WebSockets server through the NGINX proxy and will allow you to type a message that will be sent to the server and the server will respond with a message. Once you type a message you should see the message echoed on the server and then a message from the server should appear on the client.

    Here is an example interaction:

    Server: Client:
    $ node server.js
    Server started
    wscat –connect ws://192.168.100.20: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 and messages can continue to be sent back and forth until either the client or server disconnects. All that is needed to get NGINX to properly handle WebSockets is to set the headers correctly to handle the Upgrade request that upgrades the connection from HTTP to WebSocket.

    For more information please see:






    The post NGINX as a WebSockets Proxy appeared first on NGINX.

    Continue reading...