NginxReverse ProxyLinuxDeployment

Nginx Reverse Proxy Guide: proxy_pass, Headers, WebSocket, and Logs

Understand reverse proxies and configure Nginx for Node.js, Next.js, or Strapi with proxy_pass, forwarded headers, WebSocket upgrades, timeouts, and debugging logs.

·Updated ·10 min read·Counting...
Nginx Reverse Proxy Guide: proxy_pass, Headers, WebSocket, and Logs

A reverse proxy sits between users and application servers. Users access the proxy domain, and the proxy forwards requests to upstream apps such as Next.js, Node.js, or Strapi. It is commonly used for HTTPS, domain routing, load balancing, caching, rate limits, and access logs.

It does not automatically fix slow backends, broken permissions, or bad application architecture.

Forward proxy vs reverse proxy

Type Represents Does the user know the target service?
Forward proxy the client usually yes
Reverse proxy the server side usually only sees the proxy domain
browser -> Nginx :443 -> Next.js :3000
                       -> Strapi :1337

Minimal Nginx reverse proxy

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

After editing configuration:

sudo nginx -t
sudo systemctl reload nginx

Always test before reload.

proxy_pass trailing slash

The trailing slash and URI part can change path rewriting behavior:

location /api/ {
    proxy_pass http://127.0.0.1:1337/;
}

Here /api/users may be forwarded as /users. If you use:

proxy_pass http://127.0.0.1:1337;

the original request URI is typically preserved. Path proxying should be tested with curl -v, not guessed from slash placement.

WebSocket upgrades

For WebSocket paths:

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    location /socket/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

Do not force Connection upgrade on every ordinary request.

Timeouts

location /api/ {
    proxy_pass http://127.0.0.1:1337;
    proxy_connect_timeout 5s;
    proxy_read_timeout 60s;
    proxy_send_timeout 60s;
}

proxy_read_timeout is not a complete request deadline. It controls waiting between reads from the upstream. If you see many 504 errors, inspect upstream latency, logs, database calls, and connection pools before setting the timeout to ten minutes.

Common status codes

  • 502 Bad Gateway: upstream is down, port is wrong, connection refused, or protocol mismatch.
  • 504 Gateway Timeout: proxy waited too long for upstream.
  • 413 Request Entity Too Large: upload exceeds client_max_body_size.
  • Redirect loop: app and proxy disagree on HTTPS, Host, or base path.
  • Static asset 404: path rewriting or app base path is wrong.

Useful checks:

curl -v http://127.0.0.1:3000/
curl -vk https://example.com/
sudo tail -f /var/log/nginx/error.log

Verify the upstream directly before debugging Nginx.

Docker note

Inside Docker, 127.0.0.1 means the current container, not the host. Containers usually reach each other through a user-defined network and service name. For container networking basics, read localhost vs 0.0.0.0 in Docker.

Real IP and security

Forwarding X-Forwarded-* headers only passes information. Your app must explicitly decide which proxy layer it trusts. Otherwise an attacker may spoof client IP or protocol headers.

TLS, rate limits, authentication, and access rules still need to match your threat model.

Subscribe to FreeMac

Weekly picks: free Mac software reviews, trusted source updates, alternatives, and low-friction guides.