In this post we’ll talk about using NGINX and NGINX Plus with Node.js and Socket.IO. Our post about building real‑time web applications with WebSocket and NGINX has been quite popular, so in this post we’ll continue with documentation and best practices using Socket.IO.
Socket.IO is a WebSocket API that’s become quite popular with the rise of Node.js applications. The API is well known because it makes building realtime apps, like online games or chat, simple. NGINX 1.3.13 and later and all NGINX Plus releases support proxying of WebSocket connections, which allows you to utilize Socket.IO. The WebSocket protocol allows for full‑duplex, or bidirectional, communication via a single TCP connection.
Applications running in production usually need to run on port 80 (HTTP), port 443 (HTTPS), or both. This can be a challenge if several components of your application interact with the user or you are using a web server on port 80 to deliver other assets. This makes it necessary to proxy to the Socket.IO server, and NGINX is the best way to do that. Whether you have one instance of your backend application or hundreds, NGINX can also load balance your upstreams when using multiple nodes.
To install Node.js, download the appropriate distribution (or install with a package manager). Run the npm
install
socket.io
command to install Socket.IO.
For this example, we assume that the Socket.IO server for your real‑time app is running on port 5000. The following is a template for a server.js node application file; it’s a basic program that acts as a server and routes incoming requests to the proper port running the Socket.IO server.
var io = require('socket.io').listen(5000);
io.sockets.on('connection', function (socket) {
socket.on('set nickname', function (name) {
socket.set('nickname', name, function () {
socket.emit('ready');
});
});
socket.on('msg', function () {
socket.get('nickname', function (err, name) {
console.log('Chat message by ', name);
});
});
});
Add JavaScript code like the following to the file that is delivered to your client, for example index.html. This example requests a connection to your application to create a WebSocket with your user’s browser.
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io(); // your initialization code here.
</script>
NGINX and NGINX Plus can load balance and distribute user sessions to multiple nodes if your application has several instances. In the http
context in your NGINX or NGINX Plus configuration, include an upstream
block to define the nodes in an upstream group.
As shown in the following example, you can include the weight
parameter on a server
directive to set the proportion of traffic directed to it. Here srv1.app.com receives five times more sessions than the other servers. NGINX Plus extends the reverse proxy capabilities of NGINX with enhanced load balancing methods and by adding session persistence, health checks, extended status reports, and on‑the‑fly reconfiguration of load‑balanced server groups.
# in the http{} configuration block
upstream socket_nodes {
ip_hash;
server srv1.app.com:5000 weight=5;
server srv2.app.com:5000;
server srv3.app.com:5000;
server srv4.app.com:5000;
}
Now that the upstream group of servers is declared, a virtual server needs to be configured to direct traffic to it. At minimum, include the proxy_pass
directive and name the upstream group. Because the WebSocket protocol uses the Upgrade
header introduced in HTTP/1.1, we include the proxy_http_version
directive.
server {
server_name app.domain.com;
location / {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://socket_nodes;
}
}
To deliver static assets, you can have NGINX proxy requests to an upstream Node.js instance, but in most cases it’s more efficient to have NGINX serve them directly.
In combination with the server_name
directive in the server
block above, the following location
block tells NGINX to respond to client requests for content in http://app.domain.com/assets/ by serving it from the local /path/to/assets directory. You can further optimize static file handling or set cache expiration settings that meet your needs.
location /assets {
alias /path/to/assets;
access_log off;
expires max;
}
If you receive the following error, you are probably running a version of NGINX prior to 1.3. Use of WebSocket is supported in NGINX 1.3.13 and later.
WebSocket connection to '...' failed: Error during WebSocket handshake: 'Connection' header value is not 'Upgrade': keep-alive socket.io.js:2371
To try NGINX Plus, start your free 30-day trial today or contact us to discuss your use cases.
"This blog post may reference products that are no longer available and/or no longer supported. For the most current information about available F5 NGINX products and solutions, explore our NGINX product family. NGINX is now part of F5. All previous NGINX.com links will redirect to similar NGINX content on F5.com."