Перейти к содержимому

Двухуровневый веб-сервер вручную - nginx впереди, Apache позади

Разбираем контур из двух веб-серверов, собранный руками без готового окружения. Фронтенд принимает соединения и отдаёт файлы, бэкенд поднимает платформу и выполняет PHP. Смотрим, из каких частей состоит конфигурация и что ломается при половинчатой сборке.

Механика

Рекомендованная схема ручной установки двухуровневая: nginx стоит фронтендом на порту 80, Apache работает бэкендом на внутреннем порту. Фронтенд принимает все соединения снаружи и сам решает, какие ответы отдать без участия PHP.

Роли разделены по типу ответа, а не по адресу страницы сайта. Существующий файл с диска и готовый композитный HTML уходят посетителю прямо с фронтенда. Всё остальное проксируется в апстрим бэкенда, а веб-сокеты - на push-сервер.

Платформу поднимает именно бэкенд: он выполняет PHP и читает файл .htaccess каталога сайта. Человекопонятные адреса он превращает в запрос к файлу /bitrix/urlrewrite.php средствами модуля перезаписи адресов.

Порт бэкенда обязан быть внутренним, иначе два сервера подерутся за приём соединений. В уроках используется 8090: значение меняют в ports.conf на Debian и Astra либо в httpd.conf на РЕД ОС.

Модель процессов бэкенда зависит от способа выполнения PHP и выбирается до раскатки конфигов. При PHP модулем Apache нужен MPM prefork, потому что event с mod_php несовместим. При отдельном обработчике директивы php_value и php_flag из .htaccess становятся невалидными и дают 500.

Конфигурация фронтенда разбита на подключаемые файлы conf.d/*.conf, и у каждого своя зона ответственности. Апстримы описаны в upstreams.conf, композитный кеш в bitrix.conf, статика и внешние хранилища в bitrix_general.conf, защита служебных путей в bitrix_block.conf.

Остальные файлы каталога закрывают обработку ошибок, подписку push-сервера, параметры кеша композита, заголовки CORS и каталог временных файлов. Описание самого сайта живёт отдельно в sites-available, а проксирование на push-сервер - в файле rtc.conf.

Читается конфигурация сверху вниз: основной файл подключает каталог conf.d целиком, а следом описание сайта. Внутри запроса решает совпавший блок location, а не порядок строк в файле. Дальше эстафету принимает бэкенд: сначала свой vhost, потом .htaccess каталога сайта.

К бэкенду приходит соединение от фронтенда, а не от посетителя сайта. Реальный адрес и имя домена передаются заголовками при проксировании, иначе платформа увидит у всех гостей один и тот же локальный адрес. От этого зависят статистика посещаемости, региональность и защита от перебора паролей.

Файлы сайта читают оба сервера, поэтому владелец и группа выбираются общими. Фронтенд работает пользователем nginx в группе apache, права: файлы 0644, каталоги 0755. Те же значения дублируют константами в dbconn.php, чтобы созданные продуктом файлы получали рабочие права.

Шаги

  1. Подготовить бэкенд: сменить порт на внутренний, выбрать модель процессов, включить нужные модули.
  2. Раскатать каталог конфигов фронтенда целиком, а не выборочными файлами из готового архива.
  3. Описать апстрим и сайт: приём соединений на 80, проксирование динамики, отдельный путь для push.
  4. Создать каталог сайта, назначить владельца и права, продублировать те же права константами платформы.
  5. Проверить контур с двух сторон: коды ответа снаружи и записи в журналах обоих серверов.

Код

Готовим бэкенд и его модули:

Окно терминала
a2dismod --force autoindex # листинг каталогов наружу не показываем
a2enmod rewrite # человекопонятные адреса идут через него
a2enmod php # PHP модулем Apache: MPM только prefork
# Listen 8090 в ports.conf (Debian и Astra) или в httpd.conf (РЕД ОС)
# DocumentRoot -> /var/www/html/bx-site в описании виртуального хоста
systemctl --now enable apache2

Порт и модель процессов меняют до первого запуска связки. Оставленный порт 80 не даст подняться фронтенду, а MPM event не уживётся с PHP внутри самого Apache.

Убеждаемся, что порты разошлись:

Окно терминала
ss -lntp | grep -E ':80 |:8090 ' # 80 у фронтенда, 8090 у бэкенда
# прямой запрос к бэкенду мимо фронтенда: отвечает сам сайт
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8090/
tail -5 /var/log/httpd/error_log # на Debian - /var/log/apache2/error.log

Прямой запрос к внутреннему порту отвечает без участия фронтенда. Это делит задачу пополам: сломан контур проксирования или сам сайт на бэкенде.

Описываем апстрим и сайт фронтенда:

upstream httpd { server 127.0.0.1:8090; } # апстрим бэкенда с PHP
server {
listen 80; # фронтенд принимает снаружи
root /var/www/html/bx-site;
include conf.d/bitrix.conf; # композит и статика мимо PHP
location / {
proxy_pass http://httpd;
proxy_set_header Host $host; # домен, а не апстрим
proxy_set_header X-Real-IP $remote_addr; # адрес посетителя
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

Три заголовка при проксировании обязательны: без них бэкенд видит домен апстрима и локальный адрес клиента. Подписку push-сервера обслуживают свои файлы конфигурации, а не этот блок с проксированием динамики.

Раскатываем каталог конфигов целиком:

Окно терминала
rsync -av redos/nginx/ /etc/nginx/ # для Astra - astra/nginx/
nginx -t # синтаксис и наличие подключаемых файлов
systemctl --now enable nginx
ls /etc/nginx/conf.d/ # upstreams, bitrix, bitrix_general, bitrix_block
id nginx # пользователь nginx, группа apache

Выборочная раскатка отдельных файлов - главный источник странного поведения площадки. Без bitrix_block.conf служебные пути остаются открытыми, а без bitrix_general.conf статика и композит отдаются неправильно.

Оставляем на бэкенде правила адресов:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f # существующий файл не трогаем
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !/bitrix/urlrewrite.php$
RewriteRule ^(.*)$ /bitrix/urlrewrite.php [L]
</IfModule>
<IfModule mod_php7.c>
php_flag session.use_trans_sid off # при отдельном обработчике невалидно
</IfModule>

Обёртка по модулю тут не украшение, а страховка на будущее. При переводе PHP на отдельный обработчик директивы внутри обёртки просто не читаются, а те же строки без обёртки роняют сайт в 500.

Создаём каталог сайта и права:

Окно терминала
mkdir -p /var/www/html/bx-site
chown apache:apache /var/www/html/bx-site -R # на Debian - www-data
find /var/www/html/bx-site -type d -exec chmod 0755 {} ';'
find /var/www/html/bx-site -type f -exec chmod 0644 {} ';'

Права 0711 вместо 0755 дают ошибку 500 и молчаливые сбои записи кеша. Владелец каталога обязан совпадать с пользователем, под которым бэкенд выполняет PHP платформы.

Дублируем права константами платформы:

// /bitrix/php_interface/dbconn.php - подключается при каждом запросе
define('BX_FILE_PERMISSIONS', 0644); // права на создаваемые продуктом файлы
define('BX_DIR_PERMISSIONS', 0755); // права на создаваемые каталоги

Без констант платформа создаёт файлы кеша и загрузок с правами по умолчанию. На ручной сборке это регулярно оставляет фронтенду файлы, которые он потом не может прочитать и отдать.

Привязываем push-сервер к контуру:

'pull' => array(
'value' => array(
'path_to_listener' => 'http://#DOMAIN#/bitrix/sub/', // обслуживает фронтенд
'websocket' => 'Y',
'signature_key' => 'PUTTHEPRIVATEKEYHERE', // подставить свой ключ
),
),

Путь /bitrix/sub/ уходит не на бэкенд, а на push-сервер через свои файлы конфигурации фронтенда. Проксирование этого пути в PHP выглядит как вечно отваливающееся соединение с сервером сообщений.

Проверяем контур снаружи:

Окно терминала
# существующий файл: отвечает фронтенд, PHP в цепочке не участвует
curl -sI https://example.com/bitrix/images/main/blank.gif | head -3
# адрес ЧПУ: ответ собирает бэкенд через файл перезаписи адресов
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/catalog/
tail -3 /var/log/nginx/access.log # адрес гостя, а не адрес апстрима

Проверка идёт парой: статика и человекопонятный адрес. Первый запрос показывает работу фронтенда, второй - живой бэкенд с платформой, а журнал подтверждает переданный адрес посетителя.

Ограничения

Ручная сборка не обслуживается меню окружения: смена версии PHP, добавление сайта и выпуск сертификата делаются руками. Готовых пунктов меню здесь нет, и каждое действие оставляет свой след в конфигурации обоих серверов.

Директивы PHP в .htaccess живут только при выполнении PHP модулем Apache. При отдельном обработчике пределы задаются на уровне сервера, и правкой php.ini время выполнения скрипта уже не обходится.

Площадка обязана разрешать чтение .htaccess, иначе адреса ЧПУ и страница ошибки работать не будут. Модули mod_security и suhosin рядом с платформой не используются: они ломают работу продукта.

Требования к PHP проверяют до сборки контура: версия не ниже 8.2, рекомендуется 8.4. Нужен включённый short_open_tag, память от 32 Мб на младшей редакции и от 128 Мб на серьёзных проектах, а акселератор OPcache обязателен.

Два сервера стоят памяти: каждый держит свои процессы и свои пределы на число соединений. Проверка системы показывает тот сервер, под которым выполняется PHP, и на двухуровневой схеме это регулярно сбивает с толку.

Типичные проблемы

Фронтенд не стартует, в журнале сказано, что порт занят.

Бэкенд остался на порту 80 и держит приём соединений за собой. Внутренний порт задают в ports.conf или httpd.conf до раскатки конфигов фронтенда.

После перевода PHP на отдельный обработчик сайт отдаёт 500.

В файле .htaccess остались директивы php_value и php_flag без обёртки по модулю. Они валидны только при PHP модулем Apache, в остальных случаях сервер отвечает ошибкой.

Служебные пути сайта открываются снаружи.

Каталог конфигов раскатали выборочно и пропустили файл с блокировками. Защита служебных путей живёт в bitrix_block.conf, и без этого файла запрет просто не действует.

Тест быстрой отдачи файлов не проходит, картинки идут через PHP.

Не подключён файл, отвечающий за статику и внешние хранилища. Без bitrix_general.conf фронтенд не берёт на себя отдачу файлов и композитных страниц.

В статистике у всех посетителей адрес 127.0.0.1.

Фронтенд проксирует запрос без заголовков с реальным адресом клиента. Платформа честно показывает то, что видит бэкенд: соединение от соседнего процесса.

Сайт отдаёт 500, кеш не пишется, права выглядят странно.

На каталогах стоит 0711 вместо 0755, а владелец не совпадает с процессом PHP. Права выставляют парой 0644 и 0755 и дублируют константами в файле dbconn.php.

Частые вопросы

Проверка пишет, что требуется Apache, а у меня nginx. Это ошибка?

Проверка показывает сервер, под которым выполняется PHP. На двухуровневой схеме это бэкенд, и требование закрывает он; на сборке без Apache предупреждение остаётся, а сайт работает.

Какой порт назначить второму серверу?

Любой внутренний, в уроках это 8090. Главное - увести бэкенд с 80, иначе фронтенд не поднимется и снаружи сайт будет отвечать не тем сервером.

Можно ли накатить только пару нужных файлов конфигурации?

Нет, каталог раскатывают целиком через rsync. Пропущенный файл не даёт ошибки при старте, а проявляется потерей защиты служебных путей или неправильной отдачей статики.

Почему после ручной сборки у всех посетителей один IP?

Бэкенд видит соединение от фронтенда, а не от гостя. Реальный адрес передают заголовками при проксировании, и только после этого работают статистика и защита от перебора.

Чем ручная сборка отличается от готового окружения?

Обслуживанием: версия PHP, новый сайт, сертификат и пулы меняются руками, а не пунктом меню. Взамен площадка не переписывает конфиги при каждом изменении настроек.

Смежное

Первоисточник