# Nginx Reverse Proxy Not Working

Nginx as a reverse proxy should forward requests to your backend and return responses. Instead, you get 502 Bad Gateway, 504 Gateway Timeout, or responses with missing data. The proxied application shows incorrect client IPs or can't connect at all.

Understanding Reverse Proxy Issues

Reverse proxy problems fall into categories: - Connectivity: Nginx can't reach the upstream - Headers: Wrong or missing forwarded headers - Timeouts: Requests take too long - SSL: Certificate issues between Nginx and backend

Check the error log first: ``bash tail -f /var/log/nginx/error.log

Common Cause 1: Upstream Not Reachable

The backend service isn't running or isn't accessible.

Diagnosis: ```bash # Check if backend is running curl http://localhost:3000/health

# Check if backend port is listening netstat -tlnp | grep 3000

# Check Nginx can reach backend curl --interface 127.0.0.1 http://localhost:3000/ ```

Error log shows: `` connect() failed (111: Connection refused) while connecting to upstream

Solutions:

  1. 1.Backend not running:
  2. 2.```bash
  3. 3.sudo systemctl start myapp
  4. 4.sudo systemctl enable myapp
  5. 5.`
  6. 6.Wrong port or host:
  7. 7.```nginx
  8. 8.# Verify the upstream address
  9. 9.location / {
  10. 10.proxy_pass http://127.0.0.1:3000; # Correct address?
  11. 11.}
  12. 12.`
  13. 13.Backend not started yet:
  14. 14.```nginx
  15. 15.# Use upstream block with fail_timeout
  16. 16.upstream backend {
  17. 17.server 127.0.0.1:3000 fail_timeout=10s;
  18. 18.keepalive 32;
  19. 19.}

server { location / { proxy_pass http://backend; } } ```

Common Cause 2: Upstream DNS Resolution

When using domain names for upstream, DNS might not resolve.

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

If DNS changes, Nginx keeps the 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; }

This re-resolves DNS periodically.

Or use upstream block: ```nginx upstream api { server api1.example.com:443 resolve; server api2.example.com:443 resolve; }

server { location / { proxy_pass https://api; } } ```

Common Cause 3: Missing Host Header

Backend expects a specific Host header but receives localhost or the upstream address.

Problem: ``nginx location / { proxy_pass http://backend:3000; # Backend receives Host: backend:3000 }

Solution: Forward the original host: ``nginx location / { proxy_pass http://backend: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; }

Or set specific host: ``nginx location / { proxy_pass http://backend:3000; proxy_set_header Host "api.example.com"; }

Common Cause 4: Wrong Upstream Protocol

Mixing HTTP and HTTPS between Nginx and backend.

Backend expects HTTPS: ```nginx # Wrong proxy_pass http://api.example.com;

# Correct proxy_pass https://api.example.com; ```

SSL verification issues: ``nginx proxy_pass https://self-signed.example.com; proxy_ssl_verify off; # For self-signed certificates

Or trust specific CA: ``nginx proxy_pass https://api.example.com; proxy_ssl_trusted_certificate /etc/ssl/certs/ca-bundle.crt; proxy_ssl_verify on; proxy_ssl_verify_depth 2;

Common Cause 5: Timeout Issues

Backend takes too long to respond.

Error log: `` upstream timed out (110: Connection timed out) while reading response header from upstream

Solution: Increase timeouts: ``nginx location / { proxy_pass http://backend:3000; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; }

For long-polling or SSE: ``nginx location /events { proxy_pass http://backend:3000; proxy_read_timeout 86400s; # 24 hours proxy_buffering off; }

Common Cause 6: Buffer Overflow

Large responses exceed buffer sizes.

Error log: `` upstream sent too big header while reading response header from upstream

Solution: Increase buffer sizes: ``nginx location / { proxy_pass http://backend:3000; proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; }

For large response bodies: ``nginx proxy_max_temp_file_size 0; proxy_buffering off;

Common Cause 7: WebSocket Not Working

WebSocket upgrades not being passed through.

Solution: ```nginx map $http_upgrade $connection_upgrade { default upgrade; '' close; }

server { location /ws { proxy_pass http://backend:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_read_timeout 86400s; } } ```

Common Cause 8: Client IP Not Forwarded

Backend sees all requests coming from Nginx's IP.

Problem: ``nginx location / { proxy_pass http://backend:3000; }

Backend receives: `` Remote-Addr: 127.0.0.1 (Nginx's IP)

Solution: Forward real IP: ``nginx location / { proxy_pass http://backend:3000; 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; }

Backend must trust these headers:

Express.js example: ``javascript app.set('trust proxy', true); app.set('trust proxy', 'loopback');

Django example: ``python SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

Common Cause 9: Compression Issues

Double compression or incompatible encoding.

Problem: ```nginx gzip on; gzip_types text/plain application/json;

location /api { proxy_pass http://backend:3000; # Backend also compresses -> double compression } ```

Solution: ```nginx # Option 1: Let backend handle compression gzip off;

# Option 2: Tell backend not to compress location /api { proxy_pass http://backend:3000; proxy_set_header Accept-Encoding ""; # Strip encoding gzip on; gzip_types application/json; } ```

Common Cause 10: Connection Reuse Issues

Keepalive connections to upstream not configured.

Solution: ```nginx upstream backend { server 127.0.0.1:3000; keepalive 32; # Keep 32 connections open }

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

Complete Working Configuration

```nginx upstream backend { server 127.0.0.1:3000 max_fails=3 fail_timeout=30s; keepalive 32; }

server { listen 80; server_name example.com;

location / { proxy_pass http://backend; proxy_http_version 1.1;

# Headers 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_set_header Connection "";

# Timeouts proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s;

# Buffers proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; } } ```

Verification Steps

  1. 1.Test backend directly:
  2. 2.```bash
  3. 3.curl http://localhost:3000/health
  4. 4.`
  5. 5.Test through Nginx:
  6. 6.```bash
  7. 7.curl -v http://example.com/
  8. 8.`
  9. 9.Check response headers:
  10. 10.```bash
  11. 11.curl -I http://example.com/
  12. 12.`
  13. 13.Monitor access and error logs:
  14. 14.```bash
  15. 15.tail -f /var/log/nginx/access.log /var/log/nginx/error.log
  16. 16.`
  17. 17.Test with specific headers:
  18. 18.```bash
  19. 19.curl -H "Host: example.com" http://localhost/
  20. 20.`

Quick Reference

ErrorCauseFix
Connection refusedBackend not runningStart backend service
upstream timed outSlow backendIncrease proxy_read_timeout
too big headerResponse headers too largeIncrease proxy_buffer_size
400 Bad RequestMissing Host headerSet proxy_set_header Host
Wrong client IPHeaders not forwardedSet X-Forwarded-For headers
502 Bad GatewayBackend crashed/restartedCheck backend logs
SSL errorsProtocol mismatchUse https:// in proxy_pass

Reverse proxy issues usually come down to connectivity, headers, or timeouts. Verify the backend works directly, then ensure Nginx passes all required information.