Местоположение Nginx ведет себя не так, как предполагают документы

У меня есть вопрос о том, как nginx обрабатывает местоположения при вызове try_files. У меня есть стек докеров, который обслуживает приложения Wordpress и phpmyadmin. Мой конфиг ниже:

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;
    }
}

У меня такой вопрос: Почему указанный выше конфиг работает, когда согласно документации nginx здесь работать не должен.

Я понимаю, что при запросе «http://test.com/pma/» должно произойти следующее:

  1. Совпадение с местоположением /pma

  2. try_files $uri = ЛОЖЬ

  3. try_files $uri/ = ЛОЖЬ

  4. Возврат к /index.php

  5. $uri теперь равен: 'http://test.com/pma/index.php'

  6. Обработка перезапущена.

  7. Совпадение с расположением '.php$' внизу.

  8. Он ломается, потому что это неправильное местоположение, а контейнер «php» не имеет доступа к файлам phpmyadmin внутри контейнера «phpmyadmin».

Однако вместо этого, похоже, происходит следующее:

  1. Совпадение с местоположением /pma

  2. try_files $uri = ЛОЖЬ

  3. try_files $uri/ = ЛОЖЬ

  4. Возврат к /index.php

  5. $uri теперь равен: 'http://test.com/pma/index.php'

  6. Обработка продолжается внутри контекста «/pma», который теперь соответствует вложенному блоку местоположения «.php$», который передает запрос на прослушивание FPM внутри контейнера «phpmyadmin».

Я знаю, что должен быть счастлив, что это работает, но меня раздражает, когда все, что я понимаю в nginx, говорит, что это не должно работать.

Очевидно, у меня есть фундаментальное непонимание того, как это работает, и я был бы признателен, если бы кто-нибудь мог указать мне правильное направление.

Спасибо.

Пока Nginx может разрешать и получать доступ phpmyadmin:9000, он должен работать как положено

Chris Haas 23.12.2022 14:06

Это возможно, но проблема заключается во внутреннем перенаправлении, вызванном try_files, когда он переходит к резервному варианту. В этот момент nginx выполняет внутреннее перенаправление и добавляет index.php в конец URI. Затем следует перезапустить обработку, что приведет к совпадению последнего (неправильного) блока местоположения. Вместо этого nginx остается в контексте местоположения «/ pma» и передает запрос в контейнер «phpmyadmin». Это здорово, потому что это работает, но теперь я также понимаю, как должна работать обработка nginx.

the_slug 23.12.2022 14:15

Я все еще не уверен, чего вы ожидаете. Как вы думаете, почему он идет в другой location блок? Запрос имеет префикс /pma, а phpMyAdmin — это приложение с единой точкой входа, которое направляет все запросы через index.php. Таким образом, /pma/config все равно загрузится index.php, который просматривает исходный запрос и вычисляет код для запуска.

Chris Haas 23.12.2022 15:12

Привет, Крис, я ожидаю, что это потерпит неудачу. Я знаю, что nginx входит во вложенный блок местоположения, потому что я могу вставить туда заголовок, а затем проверить заголовок в своем браузере. Как я сказал в первоначальном вопросе, как только файл try_files попадет в блок местоположения /pma, он вернется к index.php, после чего будет перезапущена обработка местоположения, но теперь переменная $uri выглядит так: /pma/index. php. Это должно соответствовать последнему блоку местоположения, который, в свою очередь, не будет работать, потому что контейнер с именем «php» не имеет необходимого содержимого для обслуживания phpmyadmin.

the_slug 23.12.2022 15:26

Но почему вы ожидаете, что он потерпит неудачу? Вот чего я не понимаю. Это потому, что вы думаете, что во втором location ~ \.php$ { блоке есть что-то особенное? Внешний блок /pma обычно направляет запросы к phpMyAdmin, включая статические ресурсы, такие как изображения, а внутренний дополнительно квалифицирует его для поиска только файлов PHP. Кроме того, нет реальной «обработки перезапуска», внутренний наследуется от родителя, который в дальнейшем наследуется от сервера и так далее.

Chris Haas 23.12.2022 15:30

Я ожидаю, что это не удастся, потому что внешний блок местоположения php не будет направляться в контейнер phpmyadmin, он просто перейдет в общий контейнер php-fpm для обработки Wordpress. Nginx по умолчанию всегда перезапускает обработку после внутреннего перенаправления. Неважно, где происходит перезапись, как только это произошло, обработка местоположения перезапускается. Это означает, что наш переписанный URI теперь заканчивается на .php, который будет соответствовать последнему блоку местоположения, который не будет работать, потому что у него нет доступа к phpmyadmin. Однако на самом деле он работает, чего я не понимаю. По своей природе он должен кидать 500/404.

the_slug 23.12.2022 15:43

Вы можете самостоятельно проверить поведение здесь: nginx.viraptor.info Создайте ту же настройку, что и я выше, а затем запросите следующий URL-адрес: test.com/pma/index.php Понимаете, что я имею в виду?

the_slug 23.12.2022 15:48

Извините, я чувствую, что мы говорим кругами, и я надеюсь, что не расстраиваю вас. Я буду игнорировать «контейнеры», потому что Nginx не знает о них. Прокси/пароль - это просто стандартное TCP-соединение. После того, как блок местоположения совпадет, он никогда не выйдет из строя, если не существует правила @. Я не очень понимаю, что такое «внутреннее перенаправление» для Nginx, не уверен, что вы пытаетесь каким-то образом приравнять это к концепциям htaccess, которые «перезапускают». Это что PMA не живет в /var/www/html?

Chris Haas 23.12.2022 19:19

Эй, Крис, не волнуйся, ты меня не расстраиваешь. На самом деле я нашел решение здесь: stackoverflow.com/questions/74140437/… nginx имеет недокументированный способ обработки совпадений вложенных местоположений. Я опубликую ответ ниже, чтобы вы могли его посмотреть.

the_slug 24.12.2022 00:07

Я рад, что вы нашли ответ, но я все еще в замешательстве. Вы не обязаны отвечать, но мне было бы любопытно, можете ли вы опубликовать URL-адрес, который, по вашему мнению, не должен работать, но работает. Блоки местоположения определяются в порядке вложенности, поэтому внешний всегда происходит первым. Как только совпадение /pma определено как лучшее, внутреннее только дополнительно квалифицирует дополнительные потенциальные совпадения. Или мы просто идем дальше! Счастливых праздников!

Chris Haas 25.12.2022 05:39

С Рождеством, Крис! Я разделю свой ответ на два ответа ... Хорошо, поэтому, когда произойдет резервный вариант директивы «try_files», nginx выполнит внутреннюю перезапись. В документах конкретно сказано, что ЗДЕСЬ Конкретно: Если ни один из файлов не был найден, производится внутреннее перенаправление на uri, указанный в последнем параметре. Важность этого заключается в том, что когда nginx обнаруживает перезапись, он немедленно прекращает обработку текущего контекста и перезапускает сопоставление местоположения. Вот почему существует директива break.

the_slug 25.12.2022 19:30

Теперь, поскольку try_files вызвал внутреннее перенаправление, а наш $uri теперь заканчивается на .php, последний блок местоположения (регулярное выражение, проверяющее URI, оканчивающийся на .php) будет совпадать. В официальной документации nginx прямо указано, что это поведение должно происходить ЗДЕСЬ В частности:

the_slug 25.12.2022 19:40

Чтобы найти местоположение, соответствующее заданному запросу, nginx сначала проверяет местоположения, определенные с помощью строк префикса (префиксные местоположения). Среди них выбирается и запоминается местоположение с самым длинным совпадающим префиксом. Затем проверяются регулярные выражения в порядке их появления в конфигурационном файле. Поиск регулярных выражений завершается при первом совпадении_

the_slug 25.12.2022 19:40

Поскольку совпадение регулярного выражения имеет приоритет над соответствием строки префикса, это должен быть блок местоположения, который выбирает nginx, однако это не происходит из-за недокументированного поведения, которое я предоставил в качестве ответа ниже. Вместо этого nginx соответствует самому длинному префиксу, который также содержит внутри себя совпадение с регулярным выражением. На простом английском языке это переводится как: «Дайте мне URI, начинающийся с «/pma» и заканчивающийся на «.php». Нигде в официальной документации это не указано. Это предполагаемое знание, и я никого не смущаю, хотя эта важная информация не должна не быть включенным в документы!

the_slug 25.12.2022 19:42

Крис, я также думаю, что стоит упомянуть, что, хотя вы правы в описанном выше поведении, это то, как nginx обрабатывает блоки местоположения, но моя проблема в том, что это не то поведение, которое можно было бы ожидать, когда вы читаете документы. Буквально нигде не сказано, что nginx выполнит совпадение префикса, затем войдет в это место, а затем попробует найти совпадение с регулярным выражением. Не я один нахожу это упущение странным: artfulrobot.uk/blog/…

the_slug 25.12.2022 19:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
15
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Решение было найдено здесь: https://artfulrobot.uk/blog/untangling-nginx-location-block-matching-algorithm

Конкретно эта часть:

  1. Точная строка соответствует location = /foo
  2. Самая длинная из всех локаций ^~ ... соответствует
  3. Первое совпадение с регулярным выражением, вложенное в один самый длинный совпадающий префикс! См. обсуждение ниже.
  4. Первое другое местоположение соответствия регулярному выражению ~ регулярное выражение
  5. Самый длинный префикс соответствует местоположению /foo

Пункт номер «3» является ответом здесь.

Другие вопросы по теме