Skip to main content

Implementing Rewrite Rules

1. Using Rewrite Directive

Directive Syntax Description Notes
rewrite rewrite <regex> <replacement> [last|break|redirect|permanent] Applies a regular expression to the request URI and rewrites it Can be used in server, location, and if contexts

Example: Basic Rewrite Rule

location /old-page.html {
    rewrite ^/old-page\.html$ /new-page.html last;
}

Example: Rewrite with Capture Groups

location /user/ {
    rewrite ^/user/([^/]+)/?$ /profile.php?user=$1 last;
}
Note: The last flag stops processing and re-evaluates the location block with the new URI.
Warning: Inefficient regex patterns can cause performance issues. Always test rewrite rules carefully.

2. Understanding Rewrite Flags

Flag Description Usage
last Stops processing further rewrite rules if this rule matches. rewrite ^/old-path(.*)$ /new-path$1 last;
break Stops processing further rewrite rules but continues with the current location. rewrite ^/old-path(.*)$ /new-path$1 break;
redirect Returns a 302 redirect to the new URL. rewrite ^/old-path(.*)$ /new-path$1 redirect;
permanent Returns a 301 permanent redirect to the new URL. rewrite ^/old-path(.*)$ /new-path$1 permanent;

Example: Using last flag

location /old-path {
    rewrite ^/old-path(.*)$ /new-path$1 last;
}

Example: Using redirect flag

location /old-path {
    rewrite ^/old-path(.*)$ /new-path$1 redirect;
}

3. Using Return Directive

Directive Parameters Description
return code [text] or code url Stops processing and returns a response with the specified code and optional content or redirects to a URL

Example: Simple 404 Response

location /old-page {
    return 404 "Page not found";
}

Example: Permanent Redirect

location /old-url {
    return 301 https://example.com/new-url;
}
Note: The return directive is processed before any other directives in the location block.
Warning: Using return with a URL that includes variables like $uri can lead to unexpected behavior or infinite loops if not handled carefully.

4. Implementing 301 Redirects

Directive Parameters Description
rewrite ^/old-path/(.*)$ /new-path/$1 permanent Performs a 301 redirect using the permanent flag

Example: Basic 301 Redirect

rewrite ^/old-page$ /new-page permanent;

Example: Redirect with Capture Group

rewrite ^/blog/(.*)$ /posts/$1 permanent;
Note: The permanent flag ensures the redirect is a 301 (permanent) redirect, which is beneficial for SEO.

5. Implementing 302 Redirects

Directive Values Description
rewrite ^/old-path/(.*)$ /new-path/$1 permanent Performs a 302 redirect with the permanent flag
return 302 /new-path Redirects with 302 status code to a new path

Example: Basic 302 Redirect

location /old-page {
    return 302 /new-page;
}

Example: Redirect with Regex Capture

location ~ ^/products/(.*)$ {
    return 302 /items/$1;
}
Note: The return 302 directive is used for temporary redirects. For permanent redirects, use return 301.

6. Creating Conditional Rewrites

Directive Parameters Description
if $variable = value Checks if a variable matches a specific value
if $variable != value Checks if a variable does not match a specific value
if !$variable Checks if a variable is empty or not set
if $variable ~ regex Checks if a variable matches a regular expression (case-sensitive)
if $variable !~ regex Checks if a variable does not match a regular expression (case-sensitive)
if $variable ~* regex Checks if a variable matches a regular expression (case-insensitive)

Example: Conditional Redirect Based on User Agent

location / {
    if ($http_user_agent ~* "Mobile") {
        return 301 /mobile;
    }
    proxy_pass http://backend;
}

Example: Conditional Rewriting Based on IP Address

location / {
    if ($remote_addr ~ "^192\.168\.1\.") {
        rewrite ^/(.*)$ /internal/$1 permanent;
    }
    proxy_pass http://backend;
}
Note: The if directive is evaluated at runtime and can impact performance. Use it sparingly.
Warning: Be cautious with complex regex patterns in if directives as they can lead to unexpected behavior or performance issues.

7. Using Regex Captures

Group Description Example
\$1 First captured group rewrite ^/user/([^/]+)/posts/(.*)$ /user/$1/posts/$2;
\$2 Second captured group rewrite ^/([a-z]+)/(\d+)/(.*)$ /$1/$3?id=$2;
\$0 Entire matched string rewrite ^/old/(.*)$ /new/$0;

Example: Capturing and Redirecting

location /old/ {
    rewrite ^/old/([^/]+)/(.*)$ /new/$1/$2 permanent;
}
Note: The \$1, \$2, etc., refer to the captured groups in the regex pattern. These are used to reconstruct parts of the URL during rewriting.

8. Rewriting with Query String

Directive Description Example
rewrite Performs a rewrite using a regular expression and replacement string. Can include query strings in the replacement. rewrite ^/old-path/(.*)$ /new-path/$1?arg=value&other=123 last;
return Can be used to redirect with a query string. return 301 /new-path?arg=value&other=123;

Example: Rewrite with Query String

location /old-path/ {
    rewrite ^/old-path/(.*)$ /new-path/$1?arg=value&other=123 last;
}
Note: Query strings in the replacement are handled by Nginx, but care must be taken to properly escape special characters like & and ?.

9. Testing Conditions

Condition Description Example
-f Tests if the file exists if (-f $request_filename) { return 403; }
-d Tests if the directory exists if (-d $document_root$uri) { return 403; }
-e Tests if the file or directory exists if (-e $request_filename) { return 200; }
-x Tests if the file is executable if (-x $request_filename) { return 403; }
-s Tests if the file size is greater than zero if (-s $request_filename) { return 403; }
-z Tests if the file size is zero if (-z $request_filename) { return 403; }
-r Tests if the file is readable if (-r $request_filename) { return 403; }
-w Tests if the file is writable if (-w $request_filename) { return 403; }
-o Tests if the file is owned by the current user if (-o $request_filename) { return 403; }
-l Tests if the file is a symbolic link if (-l $request_filename) { return 403; }
-L Tests if the file is a symbolic link (alias for -l) if (-L $request_filename) { return 403; }
-N Tests if the file is not a regular file (e.g., directory or symlink) if (-N $request_filename) { return 403; }
-T Tests if the file is a text file if (-T $request_filename) { return 403; }
-B Tests if the file is a binary file if (-B $request_filename) { return 403; }
-u Tests if the file is owned by a user with UID if (-u $request_filename) { return 403; }
-g Tests if the file is owned by a group with GID if (-g $request_filename) { return 403; }
-h Tests if the file is a hidden file (starts with dot) if (-h $request_filename) { return 403; }
-p Tests if the file is a pipe or FIFO if (-p $request_filename) { return 403; }
-S Tests if the file is a socket if (-S $request_filename) return 403; }
-D Tests if the file is a directory if (-D $request_filename) { return 403; }
-F Tests if the file is a regular file if (-F $request_filename) { return 403; }
-U Tests if the file is a Unix domain socket if (-U $request_filename) { return 403; }
-X Tests if the file is executable (alias for -x) if (-X $request_filename) { return 403; }
-R Tests if the file is readable (alias for -r) if (-R $request_filename) { return 403; }
-W Tests if the file is writable (alias for -w) if (-W $request_filename) { return 403; }
-O Tests if the file is owned by the current user (alias for -o) if (-O $request_filename) { return 403; }
-E Tests if the file or directory exists (alias for -e) if (-E $request_filename) { return 403; }
-C Tests if the file is a character device if (-C $request_filename) { return 403; }
-M Tests if the file is a block device if (-M $request_filename) { return 403; }
-A Tests if the file is a named pipe (FIFO) if (-A $request_filename) { return 403; }
-Z Tests if the file is a zero-length file if (-Z $request_filename) { return 403; }
-G Tests if the file is a group-readable file if (-G $request_filename) { return 403; }
-P Tests if the file is a pipe or FIFO (alias for -p) if (-P $request_filename) { return 403; }
-Q Tests if the file is a queue (not supported in most systems) if (-Q $request_filename) { return 403; }
-V Tests if the file is a virtual file (e.g., /dev/null) if (-V $request_filename) { return 403; }
-K Tests if the file is a kernel module if (-K $request_filename) { return 403; }
-I Tests if the file is an image (not supported in most systems) if (-I $request_filename) { return 403; }
-J Tests if the file is a journal file (not supported in most systems) if (-J $request_filename) { return 403; }
-H Tests if the file is a hard link (not supported in most systems) if (-H $request_filename) { return 403; }
-F Tests if the file is a regular file (alias for -f) if (-F $request_filename) { return 403; }
-T Tests if the file is a text file (alias for -T) if (-T $request_filename) { return 403; }
-B Tests if the file is a binary file (alias for -B) if (-B $request_filename) { return 403; }
-N Tests if the file is not a regular file (alias for -N) if (-N $request_filename) { return 403; }
-L Tests if the file is a symbolic link (alias for -l) if (-L $request_filename) { return 403; }
-S Tests if the file is a socket (alias for -S) if (-S $request_filename) { return 403; }
-D Tests if the file is a directory (alias for -d) if (-D $request_filename) { return 403; }
-U Tests if the file is a Unix domain socket (alias for -U) if (-U $request_filename) { return 403; }
-X Tests if the file is executable (alias for -x) if (-X $request_filename) { return 403; }
-R Tests if the file is readable (alias for -r) if (-R $request_filename) { return 403; }
-W Tests if the file is writable (alias for -w) if (-W $request_filename) { return 403; }
-O Tests if the file is owned by the current user (alias for -o) if (-O $request_filename) { return 403; }
-E Tests if the file or directory exists (alias for -e) if (-E $request_filename) { return 403; }
-C Tests if the file is a character device (alias for -C) if (-C $request_filename) { return 403; }
-M Tests if the file is a block device (alias for -M) if (-M $request_filename) { return 403; }
-A Tests if the file is a named pipe (FIFO) (alias for -A) if (-A $request_filename) { return 403; }
-Z Tests if the file is a zero-length file (alias for -Z) if (-Z $request_filename) { return 403; }
-G Tests if the file is a group-readable file (alias for -G) if (-G $request_filename) { return 403; }
-P Tests if the file is a pipe or FIFO (alias for -p) if (-P $request_filename) { return 403; }
-Q Tests if the file is a queue (not supported in most systems) (alias for -Q) if (-Q $request_filename) { return 403; }
-V Tests if the file is a virtual file (e.g., /dev/null) (alias for -V) if (-V $request_filename) { return 403; }
-K Tests if the file is a kernel module (alias for -K) if (-K $request_filename) { return 403; }
-I Tests if the file is an image (not supported in most systems) (alias for -I) if (-I $request_filename) { return 403; }
-J Tests if the file is a journal file (not supported in most systems) (alias for -J) if (-J $request_filename) { return 403; }
-H Tests if the file is a hard link (not supported in most systems) (alias for -H) if (-H $request_filename) { return 403; }

Example: Testing file existence

location / {
    if (!-f $request_filename) {
        return 404;
    }
}

Example: Testing directory existence

location / {
    if (!-d $document_root$uri) {
        return 403;
    }
}

Example: Testing file size

location / {
    if (-s $request_filename) {
        return 403;
    }
}

Example: Testing file permissions

location / {
    if (!-r $request_filename) {
        return 403;
    }
}
location / {
    if (-l $request_filename) {
        return 403;
    }
}

Example: Testing file type

location / {
    if (-F $request_filename) {
        return 403;
    }
}

Example: Testing directory type

location / {
    if (-D $request_filename) {
        return 403;
    }
}

Example: Testing file ownership

location / {
    if (!-o $request_filename) {
        return 403;
    }
}

Example: Testing file executable permissions

location / {
    if (!-x $request_filename) {
        return 403;
    }
}

Example: Testing file writable permissions

location / {
    if (!-w $request_filename) {
        return 403;
    }
}

Example: Testing file readable permissions

location / {
    if (!-r $request_filename) {
        return 403;
    }
}

Example: Testing file zero-length

location / {
    if (-z $request_filename) {
        return 403;
    }
}

Example: Testing file not readable

location / {
    if (-R $request_filename) {
        return 403;
    }
}

Example: Testing file not writable

location / {
    if (-W $request_filename) {
        return 403;
    }
}

Example: Testing file not executable

location / {
    if (-X $request_filename) {
        return 403;
    }
}

Example: Testing file not owned by current user

location / {
    if (-O $request_filename) {
        return 403;
    }
}

Example: Testing file not a regular file

location / {
    if (-N $request_filename) {
        return 403;
    }
}

Example: Testing file not a directory

location / {
    if (-D $request_filename) {
        return 403;
    }
}

Example: Testing file not a socket

location / {
    if (-S $request_filename) {
        return 403;
    }
}

Example: Testing file not a pipe or FIFO

location / {
    if (-P $request_filename) {
        return 403;
    }
}

10. Preserving Query Strings

Directive Description Example
rewrite Applies a rewrite rule; use $args to preserve query strings rewrite ^/old-path/(.*)$ /new-path/$1?$args? permanent;
return Redirects with query string preservation using $args return 301 /new-path/$1?$args?;

Example: Rewrite with Query String Preservation

location /old-path/ {
    rewrite ^/old-path/(.*)$ /new-path/$1?$args? permanent;
}
Note: The $args variable contains the query string. Appending ? after $args ensures it's preserved in the rewrite.

11. Using Rewrite Log

Example: Enabling Rewrite Logging

server {
    listen 80;
    server_name example.com;

    error_log /var/log/nginx/rewrite.log debug;

    location / {
        rewrite ^/old-path/(.*)$ /new-path/$1 permanent;
    }
}
Directive Description Default
error_log Specifies the log file and level for rewrite logging error_log /var/log/nginx/error.log error;
debug Log level to capture rewrite operations error_log /var/log/nginx/error.log debug;
Note: The debug level logs all rewrite operations, which can be very verbose and impact performance in production environments.

12. Understanding Rewrite vs Return

Directive Description Behavior Use Case
rewrite Modifies the URI internally and continues processing Internal redirect, can be used in server/location context URL normalization, path manipulation
return Stops processing and sends a response to the client Immediate HTTP response (301, 302, etc.) Permanent redirects, custom error pages

Example: Using rewrite

location /old-path {
    rewrite ^/old-path(.*)$ /new-path$1 permanent;
}

Example: Using return

location /old-path {
    return 301 /new-path;
}

Comparison: rewrite vs return

  • rewrite: Modifies URI and continues processing
  • return: Sends immediate response, stops processing
  • rewrite: Can be used for internal redirects
  • return: Used for external redirects or custom responses

Was this article helpful?