Обратный прокси Nginx к удаленному серверу php-fpm с fastcgi

Вопрос или проблема

У меня есть 2 экземпляра AWS EC2, один из которых находится в публичной подсети и настроен как NAT экземпляр, и выполняет Nginx. Другой экземпляр находится в частной подсети, но может взаимодействовать с публичным. Соответствующие IP-адреса экземпляров, например:

  • 172.25.48.14 – экземпляр Nginx в публичной подсети (172.25.48.0/28), имеет присвоенный Elastic IP
  • 172.25.48.140 – экземпляр, выполняющий php-fpm в частной подсети (172.25.48.128/28)

Дело в том, что я хочу, чтобы этот веб-сайт был доступен по определенному URL – я предполагал, что Nginx будет действовать как обратный прокси-сервер, который сопоставляет запросы к определенным поддоменам или URL соответствующим ресурсам. И вот моя конфигурация Nginx:

http {
    sendfile on;
    tcp_nopush on;
    types_hash_max_size 2048;
    server_names_hash_bucket_size 128;

    include /etc/nginx/mime.types;
    default_type text/html;

    proxy_headers_hash_bucket_size;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    server {
        listen 80;

        location ~ ^/site1(.*)$ {
            # Эти строки закомментированы, поскольку вне зависимости от того, указаны они или нет, результат остается тем же
            # index index.php;
            # try_files $uri $uri/ /site1/index.php?$request_uri;
            location ~ \.php$ {
                include fastcgi.conf;
                try $uri =404;

                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass 172.25.48.140:9000;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include fastcgi_params;
            }
        }
    }
}

А вот, соответственно, конфигурация пула php-fpm для сайта в частном экземпляре:

[site1]
user = www-data
group = www-data
listen = 172.25.48.140:9000
listen.allowed_clients = 172.25.48.14, 172.25.48.140, 127.0.0.1
php_admin_value[disable_functions] = exec, passthru, shell_exec, system
php_admin_flag[allow_url_fopen] = off
pm = dynamic
pm.max_children = 10
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 8
pm.process_idle_timeout = 30s
pm.status_path = /php_status
ping.path = /ping
ping.response = wrrrrrrrrryyyyyyyyyyy
access.log = /var/log/php/8.3/$pool.access.log
access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{milli}d %{kilo}M %C%%"

Для простоты, давайте предположим, что у меня есть всего один index.php файл, который также расположен в частном экземпляре по адресу /apps/site1/, который имеет символическую ссылку на /var/www/html/site1.

Проблема в том, что, что бы я ни пробовал, я получаю 404, и судя по логам на стороне частного экземпляра, запрос даже не доходит туда – хотя я знаю, что группы безопасности экземпляра настроены правильно и на нужных портах, потому что в противном случае я могу подключаться от частного экземпляра к публичному и наоборот без каких-либо проблем. Единственный случай, когда я смог передать запрос на php-fpm (хотя тоже 404), был, когда я переместил углубленный “location” (тот, который соответствует .php скриптам) на верхний уровень сервера – так что, по сути, запрос пошел прямо на 172.25.48.14, а не на 172.25.48.14/site1, как я предполагал.

Я что-то упускаю? Может быть, проблема в том, что исходные файлы находятся на том же экземпляре, что и php-fpm, а не на стороне Nginx? Я неправильно понимаю, как это работает? Пожалуйста, если у вас есть какие-либо идеи по этому поводу, я буду крайне благодарен за вашу помощь. Спасибо заранее!

  1. Ваша конфигурация, проверяемая с помощью команды nginx -t, должна выдавать сообщение об ошибке, такое как

    nginx: [emerg] unknown directive "try" in ...
    

    из-за строки

    try $uri =404;
    

    Если это должно быть

    try_files $uri =404;
    

    то это также не сработает. Это заставляет nginx проверять ваш URI запроса как физический файл относительно корня вашего веб-сервера (который вообще не определен), очевидно, что это не сработает (так как ваш PHP файл находится на другом хосте). Эта строка должна быть удалена из вашего вложенного местоположения.

  2. Поскольку вы не явно определили корень вашего веб-сайта, по умолчанию он равен {prefix}/html, где {prefix} является некоторым предварительно скомпилированным значением (можно посмотреть с помощью команды nginx -V). Так что все, что вы передаете на ваш частный экземпляр через

    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    

    скорее всего, неверно. Вам следует использовать либо

    root /apps/site1;
    

    либо

    root /var/www/html/site1;
    

    внутри вашего вложенного местоположения (хотя я не знаю, как PHP-FPM будет обрабатывать пути с включенными символическими ссылками).

  3. Как уже говорилось на StackOverflow:

    У вас есть вложенное местоположение, которое обрабатывает запросы .php, но похоже, что вы не запрашиваете фактический PHP файл в вашем тестовом URL. Типичный шаблон будет иметь директиву try_files, которая пытается загрузить запрашиваемый файл / каталог на диске или вернуться к маршрутизации запроса через файл index.php как фронтальный контроллер. Похоже, у вас этого нет.

    Добавьте либо

    try_files $uri /site1/index.php$is_args$args;
    

    либо

    error_page 404 = /site1/index.php$is_args$args;
    

    в ваше родительское местоположение.

  4. Вам не нужно использовать обе

    include fastcgi.conf;
    

    и

    include fastcgi_params;
    

    в вашем вложенном местоположении. Они почти одинаковы, единственное отличие заключается в том, что файл fastcgi.conf включает строку

    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    

    в то время как fastcgi_params не включает ее (если вы используете файл fastcgi_params вместо fastcgi.conf, вы должны включить эту строку сами).

  5. Любые вещи, связанные с PATH_INFO, такие как

    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    

    не имеют смысла в location ~ \.php$ { ... } местах (в отличие от location ~ \.php(?:/|$) { ... }).

  6. Почему бы не использовать простое префиксное местоположение, такое как

    location /site1/ {
        ...
    }
    

    или

    location ^~ /site1/ {
        ...
    }
    

    ? Особенно если вы все равно не используете группу захвата регулярного выражения.

Ответ или решение

Настройка обратного прокси Nginx для удаленного сервера PHP-FPM с FastCGI в AWS

В этой инструкции рассмотрим, как правильно настроить обратный прокси Nginx на экземпляре AWS EC2, который будет направлять запросы на удаленный сервер PHP-FPM, расположенный в частной подсети. У вас уже настроены два экземпляра EC2: один работает в публичной подсети и содержит Nginx, а другой выполняет PHP-FPM в частной подсети.

Шаг 1: Правильная конфигурация Nginx

Ваш исходный конфигурационный файл Nginx, судя по всему, нуждается в доработке. Следует обратить внимание на несколько деталей:

  1. Корневая директория (root)

    Укажите корневую директорию для вашего приложения. В вашем случае приложение находится в /apps/site1, поэтому в конфигурации Nginx необходимо добавить:

    location /site1/ {
       root /apps/site1;
       # Другие параметры...
    }
  2. Настройка обработки PHP файлов

    Вы правильно предполагаете использовать FastCGI для обработки PHP. Однако у вас есть ошибка в конфигурации. Замените:

    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

    на

    fastcgi_param SCRIPT_FILENAME $document_root/site1$fastcgi_script_name;

    Это гарантирует, что Nginx правильно найдет ваш файл index.php.

  3. Использование try_files

    Добавьте директиву try_files, которая будет проверять существование запрашиваемого файла или перенаправлять на index.php:

    location /site1/ {
       try_files $uri /site1/index.php$is_args$args;
       # Настройки для обработки PHP...
    }

Шаг 2: Конфигурация PHP-FPM

Ваша конфигурация пула PHP-FPM также требует внимания. Убедитесь, что он слушает только на интерфейсе, который доступен для Nginx (в вашем случае 172.25.48.140:9000):

[site1]
listen = 172.25.48.140:9000
listen.allowed_clients = 172.25.48.14, 127.0.0.1

Шаг 3: Устранение ошибок и отладка

  1. Логи Nginx

    Убедитесь, что используете логи доступа и ошибки Nginx, чтобы видеть, какие запросы обрабатываются и какие ошибки возникают. Они находятся по указанному вами пути:

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
  2. Логи PHP-FPM

    Также проверьте логи PHP-FPM, чтобы убедиться, что запросы фактически доходят до сервера PHP-FPM. Лог может находиться по пути:

    /var/log/php/8.3/site1.access.log

Шаг 4: Проверка и тестирование

После внесения всех изменений перезапустите Nginx и PHP-FPM:

sudo systemctl restart nginx
sudo systemctl restart php-fpm

Затем проверьте:

  1. Доступность http://<your-elastic-ip>/site1/index.php.
  2. Правильность работы и отсутствие ошибок 404.

Заключение

Обработка запросов через Nginx в качестве обратного прокси на сервер PHP-FPM может быть тонким процессом, требующим внимания к деталям конфигурации. Проверьте правильность указанных путей, необходимых параметров и логов для диагностики. Удачи в настройке!

Оцените материал
Добавить комментарий

Капча загружается...