An Nginx reverse proxy sits in front of your application, accepts visitors on ports 80 and 443, and forwards requests to an app listening on a local port such as 3000 or 8080. It handles HTTPS, compression and static files so your app does not have to. This guide sets up an Nginx reverse proxy on a fresh Linux VPS.
Before you start
- A Linux VPS running Ubuntu 22.04/24.04 or AlmaLinux/Rocky 8 or 9, with root or sudo access.
- A domain whose A record points to the server's IP.
- An app already running locally, for example on
127.0.0.1:3000. - Ports 80 and 443 open in your firewall.
Install Nginx
- On Ubuntu or Debian:
sudo apt update && sudo apt install -y nginx - On AlmaLinux or Rocky Linux:
sudo dnf install -y nginx && sudo systemctl enable --now nginx - Check it runs:
systemctl status nginx, then openhttp://your-server-ipand you should see the Nginx welcome page.
Create the reverse proxy configuration
- Create a site file. On Ubuntu use
/etc/nginx/sites-available/app.example.com; on AlmaLinux use/etc/nginx/conf.d/app.example.com.conf. - Add this server block, replacing the domain and port:
server { listen 80; server_name app.example.com; location / { proxy_pass http://127.0.0.1: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; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 60s; } } - On Ubuntu, enable the site:
sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/ - Test the syntax and reload:
sudo nginx -t && sudo systemctl reload nginx
The X-Forwarded-* headers tell your app the visitor's real IP and that the original request used HTTPS. The Upgrade and Connection headers let WebSockets pass through.
Allow the proxy on SELinux (AlmaLinux/Rocky)
If you get a 502 error on a RHEL-family server, SELinux may block Nginx from connecting to the app port. Allow it with:
sudo setsebool -P httpd_can_network_connect 1Add free HTTPS with Let's Encrypt
- Install Certbot with the Nginx plugin:
sudo apt install -y certbot python3-certbot-nginx(on AlmaLinux enable EPEL first, thensudo dnf install -y certbot python3-certbot-nginx). - Request and install the certificate:
sudo certbot --nginx -d app.example.com - Choose to redirect HTTP to HTTPS when asked. Renewal runs automatically; test it with
sudo certbot renew --dry-run.
What to check afterwards
curl -I https://app.example.comreturns your app's response, not a 502.- Your app logs show real visitor IPs, not
127.0.0.1. Many frameworks need a "trust proxy" setting for this. - The app port is not reachable from outside: bind the app to
127.0.0.1or block the port in the firewall.
Troubleshooting
- 502 Bad Gateway: the app is not running or listens on a different port. Check with
ss -tlnp | grep 3000and read/var/log/nginx/error.log. - 504 Gateway Timeout: the app is too slow; raise
proxy_read_timeoutor fix the slow request. - Redirect loop after HTTPS: the app does not see
X-Forwarded-Protoand keeps redirecting to HTTPS; enable its proxy trust setting. - 413 Request Entity Too Large: add
client_max_body_size 50m;in the server block.
FAQ: Nginx reverse proxy
Why use a reverse proxy instead of exposing the app directly?
It centralises HTTPS, lets several apps share ports 80/443 by domain name, serves static files efficiently and hides the app from direct traffic.
Can Nginx proxy to several apps?
Yes. Add one server block per domain, or several location blocks with different proxy_pass targets.
Can I do this on cPanel hosting?
On shared hosting you cannot edit Nginx, but Node.js apps can run through the cPanel Node.js selector with LiteSpeed in front.
