webdevops nginx - удалить требование .php из URL-адреса

У меня есть докер, основанный на webdevops/php-nginx:7.2, и я пытаюсь настроить nginx для маршрутизации запросов с расширением .php или без него в соответствующий файл.

Если abc.php существует, мне нужны /abc и /abc.php для маршрутизации к abc.php. Все остальное пойдет на index.php

Текущая установка выглядит так:

Dockerfile содержит

WEB_DOCUMENT_ROOT=/app/public
COPY docker/opt/docker/etc /opt/docker/etc/

opt/docker/etc/nginx/conf.d/10-location-root.conf

server {
  index index.html index.php;
  location / {
    try_files $uri $uri/ /index.php?_url=$uri&$args;
  }
}

/app/public содержит

index.php
abc.php

В настоящее время эта конфигурация направляет все на index.php, кроме /abc.php. Пытаюсь попасть по /abc маршрутам к index.php.

Спасибо :)

Редактировать: Используя ответ Ивана, докер регистрирует спам:

app_1  | -> Executing /opt/docker/bin/service.d/nginx.d//10-init.sh
app_1  | 2020-10-20 10:31:59,273 INFO success: nginxd entered RUNNING state, process has stayed up for > than 0 seconds (startsecs)
app_1  | nginx: [emerg] unknown "_uri" variable
app_1  | 2020-10-20 10:31:59,287 INFO exited: nginxd (exit status 1; not expected)

person Arthur    schedule 19.10.2020    source источник
comment
Можете ли вы добавить к своему вопросу текущую конфигурацию обработчика PHP (обычно что-то вроде location ~ \.php$ { ... })?   -  person Ivan Shatsky    schedule 19.10.2020
comment
Единственная конфигурация для обработки местоположения, которую я использую, — это конфигурация в основном посте (10-location-root.conf). Если установлено что-то еще, то это, вероятно, исходит из образа webdevops: dockerfile.readthedocs.io/en/latest/content/DockerImages/ - я новичок в nginx и ранее использовал apache/htaccess, поэтому я не уверен, где найти эту конфигурацию обработчика php было бы   -  person Arthur    schedule 20.10.2020
comment
Я не знаком с Docker, но знаком с nginx и понимаю, какой конфиг nginx нужен для достижения желаемого. Я просмотрел документы, нашел это на GitHub, и мне кажется, что вы делаете что-то совершенно неправильное. В документации упоминается /opt/docker/etc/nginx/vhost.common.d/10-location-root.conf, а не opt/docker/etc/nginx/conf.d/10-location-root.conf. Я думаю, что ваши модификации вообще не работают.   -  person Ivan Shatsky    schedule 20.10.2020
comment
Например, с вашим конфигом server вы вообще не сможете выполнить какой-либо PHP-скрипт, а если abc.php работает как положено, значит, его обрабатывает какой-то другой конфиг (думаю, дефолтный). Мне кажется, что вам нужно изменить как минимум два файла - /opt/docker/etc/nginx/vhost.common.d/10-location-root.conf и /opt/docker/etc/nginx/vhost.common.d/10-php.conf, возможно, добавить третий пользовательский файл в /opt/docker/etc/nginx/conf.d/, скажем, /opt/docker/etc/nginx/conf.d/maps.conf.   -  person Ivan Shatsky    schedule 20.10.2020
comment
Можете ли вы проверить мой первый вариант? Удалите свой /opt/docker/etc/nginx/conf.d/10-location-root.conf, поставьте вместо него эти два файла и проверьте, как он работает. Оставьте свой /app/public контент как есть.   -  person Ivan Shatsky    schedule 20.10.2020


Ответы (1)


Если я правильно понимаю, как работает эта система, давайте попробуем для начала два следующих файла:

  • /opt/docker/etc/nginx/vhost.common.d/10-location-root.conf
location / {
    try_files $uri $uri/ @extensionless-php;
}
location @extensionless-php {
    rewrite ^ $uri.php last;
}
  • /opt/docker/etc/nginx/vhost.common.d/10-php.conf
location ~ \.php$ {
    try_files $uri /<DOCUMENT_INDEX>?_url=$uri&$args;
    fastcgi_pass php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_read_timeout <PHP_TIMEOUT>;
}

Вышеупомянутая конфигурация имеет один серьезный недостаток. Если запрошенный URI не является именем существующего файла PHP (с расширением .php или без него), значение внутренней переменной $uri nginx всегда будет заканчиваться на .php из-за правила rewrite внутри именованного местоположения @extensionless-php. Это приведет к следующему (при условии, что файл /app/public/some/path.php не существует):

/some/path => /index.php?_url=/some/path.php

/some/path.php => /index.php?_url=/some/path.php

Чтобы решить эту проблему, мы можем сохранить исходное значение переменной $uri внутри именованного местоположения extensionless-php:

  • /opt/docker/etc/nginx/vhost.common.d/10-location-root.conf
location / {
    try_files $uri $uri/ @extensionless-php;
}
location @extensionless-php {
    set $original_uri $uri;
    rewrite ^ $uri.php last;
}
  • /opt/docker/etc/nginx/vhost.common.d/10-php.conf
location ~ \.php$ {
    try_files $uri /<DOCUMENT_INDEX>?_url=$original_uri&$args;
    fastcgi_pass php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_read_timeout <PHP_TIMEOUT>;
}

Эта конфигурация лучше, но все же имеет недостаток. Если запрошенный URI заканчивается на .php и в каталоге /app/public нет соответствующего PHP-файла, переменная $original_uri не будет инициализирована, а аргумент запроса _url будет передан бэкенду в виде пустой строки:

/some/path => /index.php?_url=/some/path

/some/path.php => /index.php?_url=

Это может быть нормально для некоторых веб-приложений (пустой аргумент запроса _url всегда означает недопустимый маршрут), но что нам делать, если мы хотим получить исходный URI, каким бы он ни был? Мы можем добиться этого с помощью директивы map ( чрезвычайно мощная функция nginx). Однако все блоки map должны быть объявлены вне блоков server, поэтому нам понадобится дополнительный файл:

  • /opt/docker/etc/nginx/conf.d/10-map.conf
map $_uri $original_uri {
    ""          $uri;
    default     $_uri;
}
  • /opt/docker/etc/nginx/vhost.common.d/10-location-root.conf
location / {
    try_files $uri $uri/ @extensionless-php;
}
location @extensionless-php {
    set $_uri $uri;
    rewrite ^ $uri.php last;
}
  • /opt/docker/etc/nginx/vhost.common.d/10-php.conf
location ~ \.php$ {
    try_files $uri /<DOCUMENT_INDEX>?_url=$original_uri&$args;
    fastcgi_pass php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_read_timeout <PHP_TIMEOUT>;
}

Этот блок map означает, что переменная $original_uri была бы равна $uri единице, если бы она не была изменена (переменная $_uri не инициализирована и пуста). Если переменная $_uri не пуста, это означает, что исходная переменная $uri была изменена, а переменная $_uri теперь сохраняет свое исходное значение, поэтому значение переменной $original_uri будет установлено на $_uri. Эта конфигурация должна работать с любыми запросами, сохраняющими исходный URI в качестве аргумента запроса _url.

person Ivan Shatsky    schedule 20.10.2020
comment
Привет, Иван, поэтому, когда я использую эти фрагменты, все маршруты не загружаются, и мой журнал докеров забит спамом: app_1 | -> Executing /opt/docker/bin/service.d/nginx.d//10-init.sh app_1 | 2020-10-20 10:31:59,273 INFO success: nginxd entered RUNNING state, process has stayed up for > than 0 seconds (startsecs) app_1 | nginx: [emerg] unknown "_uri" variable app_1 | 2020-10-20 10:31:59,287 INFO exited: nginxd (exit status 1; not expected) - форматирование в комментариях довольно уродливо, поэтому я обновлю свой основной пост. - person Arthur; 20.10.2020
comment
Я попытался заменить переменную $_uri в 10-php.conf только на $uri (не уверен, что это правильно), и раньше у меня было подобное поведение, когда работало только abc.php, а не abc, используя только /abc, мое приложение вылетало с [error] 65#65: *1 could not find named location "@extensionless-php", client: 172.22.0.1, server: _, request: "GET /favicon.ico HTTP/1.1", host: "localhost:8080", referrer: "http://localhost:8080/" - person Arthur; 20.10.2020
comment
@Arthur Плохо, было две опечатки. Исправлено (см. историю редактирования ответов), можете ли вы проверить это сейчас? - person Ivan Shatsky; 20.10.2020
comment
@Arthur Приятно слышать, теперь мы знаем, как изменить конфигурацию nginx внутри докера, но вся настройка еще не завершена. Это была первая попытка проверить, работает ли мой подход, но он передал запрос типа /some/path в качестве аргумента запроса _url=/some/path.php сценарию index.php. Я напишу обновление к ответу, чтобы исправить это, и дам вам знать. - person Ivan Shatsky; 20.10.2020
comment
@ Артур Уф, я закончил. Пожалуйста, дайте отзыв, когда вы протестируете его. Поскольку вы новичок в nginx, я постарался написать максимальное объяснение того, как работает эта конфигурация. Это означает, что он полон различных английских ошибок, поэтому, если вы являетесь носителем английского языка, вы можете исправить некоторые :) (ваш представитель должен разрешить вам редактировать мой ответ, я прав?) - person Ivan Shatsky; 20.10.2020
comment
Спасибо @Ivan, все работает отлично. Ваш английский очень хорош - я только что предложил несколько незначительных исправлений грамматики, но и так все совершенно ясно. - person Arthur; 20.10.2020