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