Home > OS >  Nginx location not behaving as the docs suggest
Nginx location not behaving as the docs suggest

Time:12-27

I have a query about the way nginx handles locations when try_files is invoked. I have a docker stack which serves Wordpress and phpmyadmin applications. My config is below:

server {
    listen 80;
    index index.php;
    server_name test.com; # Just a placeholder
    root /code;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location /pma {
        alias /var/www/html;
        index index.php;
        try_files $uri $uri/ /index.php;

        location ~ \.php$ {
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $request_filename;
            fastcgi_pass phpmyadmin:9000;
        }
    }


    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(. \.php)(/. )$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

My question is this: Why does the above config work when according to the nginx documentation here it should not work.

When a request for 'http://test.com/pma/' is made I understand the following should happen:

  1. Match /pma location

  2. try_files $uri = FALSE

  3. try_files $uri/ = FALSE

  4. Fallback to /index.php

  5. $uri now equal to: 'http://test.com/pma/index.php'

  6. Processing is now restarted.

  7. Match '.php$' location at the bottom.

  8. It breaks because this is the wrong location and the 'php' container doesn't have access to the phpmyadmin files inside the 'phpmyadmin' container.

However, instead what appears to happen is this:

  1. Match /pma location

  2. try_files $uri = FALSE

  3. try_files $uri/ = FALSE

  4. Fallback to /index.php

  5. $uri now equal to: 'http://test.com/pma/index.php'

  6. Processing continues inside the '/pma' context, which now matches the nested '.php$' location block, which passes the request to FPM listening inside the 'phpmyadmin' container.

I know I should be happy that it works, but it's bugging me when everything I understand about nginx says this shouldn't work.

Obviously I have some fundamental misunderstanding about the way this works, and I'd appreciate it if someone could point me in the right direction.

Thank you.

CodePudding user response:

Solution was found here: https://artfulrobot.uk/blog/untangling-nginx-location-block-matching-algorithm

Specifically this part:

  1. Exact string matches location = /foo
  2. The longest of any location ^~ ... matches
  3. The first regex match that is nested within the single longest matching prefix match! See discussion below.
  4. The first other regex match location ~ regex
  5. The longest prefix match location /foo

Point number '3' is the answer here.

  • Related