Introduction
Whenever you visit one of these modern websites like Netflix, GitHub, Amazon, or Spotify, your request will not reach the application server directly; it goes through something called a reverse proxy which does things like routing, SSL, caching, compression, and load balancing of requests.
- Introduction
- What Is Nginx?
- What Is a Reverse Proxy?
- Why Use a Reverse Proxy?
- Reverse Proxy vs Forward Proxy
- How Nginx works?
- Benefits of Using Nginx as a Reverse Proxy
- Configure Nginx as a Reverse Proxy for a Node.js Application
- Step 2: Configure Nginx
- How proxy_pass Works
- Reverse Proxying Multiple Applications
- WebSocket support
- Turn on Gzip Compression
- Security headers
- Typical Reverse Proxy Problems 502 Bad Gateway
- Test Your Configuration
Nginx is one of the most widely used reverse proxies out there.
Nginx is loved by millions of websites as it is light-weight, fast, and can handle thousands of concurrent connections at once. Regardless of whether you are developing a simple Node.js application or dealing with complex micro-services architecture, setting up Nginx reverse proxy should be in your developer/DevOps toolbox.
Here, in this tutorial, you will learn:
- What Nginx is.
- What is a reverse proxy.
- How does Nginx process requests.
- How to install Nginx.
- How to configure your first reverse proxy.
- Practical examples with Node.js.
- Best practices for deploying in production environment.
At the end of this tutorial, you will know how to set up Nginx as a reverse proxy on your machine.
What Is Nginx?
Nginx, pronounced “Engine X,” is an open-source web server which can also act as:
- Reverse Proxy
- Load Balancer
- HTTP Cache
- API Gateway
- Mail Proxy
- Static File Server
Developed in 2004, Nginx was intended to overcome the C10K problem – the issue of processing 10,000 simultaneous client connections effectively.
It has become popular today due to its:
- High performance
- Low memory consumption
- Good scalability
- Effective request processing
- Easy configuration
What Is a Reverse Proxy?
A reverse proxy is positioned between clients and backend servers.
Rather than clients talking directly to your application they talk to Nginx. Nginx then forwards the request to the correct backend server and returns the response to the client.
User Browser
│
▼
Nginx
│
▼
Application Server
(Node.js / PHP / Python / Java)
From the client’s point of view it looks like they are talking directly to the website, but in reality Nginx is talking behind the scenes.
Why Use a Reverse Proxy?
Without a reverse proxy:
Client
│
▼
Application Server
Problems:
- Application server is directly exposed.
- SSL must be configured in every application.
- Limited scalability.
- Harder to manage multiple services.
- Increased security risks.
With Nginx:
Client
│
▼
Nginx Reverse Proxy
│
├────────► Node.js
├────────► Django
├────────► PHP
└────────► Go API
Benefits:
- Centralized SSL management.
- Better security.
- Easier scaling.
- Request routing.
- Load balancing.
- Response caching.
- Compression.
- Rate limiting.
Reverse Proxy vs Forward Proxy
These terms often confuse beginners.
| Feature | Forward Proxy | Reverse Proxy |
|---|---|---|
| Protects | Clients | Servers |
| Used By | End users | Website owners |
| Purpose | Hide client identity | Hide server architecture |
| Example | Corporate proxy, VPN | Nginx, HAProxy |
Forward Proxy
A forward proxy acts on behalf of the client.
Example:
User
│
▼
Forward Proxy
│
▼
Internet
Reverse Proxy
A reverse proxy acts on behalf of the server.
Internet
│
▼
Reverse Proxy
│
▼
Application

How Nginx works?
When a user comes to:
https://example.com
What happens is this:
Step 1:
The browser makes an HTTP request.
Step 2
Nginx receive the request. ↓
Step 3.
Test the configuration of Nginx.
Step 4
Nginx decides which backend server will be responsible for the request.
↓
Step 5
nginx passes on the request.
Step 6
The backend takes care of the request
↓
7 Steps
The response is sent back to Nginx.
↓
Step 8:
Nginx returns the response to the browser.
The process is fast, effective and transparent for the user.
Real-World Example
Imagine an online shopping website.
Without Nginx:
User
│
▼
Node.js Server
If 10,000 users access the site simultaneously, the application server may become overwhelmed.
With Nginx:
Users
│
▼
Nginx
│
├────► Server 1
├────► Server 2
├────► Server 3
└────► Server 4
Nginx distributes traffic across multiple backend servers, improving availability and performance.
Benefits of Using Nginx as a Reverse Proxy
Some of the main benefits are:
- Enhanced Security
Clients don’t talk directly to your application server. This hides internal infrastructure, and reduces the attack surface.
- SSL Termination
Nginx can centralize SSL certificates, so you don’t need to configure HTTPS on each application.
- Balance de carga
Traffic can be distributed across multiple backend servers to achieve performance and reliability.
- Static Files Serving
Nginx is also highly optimized to serve static assets, such as images, CSS and JavaScript. That takes load off of your application.
- Compress
Nginx supports Gzip and Brotli compression which helps reduce bandwidth and increase page load speeds.
- Buffering
Frequent requests can be served from cache, decreasing backend load and improving response times.
Installing Nginx
Ubuntu/Debian
Update your package index:
sudo apt update
Install Nginx:
sudo apt install nginx -y
Start the service:
sudo systemctl start nginx
Enable it to start on boot:
sudo systemctl enable nginx
Check the status:
sudo systemctl status nginx
You should see:
Active: active (running)
Verify the Installation
Open your browser and visit:
http://localhost
or
http://your-server-ip
You should see the default Welcome to Nginx! page, confirming that the web server is running successfully.
Understanding the Nginx Configuration Structure
Most Nginx configurations are stored in:
/etc/nginx/
Common directories include:
/etc/nginx/
├── nginx.conf
├── sites-available/
├── sites-enabled/
├── conf.d/
└── snippets/
The two directories you’ll use most are:
- sites-available/ – Contains available site configurations.
- sites-enabled/ – Contains symbolic links to active site configurations.
Your First Reverse Proxy Configuration
Let’s assume your Node.js application is running locally on port 3000.
Create a new configuration file:
sudo nano /etc/nginx/sites-available/myapp
Paste the following configuration:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
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;
}
}
What Does This Configuration Do?
listen 80;→ Listens for incoming HTTP requests.server_name example.com;→ Matches requests for your domain.proxy_pass→ Forwards requests to the Node.js application.proxy_set_header→ Preserves important client information such as the original IP address and protocol.
Enable the site:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
Test the configuration:
sudo nginx -t
If everything is correct, you’ll see:
syntax is ok
test is successful
Reload Nginx:
sudo systemctl reload nginx
Now, requests to your domain will be forwarded to the application running on localhost:3000.
Configure Nginx as a Reverse Proxy for a Node.js Application
Now that you’ve created your first reverse proxy configuration, let’s connect Nginx to a real Node.js application.
Step 1: Create a Simple Node.js Application
Install Express.js:
npm init -y
npm install express
Create a file named server.js:
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("Hello from Node.js behind Nginx!");
});
app.listen(3000, () => {
console.log("Server running on port 3000");
});
Start the application:
node server.js
Your application is now available at:
http://localhost:3000
Step 2: Configure Nginx
Open your Nginx configuration file:
sudo nano /etc/nginx/sites-available/myapp
Replace the contents with:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1: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;
}
}
Test the configuration:
sudo nginx -t
Reload Nginx:
sudo systemctl reload nginx
Now, when someone visits:
http://example.com
Nginx automatically forwards the request to your Node.js application.
How proxy_pass Works
The single most important directive is:
proxy_pass http://127.0.0.1:3000;
It tells the Nginx:
Any request from a client should be routed to the application running on port 3000.
The application is actually served on a different port, but the browser is not aware of it.
Reverse Proxying Multiple Applications
Suppose your server hosts three applications:
| Application | Port |
|---|---|
| React Frontend | 3000 |
| Node.js API | 5000 |
| Admin Dashboard | 8080 |
Instead of exposing all ports publicly, Nginx can route requests based on the URL.
Example:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
}
location /api {
proxy_pass http://localhost:5000;
}
location /admin {
proxy_pass http://localhost:8080;
}
}
Now:
example.com→ Reactexample.com/api→ Node APIexample.com/admin→ Admin Dashboard
This creates a clean, user-friendly URL structure.
Load Balancing with Nginx
As traffic grows, one application server may not be enough.
Nginx can distribute requests across multiple servers.
Define an Upstream Group
upstream backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002;
}
Now update the server block:
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
Nginx will automatically distribute incoming requests among the backend servers.
Benefits include:
- Improved performance
- Better fault tolerance
- Easier horizontal scaling
- Reduced server overload
SSL Termination with Nginx
Modern websites should always use HTTPS.
Instead of configuring SSL inside every application, let Nginx handle it.
Example:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/ssl/certs/example.crt;
ssl_certificate_key /etc/ssl/private/example.key;
location / {
proxy_pass http://localhost:3000;
}
}
Now:
HTTPS
↓
Nginx
↓
HTTP
↓
Application
The application only handles HTTP while Nginx manages encryption.
This approach simplifies certificate management and improves security.
Redirect HTTP to HTTPS
To ensure all traffic is encrypted:
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
Visitors are automatically redirected to the secure version of your website.
WebSocket support
Applications like:
- Messaging applications
- Live dashboards for online games
- Platforms for stock trading.
use WebSocket.
Configure Nginx to:
location /socket {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
If these headers are missing, WebSocket connections might not work.
Turn on Gzip Compression
Compression reduces page size and improves page loading speed.
Example:
gzip on; gzip_types text/plain text/css application/json application/javascript text/xml;
Advantages:
- Faster Web sites
- Less bandwidth usage
- Core Web Vitals, faster.
- Improved user experience
Configure Browser Caching
Static files rarely change.
Tell browsers to cache them:
location ~* \.(jpg|png|css|js|svg|woff2)$ {
expires 30d;
add_header Cache-Control "public";
}
Benefits include:
- More repeat visits
- reduced load on servers
- Even more SEO success
Security headers
Enhance your site security with common HTTP headers.
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy strict-origin-when-cross-origin;
These headers help to reduce the risk of clickjacking, MIME type sniffing and other attacks:
Typical Reverse Proxy Problems 502 Bad Gateway
502 Bad Gateway
Possible reasons:
- Application doesn’t run
- Incorrect location for proxy_pass directive
- Incorrect application port
504 Gateway Timeout
Possible reasons are:
- Slow server backend
- Database lag
- Firewall problems
If necessary, increase timeout values:
proxy_connect_timeout 60s;
proxy_send_timeout 60;
proxy_read_timeout 60s;
Permissions Issues
Always check:
File permissions
- SELinux or AppArmor policies
- Firewall settings
- Ports listening
Test Your Configuration
Always check before reloading Nginx:
sudo nginx -t
Reload securely:
sudo systemctl reload nginx
Always check configuration before restarting Nginx.