Skip to content

Instantly share code, notes, and snippets.

@nuga99
Last active June 26, 2019 08:42
Show Gist options
  • Save nuga99/c95463829174c88a3827f63f6d0c852e to your computer and use it in GitHub Desktop.
Save nuga99/c95463829174c88a3827f63f6d0c852e to your computer and use it in GitHub Desktop.
Nginx Learning Resources

Resources: https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/

Introduction Problem to If in Nginx is (Evil).

The only 100% safe things which may be done inside if in a location context are:

return ...;
rewrite ... last;

What to do instead Use try_files if it suits your needs. Use the “return ...” or “rewrite ... last” in other cases. In some cases, it’s also possible to move ifs to server level (where it’s safe as only other rewrite module directives are allowed within it).

E.g. the following may be used to safely change location which will be used to process request:

if ($request_method = POST ) {
  return 405;
}
if ($args ~ post=140){
  rewrite ^ http://example.com/ permanent;
}

Examples Here are some examples which explain why if is evil. Don’t try this at home. You were warned.

Here is collection of unexpectedly buggy configurations to show that

if inside location is evil.

only second header will be present in response

not really bug, just how it works

location /only-one-if {
    set $true 1;

    if ($true) {
        add_header X-First 1;
    }

    if ($true) {
        add_header X-Second 2;
    }

    return 204;
}

request will be sent to backend without uri changed

to '/' due to if

location /proxy-pass-uri {
    proxy_pass http://127.0.0.1:8080/;

    set $true 1;

    if ($true) {
        # nothing
    }
}

try_files wont work due to if

location /if-try-files {
     try_files  /file  @fallback;

     set $true 1;

     if ($true) {
         # nothing
     }
}

nginx will SIGSEGV

location /crash {

    set $true 1;

    if ($true) {
        # fastcgi_pass here
        fastcgi_pass  127.0.0.1:9000;
    }

    if ($true) {
        # no handler here
    }
}

alias with captures isn't correcly inherited into implicit nested

location created by if

location ~* ^/if-and-alias/(?<file>.*) {
    alias /tmp/$file;

    set $true 1;

    if ($true) {
        # nothing
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment