# Nginx Proxy_Pass Error

The proxy_pass directive connects Nginx to upstream servers, but misconfigured URLs cause 502 errors, wrong paths, or failed connections. A trailing slash makes the difference between correct proxying and broken routing. Understanding how Nginx constructs the proxied URL is essential.

Understanding Proxy_Pass URL Construction

  1. 1.proxy_pass combines two parts:
  2. 2.The location match
  3. 3.The proxy_pass URL

URL construction rules: - If proxy_pass has URI path: replace location match with proxy_pass path - If proxy_pass has no URI path: append request URI to proxy_pass

Example 1 - proxy_pass with path: ``nginx location /api/ { proxy_pass http://backend/v1/; } Request /api/users becomes http://backend/v1/users`

Example 2 - proxy_pass without path: ``nginx location /api/ { proxy_pass http://backend; } Request /api/users becomes http://backend/api/users`

Common Cause 1: Trailing Slash Mismatch

Trailing slashes drastically change behavior.

Problematic config: ``nginx location /api/ { proxy_pass http://backend:3000; }

Request /api/users: - Location captures /api/ - Remaining URI: users - proxy_pass has no path (no trailing slash) - Full proxy URL: http://backend:3000/api/users

Backend receives /api/users. If backend expects /users, this fails.

Solution - add trailing slash: ``nginx location /api/ { proxy_pass http://backend:3000/; }

Request /api/users: - Location captures /api/ - proxy_pass path: / - Remaining URI: users - Proxy URL: http://backend:3000/users

Backend receives /users - correct.

ConfigRequestBackend Receives
proxy_pass http://backend; (no slash)/api/users/api/users
proxy_pass http://backend/; (slash)/api/users/users
proxy_pass http://backend/v1/;/api/users/v1/users

Common Cause 2: Location Without Trailing Slash

Location without trailing slash changes matching behavior.

Problematic config: ``nginx location /api { proxy_pass http://backend/; }

Request /api/users: - Location /api matches prefix - Nginx doesn't strip /api from URI - proxy_pass path / replaces nothing - Proxy URL: http://backend/api/users

Solution: Add trailing slash to location: ``nginx location /api/ { proxy_pass http://backend/; }

Common Cause 3: Regex Location with Proxy_Pass

Regex locations can't use path replacement in proxy_pass.

Problematic config: ``nginx location ~ ^/api/(.*)$ { proxy_pass http://backend/$1; # Invalid - can't use capture groups in proxy_pass directly }

Nginx error: `` nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression

Solution: Use rewrite or map: ``nginx location ~ ^/api/(.*)$ { set $path $1; proxy_pass http://backend/$path; }

Or use prefix location: ``nginx location /api/ { proxy_pass http://backend/; }

Common Cause 4: Upstream DNS Resolution

proxy_pass with hostname requires DNS resolution.

Problematic config: ``nginx location / { proxy_pass http://api.example.com; }

If DNS changes IP, Nginx keeps old IP until reload.

Solution: Use resolver directive: ``nginx location / { resolver 8.8.8.8 valid=30s; set $upstream http://api.example.com; proxy_pass $upstream; }

Or use upstream block: ```nginx upstream api { server api.example.com resolve; # Nginx Plus feature }

location / { proxy_pass http://api; } ```

Common Cause 5: Wrong Protocol

HTTP vs HTTPS mismatch with upstream.

Problematic config: ``nginx location / { proxy_pass http://backend:443; # Backend expects HTTPS on 443 }

Upstream receives HTTP on HTTPS port - connection fails.

Solution: Use correct protocol: ``nginx location / { proxy_pass https://backend:443; proxy_ssl_verify off; # For self-signed certificates }

Common Cause 6: Missing Port

proxy_pass without port uses default (80 for HTTP, 443 for HTTPS).

Problematic config: ``nginx location / { proxy_pass http://backend; # Uses port 80, backend listens on 3000 }

Solution: Specify port: ``nginx location / { proxy_pass http://backend:3000; }

Common Cause 7: Upstream Block vs Direct URL

Mixing upstream block syntax with direct URL.

Problematic config: ```nginx upstream backend { server 10.0.0.1:3000; }

location /api/ { proxy_pass http://backend:3000/; # backend is upstream name, not host # Actually works, but confusing } ```

Solution: Use consistent approach: ```nginx upstream backend_servers { server 10.0.0.1:3000; server 10.0.0.2:3000; }

location /api/ { proxy_pass http://backend_servers/; } ```

Or direct: ``nginx location /api/ { proxy_pass http://10.0.0.1:3000/; }

Common Cause 8: Path Encoding Issues

URL encoding handled differently by Nginx and backend.

Problematic config: ``nginx location /api/ { proxy_pass http://backend/; }

Request /api/search?q=hello%20world: - %20 is space - Some backends expect decoded URL

Solution: Control encoding: ``nginx location /api/ { proxy_pass http://backend/; proxy_set_header X-Original-URI $request_uri; }

Backend can receive both encoded and decoded variants.

Common Cause 9: IPv6 Address Syntax

IPv6 addresses need brackets in proxy_pass.

Problematic config: ``nginx location / { proxy_pass http://::1:3000; # Invalid syntax }

Solution: Use brackets: ``nginx location / { proxy_pass http://[::1]:3000; }

Verification Steps

  1. 1.Test proxy_pass URL:
  2. 2.```bash
  3. 3.curl -v http://localhost/api/users 2>&1 | grep ">"
  4. 4.`
  5. 5.Check upstream receives:
  6. 6.```bash
  7. 7.# On backend server
  8. 8.tail -f /var/log/backend/access.log
  9. 9.`
  10. 10.Add diagnostic header:
  11. 11.```nginx
  12. 12.location /api/ {
  13. 13.proxy_pass http://backend/;
  14. 14.add_header X-Proxied-URL $upstream_uri always;
  15. 15.}
  16. 16.`
  17. 17.Test configuration:
  18. 18.```bash
  19. 19.sudo nginx -t
  20. 20.`
  21. 21.Check error log:
  22. 22.```bash
  23. 23.tail -f /var/log/nginx/error.log
  24. 24.`
  25. 25.Verify backend connection:
  26. 26.```bash
  27. 27.# Test backend directly
  28. 28.curl http://backend:3000/users
  29. 29.`

Complete Working Configurations

Simple proxy: ``nginx location /api/ { proxy_pass http://backend:3000/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }

With upstream block: ```nginx upstream backend { server 10.0.0.1:3000; server 10.0.0.2:3000 backup; keepalive 32; }

location /api/ { proxy_pass http://backend/; proxy_http_version 1.1; proxy_set_header Connection ""; } ```

With path rewrite: ``nginx location /old-api/ { rewrite ^/old-api/(.*)$ /v1/$1 break; proxy_pass http://backend:3000/; }

Dynamic upstream: ```nginx location /api/ { resolver 8.8.8.8 valid=30s;

set $upstream_host api.example.com; proxy_pass http://$upstream_host/; } ```

Quick Reference

ConfigRequestBackend URL
location /api/ { proxy_pass http://backend; }/api/users/api/users
location /api/ { proxy_pass http://backend/; }/api/users/users
location /api/ { proxy_pass http://backend/v1/; }/api/users/v1/users
location /api { proxy_pass http://backend/; }/api/users/api/users
location ~ ^/api/(.*)$ { proxy_pass http://backend/$1; }Invalid!Use set variable

The critical rule: trailing slash on proxy_pass strips the location prefix; no trailing slash preserves it. Match your location and proxy_pass slashes to what the backend expects.