Report this

What is the reason for this report?

Nginx Rewrite URL Rules: Examples and Configuration

Updated on May 12, 2026
Meghna GangwarManikandan Kurup

By Meghna Gangwar and Manikandan Kurup

Nginx Rewrite URL Rules: Examples and Configuration

NGINX rewrite rules are used to change entire or a part of the URL requested by a client. The main motive for changing a URL is to inform the clients that the resources they are looking for have changed their location, apart from controlling the flow of request processing in NGINX.

The return and rewrite directives in NGINX are used to rewrite URLs. While both can be used to achieve redirection, they do not behave exactly the same.

  • The return directive is the simplest and most efficient way to perform redirects.
  • The rewrite directive is more flexible and is used when URL transformation or pattern matching is required.

In this tutorial, we will explore how both return and rewrite directives are used in NGINX to change or rewrite URLs.

Key Takeaways:

  • Use return for simple redirects; it’s more efficient. Use rewrite only when you need regex-based URL transformations or pattern matching.
  • The break flag stops rewrite processing and serves the request within the current location without re-evaluating other location blocks.
  • The last flag initiates a new location search with the rewritten URI. Improper use can create infinite loops if the new location triggers another rewrite.
  • Use permanent (301) for SEO migrations to transfer ranking authority. Use redirect (302) only for temporary changes that won’t transfer SEO value.
  • Regex capturing groups ( ) create variables like $1 and $2 that enable a single rewrite rule to handle multiple dynamic URLs.
  • NGINX processes server context rewrites first, then selects a location block, followed by location-specific rewrites. Understanding this order helps avoid unexpected behavior.
  • Use proxy_redirect to rewrite Location and Refresh headers from backend servers when NGINX acts as a reverse proxy.
  • The map directive creates hash table lookups that are faster than sequential rewrite rules for managing multiple URL redirects.

NGINX Return directive

The easiest and cleanest way to redirect a URL is by using the return directive. The return directive must be declared in the server or location context by specifying the status code and the URL to be redirected.

1. NGINX Return directive in Server context

The return directive in server context is very useful in a situation where you have migrated your site to a new domain and you want to redirect all old URLs to the new domain. Further, it also helps in canonicalization of URLs by forcing your site to redirect to either www or non-www version.

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

The return directive in the above server context redirects requests destined for www.olddomain.com to www.newdomain.com. As soon as NGINX receives a request for www.olddomain.com, it stops processing the request and sends a 301 response along with the rewritten URL to the client.

The two variables used in the above return directive are $scheme and $request_uri:

  • $scheme defines the protocol of the URL (http or https)
  • $request_uri contains the complete URI including query parameters

2. Return directive in Location context

In some situations, you may want to redirect specific pages instead of entire domains. The return directive inside the location block enables you to redirect specific pages to a new location.

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

In the above example, whenever a request URI matches exactly with /tutorial/learning-nginx, NGINX will redirect it to https://example.com/nginx/understanding-nginx/.

You can also redirect everything under a specific path to a new location:

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

NGINX Rewrite directive

We can also use the rewrite directive to rewrite URLs in NGINX. Like the return directive, rewrite can also be placed in the server context as well as in the location context.

The rewrite directive is useful when you need to match and transform URLs using regular expressions. Unlike return, it modifies the request URI and may continue processing depending on the flag used.

The syntax of rewrite directive is:

rewrite regex replacement [flag];
  • regex: A PCRE-based regular expression matched against the request URI (not the full URL)
  • replacement: The URI or URL to replace the matched request
  • flag: Controls how the rewrite is processed

Note: For simple redirects, return is generally preferred over rewrite due to better performance and clarity.

Processing order of rewrite rules

NGINX processes rewrite rules in a specific order:

  1. Rewrite directives in the server context are executed first
  2. NGINX selects the best matching location block
  3. Rewrite directives inside the location block are executed
  4. If the last flag is used, NGINX performs a new location lookup

Understanding this order helps avoid unexpected behavior when multiple rewrite rules are defined.

NGINX Rewrite directive examples

Let us quickly check a few rewrite rules to get you started, starting from rewriting a simple HTML page to another URL:

1. Rewrite static page

Consider a scenario where you want to rewrite a URL for a page, say https://example.com/nginx-tutorial to https://example.com/somePage.html. The rewrite directive to do the same is given in the following location block.

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

Explanation:

  • The location directive location = /nginx-tutorial tells us that the location block will only match with a URL containing the exact match which is /nginx-tutorial.

  • NGINX will look for the pattern ^/nginx-tutorial$ in the requested URL.

  • To define the pattern, the characters ^ and $ are used and have special meaning.

  • ^ represents the beginning of the string to be matched.

  • $ represents the end of the string to be matched.

  • If the requested URI matches the pattern exactly, then somePage.html will be used as a replacement.

  • Since the rewrite rule ends with break, the rewriting also stops, but the rewritten request is not passed to another location.

2. Rewrite dynamic page

Now consider a dynamic page https://www.example.com/user.php?id=11 where the dynamic part is id=11(userid). We want the URL to be rewritten to https://www.example.com/user/11. If you have 10 users then there is a need for 10 rewrite rules for all users if you follow the previous method of rewriting URLs. Instead, it is possible to capture elements of the URL in variables and use them to construct a single rewrite rule that will take care of all the dynamic pages.

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

Explanation:

  • The location directive location /user tells NGINX to match the location block with a URL containing the prefix /user.
  • NGINX will look for the pattern ^/user/([0-9]+)/?$ in the requested URL.
  • The regular expression within square brackets [0-9]+ contains a range of characters between 0 and 9. The + sign signifies matching one or more of the preceding characters. Without the + sign, the above regular expression will match with only 1 character like 5 or 8 but not with 25 or 44.
  • The parentheses ( ) in the regular expression create a capture group (backreference). The $1 in the replacement URL user.php?id=$1 refers to this backreference.

For example, if https://www.example.com/user/24 is the input URL then the user id 24 will match with the range in the backreference resulting in the following substitution: https://www.example.com/user.php?id=24

3. Advanced URL Rewriting

Let us proceed with another example where we want the URL https://www.example.com/user.php?user_name=john to be rewritten to https://www.example.com/user/login/john. Unlike the previous rewrite rule, the dynamic part of the URL user_name=john now contains a range of alphabetic characters. The rewrite rule for this scenario is given below:

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

Explanation:

  • The location directive location /user/login tells NGINX to match the location block with a URL containing the prefix /user/login.
  • NGINX will look for the pattern ^/user/login/([a-z]+)/?$ in the requested URL.
  • The regular expression within square brackets [a-z]+ contains a range of characters between a to z. The + sign signifies matching one or more of the preceding characters. Without the + sign, the above regular expression will match with only 1 character like a or c but not with john or doe.
  • The parentheses ( ) in the regular expression create a capture group (backreference). The $1 in the replacement URL user.php?user_name=$1 refers to this backreference.

For example, if the input URL is https://www.example.com/user/login/john then the user name “john” will match with the range in the backreference resulting in the following substitution: https://www.example.com/user.php?user_name=john

4. Rewrite with multiple backreferences

In this example, we will find out how to rewrite a URL by using multiple backreferences. Let us assume the input URL is https://example.com/tutorial/linux/wordpress/file1 and we want to rewrite the URL to https://example.com/tutorial/linux/cms/file1.php. If you closely look at the input URL, it starts with /tutorial, and somewhere later in the path the string wordpress needs to be replaced with cms. Further, a file extension (.php) also needs to be appended at the end of the filename. The rewrite rule for this scenario is given below:

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

Explanation:

  • The first backreference ^(/tutorial/.*) in the regular expression is used to match any input URL starting with /tutorial/.
  • The second backreference (\w+) is used to capture the file name only without extension.
  • The above two backreferences are used in the replacement URL using $1 and $2.
  • The last flag instructs NGINX to stop processing rewrite directives and perform a new location search.

Rewrite flags

The flag parameter in the rewrite directive controls how NGINX processes the rewrite operation. There are four different flags available, each serving a distinct purpose. Let us examine each flag with practical examples to understand their behavior and appropriate use cases.

The break flag

The break flag tells NGINX to stop processing rewrite rules immediately and use the rewritten URI to serve the request within the current location block.

Consider the following example:

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

When a request comes in for /test, NGINX internally rewrites it to /new and stops processing any further rewrite directives. The rewritten request is not re-evaluated against other location blocks, and the current location continues handling the request.

This flag is particularly useful when you want to rewrite a URL internally while keeping all processing within the same location block. The rewrite is transparent to the client, and the browser’s address bar continues to show the original URL.

The last flag

The last flag works differently from break in that it triggers NGINX to perform a new location search after rewriting the URI.

Here is an example that demonstrates this behavior:

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

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

When a request for /test arrives, NGINX rewrites it to /new and then stops processing rewrite directives in the current location. However, instead of continuing with the current location, NGINX initiates a new search for a location block that matches /new.

In this example, the request will be handled by the /new location block, which returns a 200 status with the message “Handled by /new location”. Use the last flag when the rewritten URI should be processed by a different location block in your configuration.

Important: Improper use of this flag can create infinite loops if the new location triggers another rewrite with the last flag that matches the same pattern.

The redirect flag

The redirect flag instructs NGINX to return an HTTP 302 status code, which signals a temporary redirect to the client.

Consider this example:

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

When a client requests /old, NGINX responds with a 302 Temporary Redirect status and provides the new URL /new in the response. The client’s browser then makes a new request to /new, and the browser’s address bar updates to show the new URL.

Unlike the break and last flags which perform internal rewrites, the redirect flag performs a client-side redirect where the browser is aware of the URL change. This flag is commonly used for temporary URL changes during testing or short-term migrations where you may want to revert the change later.

The permanent flag

The permanent flag is similar to redirect but returns an HTTP 301 status code instead of 302, indicating a permanent redirect.

Here is an example:

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

When a request comes in for /old, NGINX returns a 301 Permanent Redirect status, telling the client that the resource has permanently moved to /new. The client’s browser makes a new request to the new location and updates the address bar accordingly.

More importantly, browsers and search engines cache this redirect, which means future requests to /old may go directly to /new without even contacting your server.

Use the permanent flag for long-term URL changes, especially when migrating content for SEO purposes, as search engines will transfer ranking signals to the new URL. However, use this flag with caution because the cached nature of 301 redirects means any corrections will take time to propagate through caches.

Additional use cases

Apart from the basic URL rewriting scenarios we have covered, there are several other practical applications of NGINX rewrite rules. Let us explore some common use cases that you might encounter in real-world deployments.

SEO-friendly redirects

Consider a scenario where you’re restructuring your website and need to migrate all blog content from the /blog/ path to a new /articles/ path while preserving the entire URL structure. Here’s how you can implement this redirect:

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

This pattern is commonly used when restructuring your site’s content hierarchy. The regex (.*) captures everything after /blog/ in the URI path. Query strings are preserved automatically unless explicitly modified. For example:

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

Using the permanent flag (HTTP 301) is critical for SEO because it signals to search engines that the content has permanently moved, transferring the ranking authority and link equity to the new URLs. This prevents duplicate content penalties and maintains your search engine rankings during URL restructuring.

Reverse proxy rewriting

When using NGINX as a reverse proxy, backend servers may return redirects with internal URLs that are not accessible to external clients. To solve this problem, you need to rewrite these internal URLs to public-facing URLs before sending responses to clients. Here’s the basic configuration:

proxy_redirect http://backend:8080/ /;

This directive is part of NGINX’s proxy module and intercepts the Location and Refresh headers in responses from proxied servers. Here’s how it works:

  • If your backend server (running on http://backend:8080) sends a redirect header like Location: http://backend:8080/dashboard, NGINX will rewrite it to Location: /dashboard before sending the response to the client
  • This prevents clients from seeing or attempting to access internal backend URLs that may not be publicly accessible
  • Without this rewriting, users would see error messages or broken redirects when the backend server tries to redirect them using its internal address
  • The format is: proxy_redirect original_url replacement_url

You can also use variables for more dynamic scenarios:

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

Using map for complex conditions

When you have multiple URL redirects to manage, using individual rewrite rules can become cumbersome and inefficient. The map directive provides a more elegant solution for handling complex conditional redirects. Here’s a basic example:

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

The map directive creates a variable based on pattern matching and is more efficient than multiple if statements or rewrite rules when you have numerous URL mappings. Here’s a more comprehensive example:

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 directives are processed once during configuration loading and stored in hash tables, making lookups extremely fast compared to sequential rewrite rules
  • Maintainability: Centralizes URL mappings in one place rather than scattered across multiple location blocks
  • Flexibility: Supports exact matches, regex patterns (prefix with ~), and default values
  • Conditional logic: The mapped variable can be checked in server or location contexts to conditionally apply redirects

The default "" line sets the value of $new_uri to an empty string when no match is found, which you can then test with an if statement to conditionally perform redirects only for matched URIs.

FAQs

1. What is the difference between the return and rewrite directives in Nginx?

The return directive immediately stops all processing and sends a response or redirect to the client. The rewrite directive modifies the request URI internally and continues processing within NGINX, allowing the rewritten URI to be evaluated against location blocks. Use return for simple redirects as it is faster and more explicit. Use rewrite when you need regex-based URI transformations before NGINX selects the appropriate location block.

2. What do the last and break flags do in a rewrite rule?

The last flag stops processing rewrite directives and initiates a new search for a matching location block using the rewritten URI. The break flag stops processing rewrite directives but continues serving the request within the current location block without re-matching. Think of last as triggering an internal redirect and break as stopping rewrite processing in place. Use last when the rewritten URI should be handled by a different location block, and use break to rewrite the URI while staying in the current location.

3. How do I redirect HTTP to HTTPS in Nginx?

Use a return 301 directive inside a server block listening on port 80:

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

This uses the $host variable to preserve the domain name and $request_uri to preserve the path and query parameters. The client receives a permanent redirect (301) and updates to HTTPS. Avoid using a rewrite rule for this purpose because the return directive is faster and makes your configuration more explicit. The return directive stops processing immediately, while a rewrite rule would continue through the configuration unnecessarily.

4. How do I test Nginx rewrite rules without restarting the server?

Use nginx -t to validate configuration syntax before applying changes. Test redirect behavior with curl -I to see response headers or curl -L to follow redirect chains. For deeper insights, enable rewrite logging by adding rewrite_log on; to your http or server context, then check the NGINX error log at the notice level. The error log will show which rewrite rules are matching and how URIs are being transformed, allowing you to debug without impacting live traffic.

5. Can I use regex capturing groups in Nginx rewrite rules?

Yes, NGINX fully supports regex capturing groups in rewrite rules. When you use parentheses ( ) in your regex pattern, NGINX creates a capturing group that stores the matched portion of the URI. These captured values are available as numbered variables $1, $2, $3, and so on in the replacement string. Here is a practical example:

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

In this rule, the regex pattern (\w+) captures one or more word characters after /user/. If a client requests /user/johndoe, NGINX captures johndoe in $1 and rewrites the URI to /profile.php?username=johndoe. You can use multiple capturing groups in a single pattern and reference each one in the replacement string, making rewrite rules powerful for transforming complex URL structures.

6. When should I use the map directive instead of rewrite rules?

Use map when you have multiple URL mappings that would otherwise require a long chain of rewrite or if statements. NGINX processes map directives during configuration loading and stores mappings in hash tables, making lookups extremely fast. This is ideal for bulk URL mapping scenarios like SEO migrations with dozens or hundreds of redirected URLs. The map directive centralizes all URL mappings in one place, making your configuration cleaner and more maintainable than scattered rewrite rules.

7. What is proxy_redirect and when do I need it?

The proxy_redirect directive rewrites the Location and Refresh headers in responses from upstream servers before sending them to clients. Use it when your backend returns absolute URLs with internal addresses that external clients cannot reach. For example, if your backend sends Location: http://backend:8080/dashboard, use proxy_redirect http://backend:8080/ /; to rewrite it to /dashboard. You can also use variables like proxy_redirect http://backend:8080/ $scheme://$host/; to preserve the client’s original scheme and hostname.

8. Why does my Nginx rewrite rule cause an infinite redirect loop?

Infinite loops occur when the rewritten URI matches the same location block and triggers the same rewrite rule again. For example, rewriting /user to /user/profile in a location block matching /user creates a loop because /user/profile still matches the pattern. To fix this, either use the break flag instead of last to stop rewrite processing without re-evaluating location blocks, or restructure your location regex so the rewritten URI does not match. For instance, use location ~ ^/user/[0-9]+$ to match only specific patterns. Use curl -L to trace redirect chains and identify loop sources.

Summary

In this tutorial, you learned about the two primary directives NGINX provides for URL rewriting. The return directive is preferred for simple redirects because it immediately stops processing and is more efficient. The rewrite directive offers greater flexibility when you need regex-based URL transformations.

You also explored the four rewrite flags. The break flag stops rewrite processing within the current location block, while last initiates a new location search. The redirect and permanent flags return temporary (HTTP 302) and permanent (HTTP 301) redirects to the client, respectively.

For advanced scenarios, you can use proxy_redirect to rewrite redirect headers from upstream servers and the map directive for efficient bulk URL mappings. Understanding NGINX’s processing order—server context first, then location matching, followed by location-specific rewrites—helps you avoid common pitfalls like infinite redirect loops.

To learn more about NGINX, check out the following articles:

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Meghna Gangwar
Meghna Gangwar
Author
Manikandan Kurup
Manikandan Kurup
Editor
Senior Technical Content Engineer I
See author profile

With over 6 years of experience in tech publishing, Mani has edited and published more than 75 books covering a wide range of data science topics. Known for his strong attention to detail and technical knowledge, Mani specializes in creating clear, concise, and easy-to-understand content tailored for developers.

Category:
Tags:

Still looking for an answer?

Was this helpful?

Pretty awesome, but you’ve gramatically described what you want things re-written to incorrectly. you want to rewrite an URL for a page say https://example.com/somePage.html to https://example.com/nginx-tutorial You’re doing the exact opposite in your examples. that applies to all of them. Nice page though

- Peter

How can we add multiple rewrite rules? I’m trying the build the docker image and after copying the file to /etc/nginx the entries are getting deleted and I can see only one rewrite rule.

server {
       listen       8080;
       server_name nginx.com;
       access_log      /opt/www/logs/access.log;
       error_log       /opt/www/logs/error.log;
       access_log off;
       underscores_in_headers on;

       rewrite ^/services/rest/1.0/account/accountnumber/(.*) https://nginx.com//account/services/account/accountnumber/$1 last;
       rewrite ^/services/rest/1.0/user/email/(.*) https://nginx.com/user/services/user/email/$1 last;
       rewrite ^/services/rest/1.0/user/authenticate?(.*)  https://nginx.com/user/services/user/authenticate?$1 last;
       }

- Yograj Patel

Can nginx process multiple rewrite rules for the same request? So we can arrange rules in a hierarchy. # Client calls via version number rewrite /1\.(\d+)/(.*) /oldversion/$1 rewrite/2\.(\d+)/(.*) /newversion/$1 # App1 does not care rewrite /.*/app1DoesNotCare # App2 has 2 versions rewrite/oldversion/app2 /legacyVerApp2 rewrite/newversion/app2 /newVerApp2

- Marc Cawood

As peter said in his comment 6 months ago, these examples are all doing the opposite of what is stated. i.e. Changing B to A, but states how to change A to B… The logic/regex patterns are correct, but it would help to correct the stated intent in each example as I only realised this when working through the logic, but only after doubting myself twice.

- Steven Weston

Can you help me with the configuration for NGINX re-write: Incoming request HTTP://abc.com/a--b--c/ Rewrite URL would be: Http://pqr.com/a/b/syx Incoming request HTTP://abc.com/a--b--d/ Rewrite URL would be: Http://pqr.com/a/b/xyz Notice: I have to use incoming request value c or d and convert it to syx and xyz. Please help with what change I’ll have to make.

- Vivek Jain

Hello, thanks for this great tutorial. I am trying to figure out a redirect pattern that should be probably simple but I can’t make it out from your explanation, so maybe you can help. I need to rewrite many URLs that follow this pattern: https://domainname.com/xxxx/xx/xx/post-title What I am looking to achieve is to strip out the “x” characters in the URL, these are numbers, and redirect to a clean URL that looks so: https://domainname.com/post-title So I understand that I need to both rewrite the URL and also catch the “post-title” which is dynamic and different for each post. Any ideas? Thanks in advance Maurice

- Maurice

Examples 2 and 3 have the regex and the request_url backwards.

- Kobi

where at do you write these rules at nginx? Thanx

- seriously

Hi trying to return 404 for all requests except for when it has /v2/blah example the following should return 404 www.journaldev.com www.journaldev.com/products www.journaldev.com/products/blah but, the following should return 200 OK www.journaldev.com/v2/blah but, the catch is, I cannot touch the location block location / { … } is that possible to do? Have tried everything I know of,( don’t have much experience with nginx)

- Edino

Hi * great tutorial thanks! What if I want to rewrite from https://sub1.domain.com/ to physically https://some-other-domain.com/this/is/important/link.html but the browser should show https://sub1.domain.com/this/is/important/link.html in other words some-other-domain.com needs to be hidden from the public thanks Markus

- Markus Kugler

Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Start building today

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.

Dark mode is coming soon.