How to Prevent Nginx from Changing Port in Redirects When Using Varnish


1 views

When running Nginx behind Varnish with non-standard ports (e.g., Varnish on 80, Nginx on 8000), you might encounter unwanted port changes in redirects. For example, accessing example.com/blog might redirect to example.com:8000/blog/ instead of maintaining the original port 80.

This happens because Nginx's server_name_in_redirect and port_in_redirect directives default to using the actual listening port (8000) rather than the client-facing port (80). We need to make Nginx aware of the public-facing port.

Add these directives to your Nginx server block:

server {
    listen 8000;
    server_name example.com;
    
    # Fix redirect port issues
    port_in_redirect off;
    server_name_in_redirect off;
    absolute_redirect off;
    
    # Alternative if above doesn't work
    # proxy_set_header Host $host;
    # proxy_set_header X-Forwarded-Port 80;
    
    location / {
        # Your regular configuration
        try_files $uri $uri/ =404;
    }
}

After applying these changes, test with:

curl -I http://example.com/blog

Should return a Location header without port 8000:

HTTP/1.1 301 Moved Permanently
Location: http://example.com/blog/

If you're passing requests through Varnish with proxy headers, ensure proper header forwarding:

proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port 80;
  • Forgetting to reload Nginx (nginx -s reload)
  • Multiple server blocks conflicting with each other
  • Cache not being cleared between tests

The solution maintains clean URLs while preserving your reverse proxy architecture. Remember to test different scenarios including trailing slashes, missing files, and directory access.


When running Nginx behind Varnish with port translation (e.g., Varnish on port 80 forwarding to Nginx on port 8000), you might encounter an annoying behavior where Nginx adds the backend port to redirect URLs:

# Bad redirect example
curl -I http://example.com/2023
HTTP/1.1 301 Moved Permanently
Location: http://example.com:8000/2023/

Nginx's default behavior is to include the $server_port in redirects when:

  • Using try_files with directory redirects
  • Implementing rewrite rules
  • Handling missing trailing slash redirects

Add these directives to your Nginx server block:

server {
    listen 8000;
    server_name example.com;
    
    # Critical settings for proper redirects
    port_in_redirect off;
    absolute_redirect off;
    
    # Alternative if you need absolute redirects
    # absolute_redirect on;
    # server_name_in_redirect on;
    
    location / {
        try_files $uri $uri/ =404;
    }
}

If you're behind a reverse proxy, you should also ensure proper header handling:

server {
    listen 8000;
    
    set $real_scheme $scheme;
    if ($http_x_forwarded_proto) {
        set $real_scheme $http_x_forwarded_proto;
    }
    
    set $real_port 80;
    if ($http_x_forwarded_port) {
        set $real_port $http_x_forwarded_port;
    }
    
    port_in_redirect off;
    absolute_redirect on;
    server_name_in_redirect on;
}

Verify with curl commands:

# Should return 301 without port 8000
curl -I http://example.com/blog

# Should maintain your domain without backend port
curl -I http://example.com/2023/
  • Forgetting to reload Nginx after changes (nginx -s reload)
  • Mixing relative and absolute redirects
  • Not considering HTTPS redirect scenarios