Nginx URL Rewrite: Handling Specific Query Parameters with Clean Redirects


1 views

When working with Nginx rewrites, handling specific query parameters requires careful consideration of Nginx's matching patterns. The common mistake developers make is trying to match query strings directly in the rewrite directive, which doesn't work as expected.

The original attempt:

rewrite "/?param1=val1&param2=&param3=(.+)&param4=(.+)&param5=(.+)" http://www.example.com/newparam/$1/$2 redirect;

fails because Nginx's rewrite directive operates on the URI portion without the query string. The query parameters (?param1=val1...) need to be matched separately.

Here's the correct way to handle this specific URL transformation:

server {
    listen 80;
    server_name www.example.com;

    if ($args ~* "^param1=val1&param2=&param3=([^&]+)&param4=([^&]+)(&param5=[^&]+)?$") {
        rewrite ^ /newparam/$1/$2? redirect;
    }

    location / {
        # Your regular configuration
    }
}

Key components of this solution:

  • $args - Nginx variable containing the query string
  • ~* - Case-insensitive regex matching
  • Capturing groups ([^&]+) to match parameter values
  • The final ? in the rewrite target removes any existing query string

For more complex requirements, you might need to handle multiple parameter patterns:

map $args $newpath {
    "~*^param1=val1&param2=&param3=([^&]+)&param4=([^&]+)" /newparam/$1/$2;
    default "";
}

server {
    if ($newpath) {
        rewrite ^ $newpath? redirect;
    }
}

While if is generally discouraged in Nginx configs, it's acceptable for rewrite rules in server context. For high-traffic sites, consider:

  • Moving the logic to your application if possible
  • Using map directives as shown above
  • Keeping the regex patterns as specific as possible

Always test your Nginx configuration changes:

nginx -t
service nginx reload

And verify with curl:

curl -I "http://www.example.com/?param1=val1&param2=&param3=test3&param4=test4"

Working with query parameters in Nginx rewrites can be tricky because the rewrite directive primarily operates on the URI path, not the query string. When dealing with URLs like:

http://www.example.com/?param1=val1&param2=&param3=val3&param4=val4&param5=val5

We need special handling to extract specific parameters and convert them into a clean path structure like:

http://www.example.com/newparam/val3/val4

Nginx processes the URI and query string separately. The rewrite directive works on the URI portion only, which is why your initial attempt didn't work. We need to:

  • Match the specific parameter pattern
  • Extract the required values (param3 and param4 in this case)
  • Construct the new URL while preserving other requests

Here's the proper way to handle this in Nginx:

location = / {
    if ($args ~* "^param1=val1&param2=&param3=([^&]+)&param4=([^&]+)(&param5=.+)?$") {
        return 301 /newparam/$1/$2;
    }
    # Other processing for non-matching URIs
}

The regex pattern accomplishes several things:

^param1=val1&param2=          # Matches exact parameter names and empty param2
&param3=([^&]+)               # Captures param3 value (any character except &)
&param4=([^&]+)               # Captures param4 value
(&param5=.+)?$                # Optionally matches param5 with any value

If you prefer using rewrite instead of return, here's another version:

location = / {
    if ($args ~* "^param1=val1&param2=&param3=([^&]+)&param4=([^&]+)") {
        rewrite ^ /newparam/$1/$2? permanent;
    }
}
  • Use 'permanent' for 301 redirects or 'redirect' for 302
  • The '=' in location ensures exact match for the root path
  • Test thoroughly with different parameter orders
  • Consider adding error checking for missing parameters

If parameters might appear in different orders, modify the regex:

if ($args ~* "^(.*&)?param1=val1(&.*)?&(.*&)?param2=((&.*)?&(.*&)?param3=([^&]+)(&.*)?&(.*&)?param4=([^&]+))") {
    return 301 /newparam/$7/$9;
}