Software & Configuration
Nginx as Reverse Proxy
How to configure Nginx to act as a reverse proxy towards Node.js, Python, and other services
A reverse proxy allows Nginx to receive requests on port 80/443 and forward them to an application running on an internal port (e.g. 3000, 8000, 8080). This way you can expose multiple applications on the same server with different domains, manage SSL centrally and add caching.
Basic configuration: app on local port
Example: you have an application running on localhost:3000 and want to expose it on app.example.com.
nano /etc/nginx/sites-available/app.example.comserver {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# Headers required for WebSocket and modern apps
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 and reload:
ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginxThen add SSL with Certbot:
certbot --nginx -d app.example.comMultiple applications on the same server
You can host multiple apps with different domains, each on its own port:
# App 1: Node.js on port 3000
server {
listen 80;
server_name api.example.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;
}
}
# App 2: Python on port 8000
server {
listen 80;
server_name dashboard.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
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 for WebSocket
If your app uses WebSocket (e.g. Socket.io, real-time chat):
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; # 24 hours for long-lived WebSocket connections
}Proxy with path: multiple apps on same domain
To expose different apps on paths of the same domain:
server {
listen 80;
server_name example.com;
# Main site
location / {
root /var/www/html;
index index.html;
}
# API on /api/ → port 3000
location /api/ {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# Admin panel on /admin/ → port 8080
location /admin/ {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}Timeout and upload size
server {
# ...
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Maximum upload size (e.g. 100MB)
client_max_body_size 100M;
}Verify and debug
# Test configuration
nginx -t
# Reload without downtime
systemctl reload nginx
# See proxy errors in real time
tail -f /var/log/nginx/error.log
# See incoming requests
tail -f /var/log/nginx/access.logSee also: Node.js with PM2 | LEMP Stack