Skip to content
VeloxMedia
VPS guide

nginx Reverse Proxy with Free Let's Encrypt HTTPS

Most applications should not face the internet directly. nginx in front handles TLS, compression, timeouts and static files, and Let's Encrypt supplies the certificates at no cost.

Intermediate · About 3 min read · Updated 27 October 2026

Prerequisites

  • A domain or subdomain with an A record pointing at your server's IPv4 address
  • Ports 80 and 443 open in the firewall
  • An application listening locally, for example on 127.0.0.1:3000

Check DNS first, because certificate issuance fails until it resolves: dig +short app.example.com should print your server's address.

1. Install nginx and Certbot

Ubuntu and Debian:

sudo apt install -y nginx certbot python3-certbot-nginx

AlmaLinux and Rocky Linux:

sudo dnf install -y epel-release
sudo dnf install -y nginx certbot python3-certbot-nginx
sudo systemctl enable --now nginx
sudo setsebool -P httpd_can_network_connect 1

The last command allows nginx to connect to a local application port under SELinux.

2. Create the proxy configuration

Create /etc/nginx/conf.d/app.example.com.conf:

server {
    listen 80;
    listen [::]:80;
    server_name app.example.com;

    client_max_body_size 25m;

    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;
    }
}

The Upgrade and Connection headers let WebSockets pass through. Test and reload:

sudo nginx -t && sudo systemctl reload nginx

3. Issue the certificate

sudo certbot --nginx -d app.example.com --redirect -m [email protected] --agree-tos --no-eff-email

Certbot proves you control the domain, installs the certificate into your server block, and adds a permanent redirect from HTTP to HTTPS.

4. Confirm renewal

Certificates last 90 days. The package installs a systemd timer that renews them automatically; check it and do a dry run:

systemctl list-timers | grep certbot
sudo certbot renew --dry-run

5. Sensible hardening

Add these inside the HTTPS server block that Certbot created:

add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy strict-origin-when-cross-origin always;

Only add HSTS once you are sure the site will stay on HTTPS, because browsers remember it for the full max-age.

Several apps on one server

Repeat step 2 with a different server_name and upstream port for each application, then run Certbot for each name. One Small or Medium server can front a dozen low-traffic services this way.

Troubleshooting

  • 502 Bad Gateway: the app is not listening where proxy_pass points. Check with ss -tlnp.
  • Certificate challenge failed: DNS does not point at this server yet, or port 80 is blocked.
  • Redirect loop: the application is also redirecting to HTTPS; tell it to trust X-Forwarded-Proto.
  • Large uploads fail: raise client_max_body_size.

Common questions

Is Let's Encrypt really free?

Yes. Let's Encrypt issues domain-validated TLS certificates at no cost. They are valid for 90 days and Certbot renews them automatically through a systemd timer.

Why do I get a 502 Bad Gateway from nginx?

nginx cannot reach the upstream application. Make sure the app is running and listening on the address and port in proxy_pass, which you can check with ss -tlnp. On RHEL-family systems also enable httpd_can_network_connect in SELinux.

Can nginx proxy WebSockets?

Yes. Use proxy_http_version 1.1 and pass the Upgrade and Connection headers to the upstream, as shown in the example configuration.

Can I host several domains on one VPS?

Yes. Create one server block per domain with its own server_name and upstream port, then request a certificate for each domain with Certbot.

Deploy your first server in under a minute

Pick a region, choose a size and connect over SSH. No setup fees, cancel anytime.