Nginx nested location with regex

nginx

I'm trying to apply HTTP auth to most of my site with the exception of the homepage, the path /welcome and separate /admin/, /services/ and /stats/ sections.

I don't appear to be doing this properly; here is my current config:

location ~ ^/(admin|services|stats)/ {   # L1
    # don't need http auth at this path as there is separate auth
    proxy_pass          http://myapp-admin-cluster;
    proxy_redirect      off;
    proxy_set_header    Host $host;
    proxy_set_header    X-Real-IP $remote_addr;
    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header    X-Forwarded-Host $server_name;
}

location / {  #L2
    location ~ /(?!welcome).+ {   #L3
        auth_basic "MyApp";
        auth_basic_user_file /var/www/myapp/htpasswd;
    }
    proxy_pass          http://myapp-web-cluster;
    proxy_redirect      off;
    proxy_set_header    Host $host;
    proxy_set_header    X-Real-IP $remote_addr;
    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header    X-Forwarded-Host $server_name;
}

The problem is if I navigate to /admin/ I get HTTP 404, rather than my request being forwarded to the myapp-admin-cluster proxy (and it also doesn't get forwarded to the myapp-web-cluster proxy).

Q1: Why doesn't the proxy settings defined in the L2 body get applied to paths matching L3?

Q2: Why does the nested location L3 override L1? They are both regex matches so surely it should match the first one? Quote from nginx doc: "Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match"

Best Answer

Because basically the location / will match any url pattern, so when you cannot match the admin string, you will match the rule under the / block.

From your rule L3, you match all the pages except matching /welcome, so you will have redirected to perform basic authentication.

UPDATE:
As the author has updated his question, the location block should be updated and I also suspect Nginx cannot find the which file should be displayed when doing redirect, I suggest to put an index section too:

location ~* ^/(admin|services|stats)/ {
    index index.html;
    ...

Since you are making proxy with the url, you need to have the corresponding file under http://myapp-admin-cluster

For example, we have following URL:

http://<your_webserver_IP or DNS>/admin/1.html

You will be redirected to:

http://myapp-admin-cluster/admin/1.html

But not:

http://myapp-admin-cluster/

Hope it will give you to have some hints to solve your problem.