Skip to content

Websocket with Nginx

Posted on:March 14, 2024 at 06:20 PM

tp.web.random_picture

Expose a websocket with the Nginx server

Table of contents

Open Table of contents

Table of contents

TL;DR

location /wsapp/ {
	proxy_pass http://backend;
	proxy_http_version 1.1;
	proxy_set_header Upgrade $http_upgrade;
	proxy_set_header Connection "Upgrade";
	proxy_set_header Host $host;
}

In the example above /wsapp/ is a rule to capture the request and pass it to backend. and the backend is an upstream server that will receive the WebSocket request.

Introduction

While working on application deployment with more than one service we usually prefer using Nginx as a proxy server. That will parse the requests based on the rule configuration and forward it to the configured service. For normal web applications which only use REST APIs this works perfectly fine with normal configuration. when it comes to WebSockets we need to add a bit more configuration to the Nginx setup.

Nginx configuration for REST API

Upstream server setup

To use Nginx as a proxy server to handle and route requests to different services we will configure the upstream servers section in Nginx. Upstream is the configuration that creates a named upstream server that can be used in other Nginx configuration blocks.

upstream backend-rest1 {
	server apisvc1:8000;
}

upstream backend-common {
	server apicommon:8001;
}

Server Block setup

Set up a proxy server to listen and handle requests coming to servers. For this, we will configure server blocks that will receive requests, and parse the request according to configured location blocks.

server {
	listen 80;
	server_name localhost;

	location /apiv1/ {
		proxy_pass http://backend-rest1;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header Host $host;
	}

	location /apiv2/ {
		proxy_pass http://backend-common;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header Host $host;
	}

	location / {
		proxy_pass http://<frontend_url>
	}
}

The above block of configuration will listen on Port 80 of localhost and any request coming to the endpoint /apiv1 will be forwarded to backend-rest1 and requests coming to the endpoint /apiv2 will be forwarded to backend-common. Any Other request not matching with these 2 routes will go to the final default block.

Complete configuration

The complete configuration of Nginx for two services looks like the following

upstream backend-rest1 {
	server apirest1:8000;
}

upstream backend-common {
	server apicommon:8001;
}

server {
	listen 80;
	server_name localhost;

	location /apiv1/ {
		proxy_pass http://backend-rest1;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header Host $host;
	}

	location /apiv2/ {
		proxy_pass http://backend-common;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header Host $host;
	}

	location / {
		proxy_pass http://<frontend_url>
	}
}

Nginx Issue with socket

If you have a new chat feature, we need to implement a web socket. In our example above, let’s say apicommon is a service having an endpoint for the WebSocket which is exposed.

If we try to connect to the WebSocket with the above configuration, we will get issues of route not found.

Adding location block for WebSocket setup

To enable the WebSocket connection to pass through the Nginx proxy, we need to explicitly configure the location block that allows the WebSocket connection to go to the backend service.

To do that we will need to set the http_upgrade header for the request and also need to update the version of HTTP to 1.1

location /ws/ {
	proxy_pass http://backend-common;
	proxy_http_version 1.1;
	proxy_set_header Upgrade $http_upgrade;
	proxy_set_header Connection "Upgrade";
	proxy_set_header Host $host;
}

All the requests coming to /ws/ will be upgraded and forwarded to the backend-common server where our WebSocket endpoint is implemented. This above code block can be placed just above the final catch-call route.

Conclusion

When we use Nginx as a reverse proxy and we have WebSockets in our application, we need to make sure that there is a location block configured that upgrades the connection and forwards it to the WebSocket endpoint.