NGINX Rewrite Rules

NGINX rewrite rules allow you to modify all or part of a URL requested by a client. One reason for changing a URL is to tell clients that a requested resource has moved to another location. Rewrite rules can also be used to control how NGINX processes incoming requests.

The return and rewrite directives in NGINX can both be used to change URLs. Although both directives support redirects, their behavior is different.

  • The return directive provides the simplest and most efficient method for redirects.
  • The rewrite directive offers more flexibility when URL transformations or pattern matching are necessary.

This tutorial explains how the NGINX return and rewrite directives can be used to redirect, change, and rewrite URLs.

Key Takeaways:

  • Use return for straightforward redirects because it is more efficient. Use rewrite when regular-expression-based URL transformations or pattern matching are required.
  • The break flag ends rewrite processing and continues handling the request within the current location without checking other location blocks again.
  • The last flag starts another location search using the rewritten URI. Incorrect configuration can result in an infinite loop when the rewritten URI activates another matching rewrite rule.
  • Use permanent with HTTP 301 redirects for SEO-related migrations where ranking authority should move to the new URL. Use redirect with HTTP 302 for temporary changes that are not intended to transfer SEO value.
  • Regular-expression capture groups written with ( ) create variables such as $1 and $2, allowing one rewrite rule to process multiple dynamic URLs.
  • NGINX first evaluates rewrite directives in the server context, then chooses a location block, and finally processes location-specific rewrite directives. Knowing this sequence helps prevent unexpected results.
  • Use proxy_redirect when NGINX works as a reverse proxy and needs to modify Location or Refresh headers returned by backend servers.
  • The map directive provides hash-table-based lookups that can be more efficient than processing many rewrite rules sequentially when numerous URL redirects must be managed.

NGINX Return Directive

The return directive is one of the easiest and clearest ways to redirect a URL. It must be configured inside either a server or location context and includes the required HTTP status code together with the destination URL.

1. NGINX Return Directive in the Server Context

Using the return directive in the server context is useful when a website has moved to another domain and every URL on the previous domain should redirect to the replacement domain. It can also be used for URL canonicalization, such as consistently redirecting visitors to either the www or non-www version of a domain.

server {
        listen 80;
        server_name www.olddomain.com;
        return 301 $scheme://www.newdomain.com$request_uri;
}

In this server configuration, requests sent to www.olddomain.com are redirected to www.newdomain.com. As soon as NGINX receives a request for www.olddomain.com, it stops further processing and returns an HTTP 301 response containing the rewritten destination URL.

The example uses two variables in the return directive: $scheme and $request_uri.

  • $scheme represents the URL protocol, such as HTTP or HTTPS.
  • $request_uri contains the complete request URI, including query parameters.

2. Return Directive in the Location Context

Sometimes only individual pages need to be redirected instead of an entire domain. A return directive placed inside a location block can redirect a specific page to another URL.

location = /tutorial/learning-nginx {
     return 301 $scheme://example.com/nginx/understanding-nginx;
}

In this example, whenever the requested URI exactly matches /tutorial/learning-nginx, NGINX redirects the request to https://example.com/nginx/understanding-nginx/.

You can also redirect every request below a particular path to a different location:

location /tutorial {
     return 301 $scheme://example.com/articles;
}

NGINX Rewrite Directive

The NGINX rewrite directive provides another way to modify URLs. Like return, the rewrite directive can be configured in both server and location contexts.

The rewrite directive is useful when URLs must be matched and transformed with regular expressions. Unlike return, it changes the request URI and can continue processing the request depending on the flag specified in the rule.

The syntax of the rewrite directive is:

rewrite regex replacement [flag];

  • regex: A PCRE-based regular expression evaluated against the request URI rather than the complete URL.
  • replacement: The URI or URL that replaces the matched request.
  • flag: Determines how NGINX continues processing the rewrite.

Note: For basic redirects, return is normally preferable to rewrite because it is clearer and more efficient.

Processing Order of NGINX Rewrite Rules

NGINX evaluates rewrite rules according to a defined processing sequence:

  1. Rewrite directives defined in the server context are processed first.
  2. NGINX then determines the best matching location block.
  3. Rewrite directives configured inside that location block are processed.
  4. When the last flag is used, NGINX starts another location lookup.

Understanding this processing sequence is important when several rewrite rules are configured because it helps prevent unexpected behavior.

NGINX Rewrite Directive Examples

The following examples demonstrate several common rewrite patterns, beginning with a basic rewrite from one static page to another URL.

1. Rewrite a Static Page

Suppose the URL https://example.com/nginx-tutorial should internally resolve to https://example.com/somePage.html. The corresponding rewrite directive can be configured in the following location block.

server {
          ...
          ...
          location = /nginx-tutorial 
          { 
            rewrite ^/nginx-tutorial$ /somePage.html break; 
          }
          ...
          ...
}

Explanation:

  • The directive location = /nginx-tutorial means that the location block matches only an exact request for /nginx-tutorial.
  • NGINX searches the requested URI for the pattern ^/nginx-tutorial$.
  • The characters ^ and $ have special meanings when defining the pattern.
  • ^ marks the beginning of the string that should be matched.
  • $ marks the end of the string that should be matched.
  • If the requested URI matches the complete pattern, somePage.html becomes the replacement.
  • Because the rewrite rule finishes with break, further rewrite processing stops and the rewritten request is not passed through another location lookup.

2. Rewrite a Dynamic Page

Consider a dynamic URL such as https://www.example.com/user.php?id=11, where id=11 is the dynamic user identifier. The goal is to use a URL such as https://www.example.com/user/11. Creating a separate rewrite rule for every user would quickly become impractical. Instead, part of the URL can be captured in a variable so that one rewrite rule can process all matching dynamic pages.

server {
          ...
          ...
          location /user 
          { 
            rewrite ^/user/([0-9]+)/?$ /user.php?id=$1 break; 
          }
          ...
          ...
}

Explanation:

  • The location /user directive tells NGINX to use this location block for URLs beginning with the /user prefix.
  • NGINX checks the requested URI against the pattern ^/user/([0-9]+)/?$.
  • The expression [0-9]+ describes one or more numeric characters from 0 through 9. The + symbol means that one or more occurrences of the preceding pattern are allowed. Without +, the expression would match only a single character such as 5 or 8, rather than values such as 25 or 44.
  • The parentheses ( ) create a capture group, also known as a backreference. The $1 variable in user.php?id=$1 refers to the value captured by that group.

For example, if the input URL is https://www.example.com/user/24, the user identifier 24 matches the capture group and produces the following substitution: https://www.example.com/user.php?id=24.

3. Advanced URL Rewriting

Consider another case where https://www.example.com/user.php?user_name=john should correspond to https://www.example.com/user/login/john. Unlike the preceding example, the dynamic value user_name=john contains alphabetic characters. The following rewrite rule handles this structure:

server {
          ...
          ...
          location /user/login 
            { 
                rewrite ^/user/login/([a-z]+)/?$ /user.php?user_name=$1 break;           
            }
          ...
          ...
  }

Explanation:

  • The directive location /user/login tells NGINX to match URLs that contain the /user/login prefix.
  • NGINX evaluates the requested URI against ^/user/login/([a-z]+)/?$.
  • The expression [a-z]+ matches one or more lowercase alphabetic characters from a through z. The + symbol allows multiple characters. Without it, the pattern would match only one character such as a or c, rather than names such as john or doe.
  • The parentheses ( ) create a capture group. The variable $1 in user.php?user_name=$1 refers to the value captured by that group.

For example, when the input URL is https://www.example.com/user/login/john, the value john is captured and the resulting substitution is https://www.example.com/user.php?user_name=john.

4. Rewrite URLs with Multiple Backreferences

This example demonstrates URL rewriting with more than one backreference. Assume that the incoming URL is https://example.com/tutorial/linux/wordpress/file1 and it should be rewritten as https://example.com/tutorial/linux/cms/file1.php. The original path begins with /tutorial, while the later wordpress segment must become cms. In addition, a .php extension must be added to the filename. The rule can be written as follows:

server {
          ...
          ...
          location /tutorial
          {
             rewrite ^(/tutorial/.*)/wordpress/(\w+)\.?.*$ $1/cms/$2.php last;
          }
          ...
          ...
  }

Explanation:

  • The first backreference, ^(/tutorial/.*), matches an input URL beginning with /tutorial/.
  • The second backreference, (\w+), captures only the filename without its extension.
  • The two captured values are inserted into the replacement URL through $1 and $2.
  • The last flag tells NGINX to stop processing the current rewrite directives and begin another location search.

NGINX Rewrite Flags

The flag argument of the rewrite directive determines how NGINX continues after a rewrite occurs. Four different flags are available, with each one providing different processing behavior. The following examples illustrate how each flag works and when it can be used.

The Break Flag

The break flag tells NGINX to immediately stop processing additional rewrite rules and use the rewritten URI while continuing to handle the request inside the current location block.

Consider this configuration:

location /test {
    rewrite ^/test$ /new break;
}

When a request for /test arrives, NGINX internally changes the URI to /new and stops evaluating additional rewrite directives. The rewritten URI is not checked against other location blocks, so the existing location continues processing the request.

This behavior is useful when a URL needs to be rewritten internally while all subsequent processing should remain in the same location block. The client does not see the internal rewrite, and the browser address bar continues displaying the original URL.

The Last Flag

The last flag differs from break because it causes NGINX to perform another location search after rewriting the URI.

The following example shows this behavior:

location /test {
    rewrite ^/test$ /new last;
}

location /new {
    return 200 "Handled by /new location";
}

When NGINX receives a request for /test, the URI is rewritten to /new and rewrite processing in the current location stops. Instead of continuing inside the original location, NGINX searches again for a location block that matches /new.

In this configuration, the request is processed by the /new location block, which returns HTTP status 200 together with the message “Handled by /new location”. The last flag is therefore useful when a rewritten URI should be processed by another location block.

Important: Incorrect use of last can create an infinite loop when the newly selected location triggers another last rewrite that matches the same pattern.

The Redirect Flag

The redirect flag instructs NGINX to send an HTTP 302 response, indicating that the requested resource is temporarily available at another URL.

Consider this example:

location /old {
    rewrite ^/old$ /new redirect;
}

When a client requests /old, NGINX responds with an HTTP 302 Temporary Redirect and provides /new as the destination. The browser then sends another request to /new and updates the address bar to display the new URL.

Unlike break and last, which perform internal URI rewriting, redirect creates a client-side redirect, meaning that the browser is informed about the changed URL. This flag is suitable for temporary URL changes, testing, or short-term migrations that may later be reversed.

The Permanent Flag

The permanent flag behaves similarly to redirect, but it returns an HTTP 301 status rather than HTTP 302, indicating that the resource has permanently moved.

Here is an example:

location /old {
    rewrite ^/old$ /new permanent;
}

When a request for /old arrives, NGINX returns an HTTP 301 Permanent Redirect and informs the client that the resource is now permanently located at /new. The browser then requests the replacement URL and updates its address bar.

Browsers and search engines can cache permanent redirects, meaning that future requests for /old may be sent directly to /new without first contacting the server.

The permanent flag is appropriate for long-term URL changes, particularly during SEO-related content migrations, because search engines can transfer ranking signals to the replacement URL. It should be used carefully because cached HTTP 301 redirects can make later corrections slower to propagate.

Additional NGINX Rewrite Use Cases

Beyond basic URL rewriting, NGINX rewrite functionality can support several other common scenarios. The following examples cover practical situations that can occur in typical deployments.

SEO-Friendly Redirects

Suppose a website is being reorganized and all content currently located below /blog/ must move to /articles/ while keeping the rest of every URL unchanged. The redirect can be configured like this:

rewrite ^/blog/(.*)$ /articles/$1 permanent;

This approach is useful when reorganizing the content structure of a website. The expression (.*) captures everything that follows /blog/ in the URI path. Query strings remain intact automatically unless they are explicitly changed. Examples include:

  • /blog/2024/01/post-name/articles/2024/01/post-name
  • /blog/category/tech/articles/category/tech

Using the permanent flag, which produces an HTTP 301 response, is important for SEO-oriented migrations because it tells search engines that the content has permanently moved. Ranking authority and link equity can then be associated with the replacement URLs. This also helps avoid duplicate content issues and maintain search visibility while URLs are being reorganized.

Reverse Proxy Rewriting

When NGINX operates as a reverse proxy, a backend server can return redirects that contain internal URLs unavailable to external clients. These internal addresses can be rewritten to public-facing URLs before the response is delivered to the client. A basic configuration looks like this:

proxy_redirect http://backend:8080/ /;

The proxy_redirect directive belongs to the NGINX proxy module and modifies Location and Refresh headers returned by proxied servers. Its behavior can be understood as follows:

  • If a backend running at http://backend:8080 returns a redirect such as Location: http://backend:8080/dashboard, NGINX changes it to Location: /dashboard before forwarding the response to the client.
  • This prevents external users from seeing or trying to access internal backend addresses that might not be publicly reachable.
  • Without rewriting these headers, users could encounter errors or invalid redirects when a backend application redirects them to its internal address.
  • The general format is proxy_redirect original_url replacement_url.

Variables can also be used when more dynamic handling is required:

proxy_redirect http://backend:8080/ $scheme://$host/;

Using the Map Directive for Complex Conditions

Managing many URL redirects with separate rewrite rules can become difficult to maintain and inefficient. The map directive offers another way to organize larger collections of conditional URL mappings. A simple example is:

map $request_uri $new_uri {
    /old-page /new-page;
}

The map directive creates a variable based on pattern matching and can be more efficient than using many separate if statements or rewrite rules when numerous URL mappings are required. A larger example looks like this:

map $request_uri $new_uri {
    default "";
    /old-page /new-page;
    /blog/old-post /articles/new-post;
    /products/legacy-item /shop/current-item;
    ~^/category/(.*)$ /browse/$1;
}

server {
    if ($new_uri != "") {
        return 301 $new_uri;
    }
}

Advantages of using map:

  • Performance: Map definitions are prepared when the configuration is loaded and stored in hash tables, allowing very fast lookups compared with evaluating many rewrite rules one after another.
  • Maintainability: URL mappings can be kept together in a central location rather than distributed across many location blocks.
  • Flexibility: The directive supports exact matches, regular-expression patterns prefixed with ~, and fallback values.
  • Conditional logic: The resulting mapped variable can be evaluated in server or location contexts so redirects are applied only when appropriate.

The default "" entry assigns an empty value to $new_uri whenever no mapping matches. An if condition can then check this value so that a redirect occurs only for URLs that have a defined destination.

NGINX Rewrite Rules FAQs

1. What Is the Difference Between the Return and Rewrite Directives in NGINX?

The return directive immediately ends request processing and sends a response or redirect back to the client. The rewrite directive changes the request URI and can continue processing it inside NGINX, allowing the modified URI to be evaluated against location blocks. For simple redirects, return is generally faster and clearer. Use rewrite when regular-expression-based URI transformations are required before the appropriate processing path is determined.

2. What Do the Last and Break Flags Do in an NGINX Rewrite Rule?

The last flag stops the current rewrite processing and begins another search for a location block using the rewritten URI. The break flag also stops rewrite processing, but the request continues inside the current location block without performing another location match. In practical terms, last behaves like an internal redirect that triggers another location lookup, while break keeps processing in the current location. Use last when another location block should handle the new URI and break when the URI should change without leaving the current location.

3. How Do I Redirect HTTP to HTTPS in NGINX?

Place a return 301 directive inside a server block that listens on port 80:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

The $host variable keeps the requested domain name, while $request_uri retains the path and any query parameters. The client receives an HTTP 301 permanent redirect and switches to HTTPS. A rewrite rule is unnecessary for this use case because return is more efficient and expresses the configuration more directly. The return directive stops request processing immediately, whereas a rewrite rule could continue through additional configuration processing.

4. How Can I Test NGINX Rewrite Rules Without Restarting the Server?

Run nginx -t to verify configuration syntax before applying a change. Redirect behavior can be tested with curl -I to inspect response headers or curl -L to follow complete redirect chains. For more detailed debugging, enable rewrite logging by adding rewrite_log on; to the HTTP or server context and inspect the NGINX error log at the notice level. The log shows which rewrite rules match and how request URIs are transformed, making it possible to diagnose rewriting behavior without disrupting active traffic.

5. Can I Use Regex Capturing Groups in NGINX Rewrite Rules?

Yes. NGINX supports regular-expression capture groups in rewrite rules. Parentheses ( ) in the regex pattern create a group containing the matching part of the request URI. The captured values are made available as numbered variables such as $1, $2, $3, and subsequent numbers, which can then be used in the replacement string. For example:

rewrite ^/user/(\w+)$ /profile.php?username=$1 last;

In this example, (\w+) captures one or more word characters following /user/. If the requested URI is /user/johndoe, NGINX stores johndoe in $1 and rewrites the request to /profile.php?username=johndoe. Multiple capture groups can be included in one regular expression and referenced individually in the replacement, which makes this technique useful for transforming complex URL structures.

6. When Should I Use the Map Directive Instead of Rewrite Rules?

Use map when many URL mappings would otherwise require a long sequence of rewrite or if statements. NGINX prepares map definitions during configuration loading and stores mappings in hash tables, resulting in efficient lookups. This makes the directive useful for large URL migration projects involving dozens or hundreds of redirects. Keeping mappings inside a map block also centralizes the configuration and can make it easier to maintain than rewrite directives spread across many locations.

7. What Is Proxy_redirect and When Is It Needed?

The proxy_redirect directive changes Location and Refresh headers returned by upstream servers before those responses are delivered to clients. It is useful when a backend application produces absolute URLs containing internal addresses that external users cannot access. For example, if the backend returns Location: http://backend:8080/dashboard, the directive proxy_redirect http://backend:8080/ /; can change the header to /dashboard. Variables can also be used, as in proxy_redirect http://backend:8080/ $scheme://$host/;, to retain the original scheme and hostname used by the client.

8. Why Does an NGINX Rewrite Rule Cause an Infinite Redirect Loop?

An infinite loop can occur when a rewritten URI matches the same location block and activates the same rewrite rule again. For example, rewriting /user to /user/profile inside a location that matches /user can create a loop because /user/profile continues to match that location. One solution is to use break instead of last, preventing a new location lookup after the rewrite. Another approach is to make the location pattern specific enough that the rewritten URI no longer matches it. For example, location ~ ^/user/[0-9]+$ restricts the match to a defined URL structure. The curl -L command can also be used to trace redirect chains and identify where a loop begins.

Summary

This tutorial covered the two main NGINX directives used for URL rewriting. The return directive is the preferred choice for simple redirects because it immediately stops processing and is more efficient. The rewrite directive provides additional flexibility when URLs need to be transformed with regular expressions.

The four available rewrite flags were also covered. The break flag stops rewrite processing while remaining in the current location block, whereas last starts a new location search. The redirect and permanent flags return temporary HTTP 302 and permanent HTTP 301 redirects to the client.

For more advanced configurations, proxy_redirect can modify redirect headers generated by upstream servers, while the map directive can efficiently manage large collections of URL mappings. Understanding the NGINX processing sequence—starting with the server context, followed by location selection and then location-specific rewriting—also helps prevent configuration problems such as infinite redirect loops.

Source: digitalocean.com

Create a Free Account

Register now and get access to our Cloud Services.

Posts you might be interested in: