nginx Reverse Proxy Setup: proxy_pass, Headers and Buffers - 夜莺博客

nginx Reverse Proxy Setup: proxy_pass, Headers and Buffers

Most production web stacks put nginx in front of application servers so that TLS, static files, load balancing and access control live in one place. The core directive behind all of it is proxy_pass, and the most common source of "works on localhost, broken behind the proxy" bugs is a misunderstanding of how nginx combines the location prefix with the proxy URL. This article explains reverse proxy configuration with nginx from the official admin guide, including header forwarding, buffering and upstream logging.

Passing Requests to a Backend with proxy_pass

A minimal reverse proxy configuration forwards every request that matches a location to a backend server:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
    }
}

When proxy_pass has no URI part, nginx passes the full original request URI to the backend. When the proxy_pass URL does carry a URI (for example proxy_pass http://www.example.com/link/;), nginx replaces the matched location part with that URI. The same rule applies to regex locations:

location ~ \.php {
    proxy_pass http://127.0.0.1:8000;
}

The Slash Trap: location + proxy_pass URI Rules

Whether the location and the proxy target end with a slash decides exactly what the backend receives:

location /webapp/   { proxy_pass http://localhost:5000/api/; }
# request /webapp/foo?bar=baz  ->  backend receives /api/foo?bar=baz

location /webapp/   { proxy_pass http://localhost:5000/api; }
# -> /apifoo?bar=baz   (trailing slash removed, URI glued together!)

location /webapp    { proxy_pass http://localhost:5000/api; }
# -> /api/foo?bar=baz

Missing or extra slashes silently change the path seen by the application, which manifests as 404s, broken asset paths and incorrect relative links. When in doubt, test each combination against your framework's router.

Forwarding Client Headers

Backends need to know the original host and client address, which are lost in a proxy hop unless nginx passes them explicitly:

location /some/path/ {
    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_pass http://localhost:8000;
}

If the backend generates redirects based on Host or does rate limiting per client IP, these three headers are mandatory. Some upstreams (typically gzip-aware reverse proxies in front of PHP-FPM) require clearing the client Accept-Encoding so nginx can compress: proxy_set_header Accept-Encoding "";.

Buffering, Timeouts and Choosing the Outgoing IP

Proxy buffering decouples a slow client from a fast backend. Tune it when streaming (SSE/WebSocket proxying needs proxy_buffering off) or when responses are large:

location / {
    proxy_buffers 16 4k;
    proxy_buffer_size 2k;
    proxy_pass http://localhost:8000;
}

location /stream/ {
    proxy_buffering off;
    proxy_pass http://127.0.0.1:8080;
}

For multi-tenant setups where each backend should see traffic sourced from a specific address, use proxy_bind. And when debugging proxy chains, switch to a dedicated upstream log format that records upstream response time alongside request time:

log_format upstream_logging '$time_local $remote_addr "$request" '
    'upstream_response_time $upstream_response_time request_time $request_time';

location /webapp/ {
    access_log /var/log/nginx/upstream.log upstream_logging;
    proxy_pass http://127.0.0.1:5000/api/;
}

Putting It Together

A typical pattern pairs this nginx layer with Keepalived + HAProxy for VIP failover when you need TCP-level load balancing, or runs nginx inside the Docker bridge network model with the backend containers as upstream servers. Whatever the deployment, remember to open the listener in the host firewall - nftables examples for exactly this are in our nftables configuration guide.

原文链接:https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/