Skip to content

Instantly share code, notes, and snippets.

@x-yuri
Last active December 9, 2021 16:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save x-yuri/456723299a9c74688ffe3e41e4b7e4b0 to your computer and use it in GitHub Desktop.
Save x-yuri/456723299a9c74688ffe3e41e4b7e4b0 to your computer and use it in GitHub Desktop.
nginx, if and try_files #nginx #nginx-if #nginx-try_files #nginx-index

nginx, if and try_files

Let's say you want to forbid access to a certain URL unless a certain parameter is passed, and there's a try_files directive:

server {
    server_name localhost;
    root /usr/share/nginx/html;
    try_files $uri /index.html;
    if ($arg_secret-key != 123456) {
        return 404;
    }
}

You do:

$ curl localhost/?secret-key=123456

and receive 404. That happens because try_files makes an internal redirect (/?secret-key=123456 -> /index.html), and as a result loses the parameter. To fix it you must have it this way:

try_files $uri /index.html$is_args$args;

Let's try it inside a location:

server {
    server_name localhost;
    root /usr/share/nginx/html;
    try_files $uri /index.html;
    location = / {
        if ($arg_secret-key != 123456) {
            return 404;
        }
    }
}

This time it finds the location, but there's no try_files there so try_files does nothing. But there's also the index module, which makes a correct internal redirect to /index.html?secret-key=123456. And when try_files is executed for the new request, there's again nothing to do.

If you decide to put try_files into the location as well, then it will redirect it to /index.html but then if won't be applied.

To reproduce:

nginx.conf:

error_log  /var/log/nginx/error.log debug;
server {
    server_name localhost;
    root /usr/share/nginx/html;
    try_files $uri /index.html;
    if ($arg_secret-key != 123456) {
        return 404;
    }
}
$ docker run --rm --name nginx -p 1111:80 -dv $PWD/nginx.conf:/etc/nginx/conf.d/default.conf nginx:alpine nginx-debug -g 'daemon off;'
// launch `docker logs -f nginx` in a separate console, use Enter to separate requests
// processing starts with "generic phase: 0"
$ curl -sS localhost:1111/?secret-key=123456
// change nginx.conf
$ docker exec nginx nginx -s reload
$ curl -sS localhost:1111/?secret-key=123456
...
$ docker stop nginx

Building nginx from source:

$ docker run --rm -it alpine
/ # apk add build-base git pcre-dev zlib-dev
/ # git clone https://github.com/nginx/nginx
/ # cd nginx
/ # auto/configure && make install
/ # /usr/local/nginx/sbin/nginx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment