Nginx ngx_http_rewrite_module
Luke Hebert
- 6 minutes read - 1075 wordsThe ngx_http_rewrite_module lets you rewrite request URIs with PCRE regular expressions, issue redirects, and conditionally select configurations. Knowing the exact processing order of its directives saves you from subtle 500 errors and infinite rewrite loops, so let’s walk through each one.
The break, if, return, rewrite, and set directives are processed in the following order:
- The directives of this module specified at the
serverlevel are executed sequentially. - Then, repeatedly:
- A
locationis searched based on the request URI. - The directives of this module specified inside the found location are executed sequentially.
- The loop repeats if the request URI was rewritten, but no more than 10 times.
- A
break
| Property | Value |
|---|---|
| Syntax | break; |
| Default | none |
| Context | server, location, if |
Stops processing the current set of ngx_http_rewrite_module directives. If a directive is specified inside a location, further processing of the request continues in that location.
if ($slow) {
limit_rate 10k;
break;
}if
| Property | Value |
|---|---|
| Syntax | if (condition) { ... } |
| Default | none |
| Context | server, location |
The specified condition is evaluated. If true, the module directives inside the braces are executed, and the request is assigned the configuration inside the if directive. Configurations inside if directives are inherited from the previous configuration level.
A condition may be any of the following:
- A variable name; false if the value is an empty string or
"0".NoteBefore version 1.0.1, any string starting with
"0"was considered a false value. - Comparison of a variable with a string using the
=and!=operators. - Matching of a variable against a regular expression using
~(case-sensitive) and~*(case-insensitive). Captures are available in$1through$9. Negative operators!~and!~*are also available. If the expression includes}or;, enclose it in single or double quotes. - File existence check with
-fand!-f. - Directory existence check with
-dand!-d. - File, directory, or symbolic link existence check with
-eand!-e. - Executable file check with
-xand!-x.
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
}
if ($request_method = POST) {
return 405;
}
if ($slow) {
limit_rate 10k;
}
if ($invalid_referer) {
return 403;
}The $invalid_referer embedded variable is set by the valid_referers directive.
return
| Property | Value |
|---|---|
| Syntax | return code [text]; / return code URL; / return URL; |
| Default | none |
| Context | server, location, if |
Stops processing and returns the specified code to the client. The non-standard code 444 closes the connection without sending a response header.
Starting from version 0.8.42, you can specify either a redirect URL (for codes 301, 302, 303, 307, and 308) or a response body text (for other codes). Both can contain variables. A redirect URL can be a URI local to this server, in which case the full URL is formed from $scheme and the server_name_in_redirect and port_in_redirect directives.
A URL for a temporary redirect (302) can be specified as the sole parameter. It must start with http://, https://, or $scheme.
Before version 0.7.51, only the following codes could be returned: 204, 400, 402-406, 408, 410, 411, 413, 416, and 500-504. Code 307 was not treated as a redirect until versions 1.1.16 and 1.0.13. Code 308 was not treated as a redirect until version 1.13.0.
See also the error_page directive.
rewrite
| Property | Value |
|---|---|
| Syntax | rewrite regex replacement [flag]; |
| Default | none |
| Context | server, location, if |
If the regular expression matches the request URI, the URI is changed as specified in the replacement string. rewrite directives execute sequentially in the order they appear in the configuration file. If the replacement string starts with http://, https://, or $scheme, processing stops and a redirect is returned to the client.
An optional flag parameter can be one of:
- last - stops processing the current set of directives and starts a new location search for the changed URI.
- break - stops processing the current set of directives (same as the
breakdirective). - redirect - returns a temporary 302 redirect; used when the replacement does not start with
http://,https://, or$scheme. - permanent - returns a permanent 301 redirect.
The full redirect URL is formed from $scheme and the server_name_in_redirect and port_in_redirect directives.
server {
...
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last;
return 403;
...
}If these directives are placed inside a /download/ location, replace last with break. Otherwise Nginx will hit the 10-cycle limit and return a 500 error.
location /download/ {
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;
rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra break;
return 403;
}If the replacement string includes new request arguments, the previous arguments are appended after them. To avoid this, add a trailing question mark:
rewrite ^/users/(.*)$ /show?user=$1? last;If a regular expression includes } or ;, enclose the whole expression in single or double quotes.
rewrite_log
| Property | Value |
|---|---|
| Syntax | rewrite_log on | off; |
| Default | rewrite_log off; |
| Context | http, server, location, if |
Enables or disables logging of ngx_http_rewrite_module directive processing results into the error_log at the notice level.
set
| Property | Value |
|---|---|
| Syntax | set $variable value; |
| Default | none |
| Context | server, location, if |
Sets a value for the specified variable. The value can contain text, variables, or a combination of both.
uninitialized_variable_warn
| Property | Value |
|---|---|
| Syntax | uninitialized_variable_warn on | off; |
| Default | uninitialized_variable_warn on; |
| Context | http, server, location, if |
Controls whether warnings about uninitialized variables are logged.
Internal Implementation
The ngx_http_rewrite_module directives are compiled at the configuration stage into internal instructions interpreted during request processing. The interpreter is a simple virtual stack machine.
For example, the following directives:
location /download/ {
if ($forbidden) {
return 403;
}
if ($slow) {
limit_rate 10k;
}
rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;
}are translated into these instructions:
variable $forbidden
check against zero
return 403
end of code
variable $slow
check against zero
match of regular expression
copy "/"
copy $1
copy "/mp3/"
copy $2
copy ".mp3"
end of regular expression
end of codeNote that there are no instructions for the limit_rate directive above, as it is unrelated to the ngx_http_rewrite_module. A separate configuration is created for the if block. If the condition holds true, the request is assigned that configuration where limit_rate equals 10k.
The directive:
rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;can be made one instruction smaller by moving the first slash inside the parentheses:
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;The corresponding instructions then look like this:
match of regular expression
copy $1
copy "/mp3/"
copy $2
copy ".mp3"
end of regular expression
end of code