У меня есть вопрос о том, как 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/» должно произойти следующее:
Совпадение с местоположением /pma
try_files $uri = ЛОЖЬ
try_files $uri/ = ЛОЖЬ
Возврат к /index.php
$uri теперь равен: 'http://test.com/pma/index.php'
Обработка перезапущена.
Совпадение с расположением '.php$' внизу.
Он ломается, потому что это неправильное местоположение, а контейнер «php» не имеет доступа к файлам phpmyadmin внутри контейнера «phpmyadmin».
Однако вместо этого, похоже, происходит следующее:
Совпадение с местоположением /pma
try_files $uri = ЛОЖЬ
try_files $uri/ = ЛОЖЬ
Возврат к /index.php
$uri теперь равен: 'http://test.com/pma/index.php'
Обработка продолжается внутри контекста «/pma», который теперь соответствует вложенному блоку местоположения «.php$», который передает запрос на прослушивание FPM внутри контейнера «phpmyadmin».
Я знаю, что должен быть счастлив, что это работает, но меня раздражает, когда все, что я понимаю в nginx, говорит, что это не должно работать.
Очевидно, у меня есть фундаментальное непонимание того, как это работает, и я был бы признателен, если бы кто-нибудь мог указать мне правильное направление.
Спасибо.
Это возможно, но проблема заключается во внутреннем перенаправлении, вызванном try_files, когда он переходит к резервному варианту. В этот момент nginx выполняет внутреннее перенаправление и добавляет index.php в конец URI. Затем следует перезапустить обработку, что приведет к совпадению последнего (неправильного) блока местоположения. Вместо этого nginx остается в контексте местоположения «/ pma» и передает запрос в контейнер «phpmyadmin». Это здорово, потому что это работает, но теперь я также понимаю, как должна работать обработка nginx.
Я все еще не уверен, чего вы ожидаете. Как вы думаете, почему он идет в другой location
блок? Запрос имеет префикс /pma
, а phpMyAdmin — это приложение с единой точкой входа, которое направляет все запросы через index.php. Таким образом, /pma/config
все равно загрузится index.php
, который просматривает исходный запрос и вычисляет код для запуска.
Привет, Крис, я ожидаю, что это потерпит неудачу. Я знаю, что nginx входит во вложенный блок местоположения, потому что я могу вставить туда заголовок, а затем проверить заголовок в своем браузере. Как я сказал в первоначальном вопросе, как только файл try_files попадет в блок местоположения /pma, он вернется к index.php, после чего будет перезапущена обработка местоположения, но теперь переменная $uri выглядит так: /pma/index. php. Это должно соответствовать последнему блоку местоположения, который, в свою очередь, не будет работать, потому что контейнер с именем «php» не имеет необходимого содержимого для обслуживания phpmyadmin.
Но почему вы ожидаете, что он потерпит неудачу? Вот чего я не понимаю. Это потому, что вы думаете, что во втором location ~ \.php$ {
блоке есть что-то особенное? Внешний блок /pma
обычно направляет запросы к phpMyAdmin, включая статические ресурсы, такие как изображения, а внутренний дополнительно квалифицирует его для поиска только файлов PHP. Кроме того, нет реальной «обработки перезапуска», внутренний наследуется от родителя, который в дальнейшем наследуется от сервера и так далее.
Я ожидаю, что это не удастся, потому что внешний блок местоположения php не будет направляться в контейнер phpmyadmin, он просто перейдет в общий контейнер php-fpm для обработки Wordpress. Nginx по умолчанию всегда перезапускает обработку после внутреннего перенаправления. Неважно, где происходит перезапись, как только это произошло, обработка местоположения перезапускается. Это означает, что наш переписанный URI теперь заканчивается на .php, который будет соответствовать последнему блоку местоположения, который не будет работать, потому что у него нет доступа к phpmyadmin. Однако на самом деле он работает, чего я не понимаю. По своей природе он должен кидать 500/404.
Вы можете самостоятельно проверить поведение здесь: nginx.viraptor.info Создайте ту же настройку, что и я выше, а затем запросите следующий URL-адрес: test.com/pma/index.php Понимаете, что я имею в виду?
Извините, я чувствую, что мы говорим кругами, и я надеюсь, что не расстраиваю вас. Я буду игнорировать «контейнеры», потому что Nginx не знает о них. Прокси/пароль - это просто стандартное TCP-соединение. После того, как блок местоположения совпадет, он никогда не выйдет из строя, если не существует правила @
. Я не очень понимаю, что такое «внутреннее перенаправление» для Nginx, не уверен, что вы пытаетесь каким-то образом приравнять это к концепциям htaccess, которые «перезапускают». Это что PMA не живет в /var/www/html
?
Эй, Крис, не волнуйся, ты меня не расстраиваешь. На самом деле я нашел решение здесь: stackoverflow.com/questions/74140437/… nginx имеет недокументированный способ обработки совпадений вложенных местоположений. Я опубликую ответ ниже, чтобы вы могли его посмотреть.
Я рад, что вы нашли ответ, но я все еще в замешательстве. Вы не обязаны отвечать, но мне было бы любопытно, можете ли вы опубликовать URL-адрес, который, по вашему мнению, не должен работать, но работает. Блоки местоположения определяются в порядке вложенности, поэтому внешний всегда происходит первым. Как только совпадение /pma определено как лучшее, внутреннее только дополнительно квалифицирует дополнительные потенциальные совпадения. Или мы просто идем дальше! Счастливых праздников!
С Рождеством, Крис! Я разделю свой ответ на два ответа ... Хорошо, поэтому, когда произойдет резервный вариант директивы «try_files», nginx выполнит внутреннюю перезапись. В документах конкретно сказано, что ЗДЕСЬ Конкретно: Если ни один из файлов не был найден, производится внутреннее перенаправление на uri, указанный в последнем параметре. Важность этого заключается в том, что когда nginx обнаруживает перезапись, он немедленно прекращает обработку текущего контекста и перезапускает сопоставление местоположения. Вот почему существует директива break.
Теперь, поскольку try_files вызвал внутреннее перенаправление, а наш $uri теперь заканчивается на .php, последний блок местоположения (регулярное выражение, проверяющее URI, оканчивающийся на .php) будет совпадать. В официальной документации nginx прямо указано, что это поведение должно происходить ЗДЕСЬ В частности:
Чтобы найти местоположение, соответствующее заданному запросу, nginx сначала проверяет местоположения, определенные с помощью строк префикса (префиксные местоположения). Среди них выбирается и запоминается местоположение с самым длинным совпадающим префиксом. Затем проверяются регулярные выражения в порядке их появления в конфигурационном файле. Поиск регулярных выражений завершается при первом совпадении_
Поскольку совпадение регулярного выражения имеет приоритет над соответствием строки префикса, это должен быть блок местоположения, который выбирает nginx, однако это не происходит из-за недокументированного поведения, которое я предоставил в качестве ответа ниже. Вместо этого nginx соответствует самому длинному префиксу, который также содержит внутри себя совпадение с регулярным выражением. На простом английском языке это переводится как: «Дайте мне URI, начинающийся с «/pma» и заканчивающийся на «.php». Нигде в официальной документации это не указано. Это предполагаемое знание, и я никого не смущаю, хотя эта важная информация не должна не быть включенным в документы!
Крис, я также думаю, что стоит упомянуть, что, хотя вы правы в описанном выше поведении, это то, как nginx обрабатывает блоки местоположения, но моя проблема в том, что это не то поведение, которое можно было бы ожидать, когда вы читаете документы. Буквально нигде не сказано, что nginx выполнит совпадение префикса, затем войдет в это место, а затем попробует найти совпадение с регулярным выражением. Не я один нахожу это упущение странным: artfulrobot.uk/blog/…
Решение было найдено здесь: https://artfulrobot.uk/blog/untangling-nginx-location-block-matching-algorithm
Конкретно эта часть:
Пункт номер «3» является ответом здесь.
Пока Nginx может разрешать и получать доступ
phpmyadmin:9000
, он должен работать как положено