68

I don't understand the difference between break and last (flags of rewrite). The documentation is rather abstruse. I've tried to switch between the two in some of my configs, but I couldn't spot any difference in behavior. Can someone please explain these flags in more detail? Preferably with an example that shows different behavior when flipping one flag to another.

  • I don't know the answer, but please update the wiki.nginx.org when you get your answer. Also, the English-language nginx mailing list is quite active, and Igor (the main developer) answers hundreds of questions per month, so perhaps ask there. – rmalayter Apr 12 '10 at 02:21
  • @rmalayter - this question was asked on the nginx mailing list. Igor answered it but the answer didn't make much sense to me either: http://www.pubbs.net/nginx/200908/46047/ –  Apr 12 '10 at 22:35
  • pubbs.net link is broken as the domain was taken over. Sorry, was not able to find where it should point. ;( – Tino Aug 09 '12 at 13:01

2 Answers2

80

OP preferred an example. Also, what @minaev wrote, was only a part of the story! So, here we go...

Example 1: No (break or last) flags

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
    }

    location /notes {
        echo 'finally matched location /notes';
    }

    location /documents {
        echo 'finally matched location /documents';
    }

    rewrite ^/([^/]+.txt)$ /notes/$1;
    rewrite ^/notes/([^/]+.txt)$ /documents/$1;
}

Result:

# curl example.com/test.txt
finally matched location /documents

Explanation:

For rewrite, the flags are optional!

Example 2: Outside location block (break or last)

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
    }

    location /notes {
        echo 'finally matched location /notes';
    }

    location /documents {
        echo 'finally matched location /documents';
    }

    rewrite ^/([^/]+.txt)$ /notes/$1 break; # or last
    rewrite ^/notes/([^/]+.txt)$ /documents/$1; # this is not parsed
}

Result:

# curl example.com/test.txt
finally matched location /notes

Explanation:

Outside the location block, both break and last behave in the exact manner...

  • no more parsing of rewrite conditions
  • Nginx internal engine goes to the next phase (searching for location match)

Example 3: Inside location block - "break"

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
        rewrite ^/([^/]+.txt)$ /notes/$1 break;
        rewrite ^/notes/([^/]+.txt)$ /documents/$1; # this is not parsed
    }

    location /notes {
        echo 'finally matched location /notes';
    }

    location /documents {
        echo 'finally matched location /documents';
    }
}

Result:

# curl example.com/test.txt
finally matched location /

Explanation:

Inside a location block, break flag would do the following...

  • no more parsing of rewrite conditions
  • Nginx internal engine continues to parse the current location block

Example 4: Inside location block - "last"

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
        rewrite ^/([^/]+.txt)$ /notes/$1 last;
        rewrite ^/notes/([^/]+.txt)$ /documents/$1;  # this is not parsed
    }

    location /notes {
        echo 'finally matched location /notes';
        rewrite ^/notes/([^/]+.txt)$ /documents/$1;  # this is not parsed, either!
    }

    location /documents {
        echo 'finally matched location /documents';
    }
}

Result:

# curl example.com/test.txt
finally matched location /notes

Explanation:

Inside a location block, last flag would do the following...

  • no more parsing of rewrite conditions
  • Nginx internal engine starts to look for another location match based on the result of the rewrite result.
  • no more parsing of rewrite conditions, even on the next location match!

Summary:

  • When a rewrite condition with the flag break or last matches, Nginx stops parsing any more rewrites!
  • Outside a location block, with break or last, Nginx does the same job (stops processing anymore rewrite conditions).
  • Inside a location block, with break, Nginx only stops processing anymore rewrite conditions
  • Inside a location block, with last, Nginx stops processing anymore rewrite conditions and then starts to look for a new matching of location block! Nginx also ignores any rewrites in the new location block!

Final Note:

I missed to include some more edge cases (actually common problem with rewrites, such as 500 internal error). But, that'd be out of scope of this question. Probably, example 1 is out of scope, too!

Pothi Kalimuthu
  • 5,734
  • 2
  • 24
  • 37
  • **ERROR**: "nginx.service failed because the control process exited with error code."... unknown directive "echo" – Peter Krauss Jul 18 '17 at 11:07
  • https://www.nginx.com/resources/wiki/modules/echo/ . Some Linux distributions such as Ubuntu 14.04 onwards bundle this module in certain packages (such as in nginx-extras). I hope that helps. – Pothi Kalimuthu Jul 18 '17 at 15:42
  • 2
    In example 1 would it make a difference if the rewrite rules were placed above the all three location directives? – Craig Hicks Feb 09 '18 at 04:55
  • 3
    @CraigHicks No, it wouldn't. A rewrite rule has higher precedence and is executed at first before locations are matched. – Pothi Kalimuthu Feb 12 '18 at 16:16
  • Can you possibly put more edge cases into a gist or something, and add a link to it? – x-yuri Jul 22 '19 at 11:10
  • 2
    This should be the best answer. It's easy to understand by referring to these examples, and reading the nginx documentation. – Don Dilanga Aug 15 '19 at 16:08
  • 1
    What about "permanent" ? Is it "permanent break" or "break permanent" or both or neither? – PJ Brunet Feb 20 '20 at 21:20
  • 1
    @PJBrunet As per the official docs that can be seen at https://nginx.org/r/rewrite, // An optional flag parameter can be **one** of last, break, redirect and permanent //. Basically, we can not use more than one flag for rewrite statement. – Pothi Kalimuthu Feb 21 '20 at 07:40
55

You may have different sets of rewrite rules for different locations. When rewrite module meets last, it stops processing the current set and the rewritten request is passed once again to find the appropriate location (and the new set of rewriting rules). If the rule ends with break, the rewriting also stops, but the rewritten request is not passed to another location.

That is, if there are two locations: loc1 and loc2, and there's a rewriting rule in loc1 that changes loc1 to loc2 AND ends with last, the request will be rewritten and passed to location loc2. If the rule ends with break, it will belong to location loc1.

minaev
  • 1,549
  • 12
  • 13