A reverse proxy is one of the most powerful features of Nginx and a core building block in modern infrastructure. From APIs and dashboards to microservices and internal tools, reverse proxies are everywhere.
In this article, we’ll walk through how to set up a reverse proxy using Nginx on Ubuntu, step by step. Instead of just showing configuration, we’ll explain why things are done a certain way, what commonly breaks in production, and how to troubleshoot it properly.
This guide is written from a real system administrator’s perspective, not as a copy-paste tutorial.
What Is a Reverse Proxy
A reverse proxy sits in front of backend services and handles all incoming client requests. Clients talk to Nginx, and Nginx decides where to forward those requests.
The backend application is never exposed directly to the internet.
Typical use cases include:
- Hosting multiple applications on one server
- Running apps on non-standard ports (3000, 8080, 5000)
- Adding SSL, authentication, rate limiting
- Hiding internal services
- Preparing for load balancing and scaling
Reverse Proxy vs Forward Proxy
- Forward proxy → used by clients to access the internet (corporate proxies)
- Reverse proxy → used by servers to manage incoming traffic
This article focuses only on reverse proxy with Nginx.
Before You Start
Make sure the following are already in place:
- Nginx installed and running
If not, install it first using this guide:
https://infrarunbook.com/article/how-to-install-nginx-on-ubuntu-2204-complete-step-by-step-guide - Backend application is already running
- You know the backend IP address and port
- Firewall allows port 80 (and 443 if using HTTPS)
A reverse proxy will not fix a broken backend, so always verify the backend first.
Understanding the Basic Reverse Proxy Flow
A typical setup looks like this:
Client → Nginx (80 / 443) → Backend App (localhost:3000)Nginx listens on standard web ports, while the backend can run on any port or even another server entirely.
Step 1: Verify Your Backend Application
Before touching Nginx, confirm the backend is working.
For example, if your backend runs on port 3000:
curl http://127.0.0.1:3000If this does not return a valid response, stop here and fix the backend first.
Step 2: Open Your Nginx Site Configuration
We’ll use infrarunbook.com as the example domain.
Site configs are stored at:
/etc/nginx/sites-available/Open (or create) the config file:
sudo nano /etc/nginx/sites-available/infrarunbook.comStep 3: Basic Reverse Proxy Configuration
Below is a clean, production-safe reverse proxy configuration:
server {
listen 80;
server_name infrarunbook.com www.infrarunbook.com;
location / {
proxy_pass http://127.0.0.1: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;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}Why These Headers Matter
- Host – preserves the original domain
- X-Real-IP / X-Forwarded-For – passes real client IP
- X-Forwarded-Proto – avoids HTTPS redirect loops
- Upgrade / Connection – required for WebSockets and real-time apps
Skipping these headers is one of the most common mistakes in reverse proxy setups.
Step 4: Enable the Site
Enable the configuration:
sudo ln -s /etc/nginx/sites-available/infrarunbook.com /etc/nginx/sites-enabled/Disable the default site (recommended):
sudo rm /etc/nginx/sites-enabled/defaultStep 5: Test and Reload Nginx
Always test before applying changes:
sudo nginx -tIf successful, reload Nginx:
sudo systemctl reload nginxReloading avoids dropping active connections.
Step 6: Verify Reverse Proxy Is Working
Open a browser and visit:
http://infrarunbook.comYou should see the backend application response, even though the backend is not publicly exposed.
Reverse Proxy to a Remote Backend Server
Your backend does not need to be on the same machine.
Example:
proxy_pass http://10.10.10.20:8080;Ensure:
- Network connectivity exists
- Firewalls allow traffic
- Backend allows requests from the Nginx server
Reverse Proxy with HTTPS (Very Common Setup)
In production, reverse proxy is almost always combined with SSL.
Typical flow:
Client → HTTPS → Nginx → HTTP → BackendNginx handles encryption, while backend stays private.
If you haven’t installed SSL yet, follow this guide first:
👉 https://infrarunbook.com/article/how-to-install-lets-encrypt-and-use-it-with-nginx-on-ubuntu
Once SSL is enabled, you can safely add:
- HTTP → HTTPS redirects
- HSTS
- Security headers
Common Reverse Proxy Issues and Fixes
502 Bad Gateway
Cause
- Backend not running
- Wrong port or IP
- Firewall blocking traffic
Check backend port:
ss -tulnp | grep 3000Client IP Not Visible in Backend
Cause
- Missing forwarded headers
Ensure these are present:
- X-Real-IP
- X-Forwarded-For
- X-Forwarded-Proto
WebSockets Not Working
Cause
- Missing upgrade headers
Ensure:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";Redirect Loops After HTTPS
Cause
- Backend thinks traffic is HTTP
- SSL terminated at Nginx
Fix by passing:
proxy_set_header X-Forwarded-Proto $scheme;And configuring the backend to trust proxy headers.
Logs for Debugging Reverse Proxy Issues
Always check logs before guessing.
Error log:
/var/log/nginx/error.logAccess log:
/var/log/nginx/access.logLive view:
sudo tail -f /var/log/nginx/error.logBest Practices for Reverse Proxy in Nginx
- Always pass client IP headers
- Keep backend services private
- Terminate SSL at Nginx
- Test backend independently
- Reload Nginx instead of restart
- Monitor logs regularly
Final Thoughts
Reverse proxying with Nginx on Ubuntu is a core infrastructure skill. Once configured correctly, it allows you to securely expose internal services, run multiple applications on one server, and scale cleanly as your architecture grows.
For InfraRunBook, this topic ties naturally with:
- Nginx installation
- Let’s Encrypt SSL
- HTTPS redirects
- HSTS
- Security headers
