Web Servers 3d ago 5 views 5 min read

How to configure Nginx as a reverse proxy for Node.js

Set up Nginx to forward traffic to a Node.js application using the reverse proxy pattern. This guide covers installing dependencies, configuring the upstream block, and handling WebSocket connections.

Roy S
Updated 6h ago
Sponsored

Cloud VPS — scale in minutes

Instantly deploy SSD cloud VPS with guaranteed resources, snapshots and per-hour billing. Pay only for what you use.

You will configure Nginx to forward HTTP requests to a Node.js backend application. These steps target Ubuntu 24.04 with Nginx 1.24.0 and Node.js 20.x. You will set up the upstream block to handle standard HTTP traffic and WebSocket connections.

Prerequisites

  • Ubuntu 24.04 LTS server with root or sudo access.
  • Nginx 1.24.0 installed and running.
  • Node.js 20.x and npm installed on the server.
  • A Node.js application running on port 3000 (or another local port).
  • An SSL certificate installed via Certbot or manually.

Step 1: Install required packages

Ensure Nginx is the latest stable version and install Node.js if not already present. Run the following commands to update the package index and install Nginx.

apt update
apt install nginx -y

Install Node.js using the NodeSource repository to ensure you have version 20.x available.

curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install nodejs -y

Verify the installation by checking the versions of both services.

nginx -v
node -v
npm -v

You will see output similar to this:

nginx version: nginx/1.24.0
v20.10.0
9.8.1

Step 2: Create the Node.js application

Create a simple Node.js server to act as the backend. Navigate to a directory and initialize a new project.

mkdir /var/www/nodeapp
cd /var/www/nodeapp
npm init -y

Install the Express framework and create a basic server file.

npm install express
nano server.js

Paste the following code into the file to create a simple API endpoint and a WebSocket handler.

const express = require('express');
const http = require('http');
const WebSocket = require('ws');

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

app.get('/', (req, res) => {
  res.send('Hello from Node.js');
});

app.get('/api/data', (req, res) => {
  res.json({ message: 'API Response' });
});

wss.on('connection', (ws) => {
  ws.on('message', (message) => {
    ws.send('Echo: ' + message);
  });
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(`Node.js server listening on port ${PORT}`);
});

Save the file and start the application in the background using PM2 or nohup.

npm install -g pm2
pm2 start server.js --name nodeapp

Check the PM2 status to ensure the process is running.

pm2 list

You will see the application listed with status "online".

Step 3: Configure Nginx as a reverse proxy

Create a new configuration file for the reverse proxy. Remove the default configuration if it exists to avoid conflicts.

rm /etc/nginx/sites-enabled/default
nano /etc/nginx/sites-available/nodeapp

Paste the following configuration into the file. This config forwards HTTP traffic to the Node.js backend and handles SSL.

server {
    listen 80;
    server_name your-domain.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /api {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Create an SSL server block for HTTPS traffic.

server {
    listen 443 ssl http2;
    server_name your-domain.com www.your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /api {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Enable the new configuration by creating a symbolic link in sites-enabled.

ln -s /etc/nginx/sites-available/nodeapp /etc/nginx/sites-enabled/

Verify the installation

Test the Nginx configuration for syntax errors before reloading the service.

nginx -t

You will see output indicating the test is successful:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Reload Nginx to apply the changes.

nginx -s reload

Test the reverse proxy by accessing the domain over HTTP and HTTPS. You should see the "Hello from Node.js" message in your browser.

curl http://your-domain.com
curl https://your-domain.com

Expected output:

Hello from Node.js

Troubleshooting

If you encounter a 502 Bad Gateway error, check the Nginx error logs for upstream connection failures.

tail -f /var/log/nginx/error.log

Ensure the Node.js application is listening on the expected port and that the process is running. Check the PM2 status again.

pm2 logs

Verify that the SSL certificate paths in the Nginx configuration match the actual files in the Let's Encrypt directory.

ls -l /etc/letsencrypt/live/your-domain.com/

If the upstream is not responding, try accessing the Node.js application directly on port 3000 using curl to isolate the issue.

curl http://localhost:3000

If the direct connection fails, debug the Node.js application logs. If the connection succeeds but the proxy fails, review the proxy_pass directive and ensure the upstream block or port is correct. Ensure that the firewall allows traffic on ports 80 and 443.

ufw allow 80/tcp
ufw allow 443/tcp

Reload Nginx after any configuration changes to apply them immediately.

nginx -s reload
Sponsored

Windows Dedicated Server

High-performance Windows dedicated servers with licensed Windows Server, Remote Desktop access and enterprise-grade hardware.

Tags: Node.jsNginxsslReverse ProxyWebSockets
0
Was this helpful?

Related tutorials

Comments 0

Login to leave a comment.

No comments yet — be the first to share your thoughts.