โ† Back to Tutorials
28 May 2026ยท4 min read

Set Up an Nginx Reverse Proxy on Ubuntu

Configure Nginx as a reverse proxy on Ubuntu 24.04: proxy_pass to a backend app, forward the right headers, and add auto-renewing HTTPS with Let's Encrypt.

A reverse proxy sits in front of one or more backend applications and forwards client requests to them. Nginx is the most popular tool for the job: it terminates TLS, routes by hostname or path, adds caching and compression, and shields an app server that was never meant to face the public internet directly. A typical use case is running a Node.js, Python, or Java app on localhost:3000 and exposing it on ports 80/443 under a real domain.

This tutorial sets up Nginx as a reverse proxy on Ubuntu 24.04 LTS: install Nginx, write a server block that proxies to a backend, forward the correct headers, then add free HTTPS with Letโ€™s Encrypt. Every command and config snippet is production-shaped and copy-pasteable.

Prerequisites

  • Ubuntu 24.04 LTS server with a user that has sudo.
  • A domain name (e.g. app.example.com) with an A record pointing at the serverโ€™s public IP โ€” required for the HTTPS step.
  • A backend application already listening locally, for example on 127.0.0.1:3000.
  • Ports 80 and 443 reachable. If you run a firewall, see our UFW firewall guide.

Step 1: Install Nginx

Update the package index and install Nginx from the Ubuntu repository:

sudo apt update
sudo apt install -y nginx

Nginx starts automatically. Confirm it is running and enabled at boot:

systemctl status nginx

Browse to http://your-server-ip and you should see the default โ€œWelcome to nginxโ€ page.

Step 2: Allow HTTP and HTTPS through the firewall

If UFW is active, open the web ports using the bundled application profile:

sudo ufw allow 'Nginx Full'
sudo ufw status

Nginx Full opens both 80 and 443. Use Nginx HTTP if you only need port 80 for now.

Step 3: Create a reverse proxy server block

Ubuntu organises site configs under /etc/nginx/sites-available/ and enables them via symlinks in sites-enabled/. Create a config for your domain:

sudo nano /etc/nginx/sites-available/app.example.com

Paste the following, adjusting the domain and backend address:

server {
    listen 80;
    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;

    # WebSocket support
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

}

The proxy_set_header lines matter: without Host and X-Forwarded-*, backend apps see the wrong hostname and think every request comes from 127.0.0.1, breaking redirects, logging, and rate limiting.

Step 4: Enable the site and reload

Enable the config by symlinking it into sites-enabled/, test the syntax, then reload:

sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

The nginx -t output should end with syntax is ok and test is successful. Always run it before reloading โ€” a bad config will refuse to reload rather than take down the running server.

Optionally remove the default site so it does not catch unmatched hostnames:

sudo rm /etc/nginx/sites-enabled/default
sudo systemctl reload nginx

Step 5: Verify the proxy works

Request your site through Nginx and confirm the backend responds:

curl -I http://app.example.com

You should get a 200 OK (or whatever your app returns) with a Server: nginx header. If you see 502 Bad Gateway, Nginx reached no backend โ€” verify the app is actually listening on the address in proxy_pass with ss -tlnp | grep 3000.

Step 6: Add HTTPS with Letโ€™s Encrypt

Install Certbot and its Nginx plugin via snap, the method the project recommends on Ubuntu:

sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Request and install a certificate. Certbot edits your server block to add the TLS configuration and an HTTPโ†’HTTPS redirect automatically:

sudo certbot --nginx -d app.example.com

Answer the prompts (email, terms). Certbot installs a systemd timer that renews certificates before they expire. Confirm renewal works with a dry run:

sudo certbot renew --dry-run

Step 7: Confirm the secure setup

Test the HTTPS endpoint and the redirect from plain HTTP:

curl -I https://app.example.com
curl -I http://app.example.com

The HTTPS request should return 200, and the HTTP request should return a 301 redirect to the https:// URL.

Troubleshooting and common pitfalls

  • 502 Bad Gateway โ€” the backend is down or proxy_pass points to the wrong host/port. Check with ss -tlnp and the app logs.
  • Redirect loops โ€” the backend forces HTTPS itself but does not trust X-Forwarded-Proto. Ensure that header is set and the app honours it.
  • Certbot fails to validate โ€” DNS is not yet pointing at the server, or port 80 is blocked. Confirm the A record and firewall.
  • WebSocket disconnects โ€” the Upgrade and Connection headers are missing from the location block.
  • Changes ignored โ€” you edited sites-available but the symlink in sites-enabled points elsewhere, or you forgot systemctl reload nginx.

Where to go next

A single Nginx reverse proxy fronts one host well, but production traffic eventually needs multiple backends and health checks. That is exactly what a cloud load balancer provides โ€” see our walkthrough on setting up an Octavia load balancer in OpenStack. To keep Nginx itself running cleanly across reboots and updates, review managing systemd services.

Conclusion

You installed Nginx, configured a reverse proxy with the correct forwarding headers, verified it routes to your backend, and secured it with an auto-renewing Letโ€™s Encrypt certificate. This pattern fronts internal apps safely on a single server. When you need cloud-scale high availability across many backends, clouditiv runs managed load balancing on a sovereign, ISOย 27001 / BSIย C5 private cloud built on Ubuntu 24.04 + OpenStack 2025.2, with your data in Germany. Explore our on-premise cloud solution.