Putting NGINX in front of an application is the most common NGINX job, and header or path mistakes break apps subtly.
proxy_pass forwards a request to a backend and returns its response. The URI sent upstream follows a precise rule:
- Without a URI part (
proxy_pass http://127.0.0.1:8000;) the original request URI is passed unchanged:/api/usersstays/api/users. - With a URI part, even just
/(proxy_pass http://127.0.0.1:8000/;), the part matching the location prefix is replaced by it: inlocation /api/,/api/usersbecomes/users.
By default NGINX sends Host as the upstream address and adds nothing about the client, so the app sees NGINX as the client. Pass the original information explicitly:
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;so apps generatehttpsURLs.
The application must be configured to trust these headers only from the proxy. Timeouts (proxy_connect_timeout, proxy_read_timeout, default 60s) govern how long NGINX waits; when the backend is down or times out the client gets a 502 or 504. Upstream errors and their reasons appear in the error log.
Example
server {
listen 80;
server_name example.com;
location /api/ {
proxy_pass http://127.0.0.1:8000/; # /api/users -> /users
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_read_timeout 30s;
}
location /admin/ {
proxy_pass http://127.0.0.1:9000; # /admin/x -> /admin/x
}
}
# curl -i http://example.com/api/health
# HTTP/1.1 502 Bad Gateway <- when nothing listens on :8000Remember
- proxy_pass without URI keeps the path; with a URI it replaces the location prefix
- Forward Host, X-Forwarded-For and X-Forwarded-Proto explicitly
- 502 = backend unreachable, 504 = backend timeout
Watch out for
- Adding or forgetting a trailing slash in proxy_pass and getting doubled or missing path prefixes.