nginx Reverse Proxy Guide
On this page
A reverse proxy sits in front of your applications and passes visitors' requests to them. With nginx in front, a Node.js app, a Docker container or a dashboard running on some port becomes https://app.example.com, with HTTPS, proper headers and one place to manage it all.
This guide sets up nginx as a reverse proxy on Ubuntu, step by step: the server block, the headers, WebSockets, free HTTPS and the errors you are most likely to meet.
What a reverse proxy does
- One public entry point. nginx listens on ports 80 and 443 and forwards each domain or path to the right app, so the apps themselves never face the internet.
- HTTPS in one place. nginx handles the certificates; the apps behind it can speak plain HTTP on localhost.
- Several apps on one server.
app.example.com,api.example.comandexample.com/blogcan each go to a different service. - Extras: compression, caching, upload limits and access rules, without touching the app.
Step 1: Install nginx
sudo apt update sudo apt install nginx
Open http://your-server-ip and you should see the nginx welcome page. If you use ufw, allow web traffic with sudo ufw allow 'Nginx Full'.
Make sure your app is running and reachable on the server itself, for example with curl http://127.0.0.1:3000. If that fails, nginx will fail too.
Run nginx and your apps with full root: HytHost KVM VPS plans start at €2.92/mo.
See VPS plansStep 2: Create the proxy server block
On Ubuntu, each site gets a file in /etc/nginx/sites-available/, enabled with a link in sites-enabled. Create /etc/nginx/sites-available/app.example.com:
server {
listen 80;
server_name app.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;
}
}
Enable it, test the configuration and reload:
sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx
Point the domain's A record at your server, and http://app.example.com now shows your app. Always run nginx -t before reloading: it catches typos before they take the site down.
The headers, and the trailing slash
Hostpasses the domain the visitor asked for. Without it, nginx sends the address fromproxy_pass, and apps that build links from the host break.X-Real-IPandX-Forwarded-Forpass the visitor's IP address. Without them, every request looks like it came from127.0.0.1.X-Forwarded-Prototells the app whether the visitor used HTTPS, so it does not redirect in a loop.
Ubuntu's nginx package ships these lines in /etc/nginx/proxy_params, so include proxy_params; is a shortcut.
The trailing slash matters. For an app under a path:
location /app/ {
proxy_pass http://127.0.0.1:3000/;
}
With the slash after the port, /app/login reaches the app as /login. Without it, the app receives the full /app/login.
WebSockets
Chat apps, live dashboards and many admin panels use WebSockets, which need two extra headers. Add this map once, inside the http block, for example in a new file /etc/nginx/conf.d/websocket.conf:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
Then in the location:
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_read_timeout 1h;
nginx closes a proxied connection that sends nothing for 60 seconds; the longer proxy_read_timeout keeps quiet WebSockets open. proxy_http_version 1.1 is the default only from nginx 1.29.7, and Ubuntu 24.04 ships 1.24, so keep the line.
Step 3: Free HTTPS with Certbot
sudo snap install --classic certbot sudo ln -s /snap/bin/certbot /usr/local/bin/certbot sudo certbot --nginx -d app.example.com
Certbot gets a free Let's Encrypt certificate, adds the HTTPS settings to your server block and can redirect HTTP to HTTPS. It renews the certificate automatically; check with sudo certbot renew --dry-run. More on certificates in how to get a free SSL certificate.
Fixing 502, 504 and 413 errors
| Error | Usual cause | Fix |
|---|---|---|
| 502 Bad Gateway | nginx cannot reach the app: it is stopped, crashed, or listens on another port or address | Start the app, check the port with curl http://127.0.0.1:PORT, read /var/log/nginx/error.log |
| 504 Gateway Timeout | The app took longer than 60 seconds to answer | Speed up the request, or raise proxy_read_timeout for that location |
| 413 Request Entity Too Large | An upload is bigger than nginx's default limit of 1 MB | Set client_max_body_size 50m; in the server block |
| Redirect loop | The app does not know the visitor used HTTPS | Pass X-Forwarded-Proto and tell the app it is behind a proxy |
After every change: sudo nginx -t, then sudo systemctl reload nginx.
Run it on a HytHost VPS
A reverse proxy needs a server where you control ports 80 and 443. HytHost VPS plans run on KVM with full root access, SSD storage and DDoS protection; pick Ubuntu 24.04 and follow the steps above. Running your apps in containers? Set up Docker first with how to install Docker on Ubuntu, and bind the containers' ports to 127.0.0.1 so only nginx can reach them.
Frequently asked questions
A reverse proxy forwards requests to one or more apps behind it. A load balancer is a reverse proxy that spreads requests across several copies of the same app. nginx can do both, with an upstream block listing the copies.
nginx cannot reach the app behind it. Check that the app is running and listening on the address and port in proxy_pass, and read /var/log/nginx/error.log for the exact reason.
No, when the app runs on the same server. nginx handles HTTPS for visitors and talks to the app over plain HTTP on 127.0.0.1, which never leaves the machine.
Give each app its own server block with its own server_name, such as app.example.com and api.example.com, each with a proxy_pass to a different port.
Yes. Publish each container's port on 127.0.0.1 only and point proxy_pass at it. That keeps the containers off the public internet, which matters because Docker's published ports bypass ufw.
Host your apps behind nginx
HytHost KVM VPS plans with full root access, SSD storage and DDoS protection start at €2.92/mo.
Live chat 8 AM – 11 PM (Chișinău time) · tickets answered during business hoursWas this guide helpful?