70

How do I set a location condition in Nginx that responds to anything that isn't equal to the listed locations?

I tried:

location !~/(dir1|file2\.php) {
   rewrite ^/(.*) http://example.com/$1 permanent;
}

But it doesn't trigger the redirect. It simply handles the requested URI using the rules in the rest of the server configuration.

lalit
  • 3,283
  • 2
  • 19
  • 26
Christiaan
  • 1,051
  • 2
  • 11
  • 20

3 Answers3

92

According to nginx documentation

there is no syntax for NOT matching a regular expression. Instead, match the target regular expression and assign an empty block, then use location / to match anything else

So you could define something like

location ~ (dir1|file2\.php) { 
    # empty
}

location / {
    rewrite ^/(.*) http://example.com/$1 permanent; 
}
Déjà vu
  • 28,223
  • 6
  • 72
  • 100
  • 2
    Worth noting: I needed this to conditionally redirect a hostname and had some more `location`s next to the redirecting one. The redirect wasn't working. Turns out I had to add a `break;` directive as per https://stackoverflow.com/a/14049884 – ᴍᴇʜᴏᴠ Jul 17 '17 at 10:56
  • Unfortunately this does not work when you want to proxy_pass requests in first location because proxy_pass doesn't support regexps – The Godfather Mar 05 '20 at 19:13
  • 4
    I get that the doc says `there is no syntax for NOT matching` however ~ ^/(?!(text or pattern not to match)) is valid regex and more importantly works. – Peter Kahn Mar 06 '20 at 15:24
  • There is a syntax for not matching. And there is a operator that not produces a match with a given subregex – Martin Muñoz Jul 22 '22 at 23:54
  • i want rule, if someone enter "/api/123" it should return 403, everything except "/api/" shoud return 403 – user3782114 Nov 22 '22 at 05:58
86

i was looking for the same. and found this solution.

Use negative regex assertion:

location ~ ^/(?!(favicon\.ico|resources|robots\.txt)) { 
.... # your stuff 
} 

Source Negated Regular Expressions in location

Explanation of Regex :

If URL does not match any of the following path

example.com/favicon.ico
example.com/resources
example.com/robots.txt

Then it will go inside that location block and will process it.

  • 1
    This working well. Example: location ~ (/konference(?!/20)) catch /konference,/konference/images/ NOT catch /konference/2015, /konferece/2015/images tested on Nginx 1.10.2 – Ondrej Prochazka Dec 22 '16 at 12:38
  • How to extract variable if needed? I want to know what is the slug so I can pass it to a proxy pass. – Apoorv Nag Aug 26 '18 at 19:32
  • @ApoorvNag i dont know, try creating new question. thanks –  Aug 28 '18 at 01:47
  • 1
    really useful. EG catch any php file except index `location ~ /public/(?!index.php$)+.*\.php$ { rewrite ^/(.*)$ /public/index.php?url=$1; }` – Kojo Sep 24 '18 at 17:51
  • @AMB Can you provide an explanation of the regex? I didn't get it even after reading the source link. – timekeeper Mar 25 '19 at 22:12
  • @AayushKumarSingha please check updated answer, if you want more explanation, feel free to reply. –  Mar 27 '19 at 05:13
  • This was super helpful, running multiple services in docker behind an nginx. With your post I was able to have a static client at / by tweaking your rule a little. Thanks! location ~ ^/(?!(grafana|gateway)) { root /etc/nginx/html/client; try_files $uri $uri/ /index.html =404; } – Greg Nov 04 '19 at 21:53
  • This should be flagged as the correct answer.it works like a charm using one location block only. – Nicolas Guérinet Apr 08 '21 at 06:36
1

As of 22-JAN-2023, nginx documentation states that !~ and !~* are valid operators, although it doesn't mention since which version they're available. See the documentation reference