Linux Apps & tools

Install Nginx reverse proxy

Practical Linux guide: install Nginx reverse proxy without the usual guesswork.

10 min read Beginner Updated 9 Jun 2026

Step-by-step guide

Work through each section in order. Stop when your issue is resolved — you do not need every step for every situation.

What you will achieve

Nginx as a reverse proxy to backend apps (Node, PHP-FPM, Docker) on Ubuntu/Debian — TLS termination and WebSocket pass-through.

1) Install Nginx

sudo apt install nginx
sudo systemctl enable --now nginx

2) Site config

# /etc/nginx/sites-available/app
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 Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

3) Add TLS with Certbot

See the Certbot guide for Let's Encrypt automation.

Verify

curl -I -H "Host: app.example.com" http://127.0.0.1
sudo ss -tlnp | grep nginx

5) Rate limiting

limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
server {
    limit_req zone=one burst=20 nodelay;
}

6) Upstream keepalive

upstream backend {
    server 127.0.0.1:3000;
    keepalive 32;
}

7) Static file caching

location /static/ {
    alias /var/www/static/;
    expires 30d;
}

Logging

tail -f /var/log/nginx/access.log
sudo nginx -T | less

nginx -T dumps full effective config — invaluable when includes obscure the active server block.

8) WebSocket timeout tuning

proxy_read_timeout 3600s;
proxy_send_timeout 3600s;

Prerequisites

Backend app listening on localhost port. DNS A record if public. nginx package. Optional certbot for TLS. Understanding of proxy headers for apps that need real client IP.

Default site cleanup

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

proxy_buffering off for SSE

proxy_buffering off;

Server-sent events and long polling need buffering disabled or clients see delayed streams.

upstream health checks

Commercial nginx plus or use separate health checker — open source nginx needs max_fails and fail_timeout on upstream server lines for passive health awareness when backend dies.

client_max_body_size uploads

client_max_body_size 100M;

Default 1M breaks file upload apps behind proxy — set in server or location block matching app requirements.

real_ip from CDN

Cloudflare connecting IP in CF-Connecting-IP header — set_real_ip_from cloudflare IP ranges and real_ip_header for accurate access logs behind CDN.

map directive for websocket upgrade

Some configs need map $http_upgrade $connection_upgrade block — copy from nginx wiki websocket example when proxy_pass returns 502 on websocket only while HTTP works.

ssl_stapling when TLS terminates

After certbot, enable stapling in nginx ssl block — reduces TLS handshake latency for returning visitors behind your reverse proxy.

include sites-enabled

Default nginx.conf includes sites-enabled — verify symlink not broken after manual site rename.

Health check endpoint

Expose /healthz returning 200 from backend — external monitor hits nginx which proxies to app — catches backend death even when nginx process still running.

Related guides

install linux nginx proxy reverse