
How to Configure Nginx as a Reverse Proxy on Ubuntu 24
Nginx as a reverse proxy is a game-changer for anyone running multiple services on a single server or looking to scale their web infrastructure. Unlike traditional web servers that directly serve static files, a reverse proxy acts as an intermediary between clients and backend servers, handling request distribution, SSL termination, and caching. This guide will walk you through configuring Nginx as a reverse proxy on Ubuntu 24, covering everything from basic setup to advanced configurations, troubleshooting common issues, and optimizing performance for production environments.
Understanding How Nginx Reverse Proxy Works
A reverse proxy sits between your users and your backend servers, intercepting requests and forwarding them to the appropriate backend service. Think of it as a smart traffic controller that can make decisions about where to send each request based on various factors like URL path, headers, or server availability.
Here’s what happens in a typical reverse proxy flow:
- Client sends a request to your domain (example.com)
- Nginx receives the request and evaluates proxy rules
- Nginx forwards the request to the appropriate backend server
- Backend server processes the request and sends response back to Nginx
- Nginx returns the response to the client
This architecture enables load balancing, SSL termination, caching, and the ability to run multiple applications on different ports while presenting them as a unified service.
Prerequisites and Installation
Before diving into configuration, make sure you have Ubuntu 24 running with sudo privileges. The installation process is straightforward:
sudo apt update
sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
Verify the installation:
nginx -v
sudo systemctl status nginx
You should see Nginx version information and a running status. By default, Nginx will be accessible on port 80, and you should see the default welcome page when visiting your server’s IP address.
Basic Reverse Proxy Configuration
Let’s start with a simple reverse proxy setup. Assuming you have a Node.js application running on port 3000, here’s how to configure Nginx to proxy requests to it:
sudo nano /etc/nginx/sites-available/myapp
Add the following configuration:
server {
listen 80;
server_name yourdomain.com www.yourdomain.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;
proxy_cache_bypass $http_upgrade;
}
}
Enable the site and restart Nginx:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
The nginx -t
command tests your configuration for syntax errors before applying changes. Always run this before reloading to avoid breaking your server.
Advanced Configuration Examples
Real-world scenarios often require more complex setups. Here are some practical configurations you’ll likely encounter:
Multiple Backend Services
When running multiple applications, you can route based on URL paths:
server {
listen 80;
server_name yourdomain.com;
# API requests go to Node.js backend
location /api/ {
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;
}
# Admin panel goes to Python Flask app
location /admin/ {
proxy_pass http://127.0.0.1:5000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# Everything else goes to React frontend
location / {
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Load Balancing Configuration
For high-traffic applications, you can distribute requests across multiple backend servers:
upstream backend_pool {
server 127.0.0.1:3000 weight=3;
server 127.0.0.1:3001 weight=2;
server 127.0.0.1:3002 weight=1;
keepalive 32;
}
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://backend_pool;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
The weight
parameter controls traffic distribution, while keepalive
maintains persistent connections to backend servers for better performance.
SSL/TLS Configuration
Setting up HTTPS is crucial for production environments. Here’s how to configure SSL with Let’s Encrypt:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Certbot will automatically modify your Nginx configuration to include SSL settings. The resulting configuration will look like this:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
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;
}
}
Performance Optimization
Here are key optimizations that can significantly improve your reverse proxy performance:
# Add to /etc/nginx/nginx.conf in the http block
worker_processes auto;
worker_connections 1024;
# Enable gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# Proxy buffering
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# Proxy timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
Common Issues and Troubleshooting
Here are the most frequent problems you’ll encounter and how to solve them:
502 Bad Gateway Error
This usually means your backend service isn’t running or isn’t accessible. Check if your application is running:
sudo netstat -tlnp | grep :3000
sudo systemctl status your-app-service
Also check Nginx error logs:
sudo tail -f /var/log/nginx/error.log
WebSocket Connection Issues
For applications using WebSockets (like real-time chat or live updates), add these headers:
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_read_timeout 86400;
}
Real IP Address Not Showing
If your backend application shows Nginx’s IP instead of the client’s real IP, ensure you’re setting the forwarded headers correctly and your backend application is configured to trust the proxy.
Reverse Proxy vs Other Solutions
Solution | Performance | Memory Usage | Configuration Complexity | Best Use Case |
---|---|---|---|---|
Nginx | Excellent | Low | Medium | High-traffic web applications |
Apache HTTP Server | Good | Higher | Medium | Traditional web hosting |
HAProxy | Excellent | Very Low | High | Complex load balancing |
Traefik | Good | Medium | Low | Docker/container environments |
Real-World Use Cases
Here are some practical scenarios where Nginx reverse proxy shines:
- Microservices Architecture: Route different API endpoints to different services running on separate ports
- Blue-Green Deployments: Switch traffic between different versions of your application by changing proxy_pass targets
- Static Asset Optimization: Serve static files directly from Nginx while proxying dynamic content to your application
- Development Environment: Run multiple projects on different ports but access them through clean URLs
Security Best Practices
Security should be a top priority when configuring reverse proxies. Here are essential security measures:
# Hide Nginx version
server_tokens off;
# Add security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req zone=api burst=20 nodelay;
# Block common attack patterns
location ~ /\.ht {
deny all;
}
location ~ /\. {
deny all;
}
Monitoring and Logging
Set up proper logging to monitor your reverse proxy performance:
# Custom log format
log_format proxy '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct="$upstream_connect_time" '
'uht="$upstream_header_time" urt="$upstream_response_time"';
# Apply to your server block
access_log /var/log/nginx/proxy.log proxy;
This configuration tracks upstream response times, which helps identify performance bottlenecks in your backend services.
For production deployments, consider pairing your Nginx reverse proxy with robust hosting solutions. A reliable VPS provides the flexibility to scale your reverse proxy setup, while dedicated servers offer the performance needed for high-traffic applications.
The configuration examples in this guide provide a solid foundation for most use cases, but remember that optimization is an ongoing process. Monitor your application’s performance, adjust buffer sizes and timeouts based on your specific needs, and always test configurations in a staging environment before deploying to production.
For more advanced configurations and the latest features, check the official Nginx documentation, which provides comprehensive coverage of all available directives and modules.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.