How to Debug and Log Nginx Rewrite Rules for Request Processing


2 views

When rewrite rules behave differently across environments, first verify what configuration Nginx is actually using:

# Check which config files are being loaded
nginx -T

# For a specific site's config
nginx -T | grep "server_name your_domain.com"

# Reload after config changes (don't assume restart applies changes)
nginx -s reload

Add these directives to your Nginx config for detailed rewrite debugging:

server {
    rewrite_log on;
    error_log /var/log/nginx/rewrite.log notice;
    
    location / {
        # Your existing rules
        rewrite ^/old-path$ /new-path permanent;
    }
}

This creates a dedicated log file showing:

  • Which rewrite rules were evaluated
  • The order of evaluation
  • Whether each rule matched
  • The final rewritten URL

For complex scenarios, use the debug module (requires Nginx built with --with-debug):

events {
    debug_connection 127.0.0.1;
}

http {
    error_log /var/log/nginx/debug.log debug;
}

Consider this problematic rewrite scenario:

# Before debugging
rewrite ^/api/v1/(.*)$ /backend/$1 last;
rewrite ^/api/(.*)$ /legacy/$1 last;

The debug log might reveal:

2023/11/15 14:22:35 [notice] 1234#1234: *1 "^/api/v1/(.*)$" matches "/api/v1/users", client: 192.168.1.1
2023/11/15 14:22:35 [notice] 1234#1234: *1 rewritten data: "/backend/users", args: ""
  • Context matters: Server vs location block differences
  • Flag behavior: last vs break vs permanent
  • Variable values: Use echo $request_uri in location blocks
  • Regex anchors: Missing ^/$ causing partial matches

For production systems, enable debugging only for specific requests:

map $arg_debug $loggable {
    default 0;
    "1"     1;
}

server {
    error_log /var/log/nginx/debug.log debug if=$loggable;
}

Then append ?debug=1 to URLs when needed.


Many developers face situations where rewrite rules that work perfectly in development environments mysteriously fail in staging or production. This often happens when:

  • Nginx isn't properly reloading configuration changes
  • Multiple rules are interfering with each other
  • The configuration files being loaded aren't what you expect

First, verify what configuration Nginx is actually running:

sudo nginx -T

This command tests the configuration and dumps the entire loaded config to stdout. Look for your rewrite rules in the output to confirm they're present.

Enable debug logging by adding these directives to your nginx config:

error_log /var/log/nginx/error.log debug;
rewrite_log on;

After reloading nginx (sudo nginx -s reload), check the error log to see detailed rewrite processing:

tail -f /var/log/nginx/error.log

Consider this problematic rewrite configuration:

location /api {
    rewrite ^/api/v1/(.*)$ /v1/$1 last;
    rewrite ^/api/v2/(.*)$ /v2/$1 last;
}

To debug why v2 rules aren't working:

  1. Check if both rules appear in nginx -T output
  2. Verify the debug log shows rule processing
  3. Add temporary return statements to test pattern matching:
location /api {
    rewrite ^/api/v1/(.*)$ /v1/$1 last;
    rewrite ^/api/v2/(.*)$ /debug-v2 last;
    return 200 "Debug endpoint hit";
}
  • Cache issues: Some reverse proxies cache 301 redirects aggressively
  • Configuration inheritance: Rewrites in server blocks might be overridden by location blocks
  • Regular expression complexity: Overly complex patterns can fail silently

For production debugging, consider temporarily adding headers to trace rule execution:

add_header X-Rewrite-Debug "Rule processed: $uri -> $request_uri" always;