01 01234567890 01234567890

Настройка Nginx и PHP-FPM для коробочного Битрикс24 в продакшене

Серверы 01 сентября 2026
~11 минут чтения 15 333 символа 7 просмотров

Расчёт пула воркеров под реальную память сервера, таймауты, кеш статики и разбор, откуда берутся ошибки 502 и 504 под нагрузкой

Пятница, вечер, отдел продаж массово выгружает отчёты перед закрытием месяца — и портал начинает отдавать 502 через раз. В логе php-fpm при этом одна и та же строка: server reached pm.max_children setting, consider raising it. Классическая история: сервер настраивали по гайду для тестового стенда, а под продакшен-нагрузку параметры пула никто не пересчитывал. Ниже — как настроить Nginx и PHP-FPM для коробочного Битрикс24 так, чтобы это не повторялось: версии PHP, расчёт пула под объём RAM, схема связки с Apache или без неё, кэш статики и разбор, почему вообще возникают 502 и 504.

Материал для разработчика или админа, который уже поднял портал (сам или через BitrixEnv) и теперь донастраивает его под реальную нагрузку, а не под установочный мастер.

Что понадобится

  • Доступ к серверу по SSH с правами root или sudo.
  • Уже установленный коробочный Битрикс24 — через BitrixEnv или руками. Если портала ещё нет, сначала разверните его на облачном сервере, это отдельная задача.
  • Информация о ресурсах сервера: количество ядер, объём RAM, тип диска. Без этих цифр расчёт пула — гадание.
  • Понимание, сколько человек одновременно работает в портале и есть ли внешняя нагрузка (сайт на 1С-Битрикс, вебхуки, интеграции, REST API от внешних систем).
  • Доступ к конфигурации PHP-FPM и Nginx. В BitrixEnv это /etc/nginx/bx/ и пул в /etc/opt/php83/php-fpm.d/ (путь зависит от версии PHP, устанавливаемой через BitrixEnv).

Настройка Nginx и PHP-FPM для коробочного Битрикс24 в продакшене: разбираем по шагам

Шаг 1. Выбираем схему: nginx + apache или nginx + php-fpm напрямую

BitrixEnv по умолчанию ставит связку nginx-фронт + Apache-бэкенд с mod_php: nginx отдаёт статику и проксирует динамику на Apache, который уже выполняет PHP-код. Это рабочая и поддерживаемая схема, и трогать её без причины не обязательно — она хорошо интегрирована в меню /root/menu.sh, и обновления окружения не ломают то, что не тронуто руками.

Вторая схема — Nginx напрямую перед PHP-FPM, без Apache. Она быстрее под нагрузкой: меньше слоёв, ниже расход памяти на процесс (у Apache prefork каждый воркер тяжелее, чем worker php-fpm), проще диагностика — один лог вместо двух. Такой вариант встречается и в материалах вендора, но это не операция из стандартного меню BitrixEnv — конфиги придётся вести руками, и здесь та же ловушка, что и с любой ручной правкой: следующая операция в меню (например, смена сайта или перевыпуск сертификата) может перегенерировать nginx-конфиг и затереть кастомные location.

Наш подход: если сервер один и им управляют через BitrixEnv — оставляем Apache-бэкенд, но переносим его на PHP-FPM вместо mod_php (Apache 2.4 с mod_proxy_fcgi это умеет), выигрывая по памяти без отказа от привычного меню. Если сервер выделенный, под высокую нагрузку, и конфиги ведутся в git — переходим на чистую связку nginx + php-fpm. Дальше показываю оба пути, различия — только в звене между nginx и PHP.

Шаг 2. Ставим PHP нужной версии

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

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

Через BitrixEnv версия PHP ставится и переключается через /root/menu.sh → пункт управления версиями PHP; окружение само разводит несколько версий по путям вида /opt/php83, /opt/php84, чтобы можно было тестировать новую версию, не ломая текущий сайт.

Обязательные для продакшена настройки в php.ini:

; Отключаем проверку времени модификации файлов на каждый запрос —
; в продакшене код не меняется "на лету", это чистый выигрыш по CPU
opcache.validate_timestamps = 0

; Память под закэшированный байт-код. Для Битрикс24 с его объёмом кода
; 256M — комфортный минимум, на проекте с кастомными модулями поднимайте до 512M
opcache.memory_consumption = 256

; Число файлов, которые может держать в кэше opcache.
; У коробки легко набирается 15-20 тысяч php-файлов с учётом модулей
opcache.max_accelerated_files = 30000

; Кэш резолвинга путей — портал активно ходит по include-цепочкам
realpath_cache_size = 4096K
realpath_cache_ttl = 600

; Лимит памяти на процесс. 256M хватает на большинство страниц,
; тяжёлые отчёты и импорт CRM могут требовать 512M
memory_limit = 256M

; Время выполнения обычного запроса. Для fpm-процессов, которые
; висят дольше (агенты, экспорт) — отдельный пул с большим значением
max_execution_time = 60

При opcache.validate_timestamps = 0 не забывайте, что после деплоя кода нужно сбрасывать кэш (opcache_reset() через админку или перезапуск php-fpm) — иначе увидите старую версию файлов ещё несколько часов.

Шаг 3. Настраиваем пул PHP-FPM: расчёт pm.max_children под RAM

Это узкое место, из-за которого чаще всего ловят 502. По умолчанию во многих дистрибутивах pm.max_children стоит на символических 5, что для одного разработчика достаточно, а для десяти сотрудников — нет.

Логика простая: сколько параллельных PHP-процессов может выдержать оставшаяся память сервера, столько и ставим. Формула:

pm.max_children = (RAM_доступная_под_php_fpm) / (средний_размер_процесса)

RAM под php-fpm — это не вся память сервера, а то, что останется после MySQL (innodb_buffer_pool_size), memcached/Redis, push-сервера, nginx/apache и системных нужд. Средний размер процесса php-fpm под коробкой обычно 50-90 МБ RSS — админка и CRM тяжелее типовой страницы каталога, берите верхнюю границу для запаса.

Пример для сервера на 8 ГБ RAM (10-15 человек): MySQL — 2,5 ГБ, memcached и push — 0,5 ГБ, nginx/система — 1 ГБ, остаётся около 4 ГБ под php-fpm. При среднем процессе 70 МБ получаем 4096 / 70 ≈ 58. Ставим с запасом вниз, не под самый край:

; Пул для основного сайта портала, файл вида
; /etc/opt/php83/php-fpm.d/www.conf или отдельный пул в conf.d/bitrix24.conf

[bitrix24]
user = bitrix
group = bitrix
listen = /var/run/php-fpm/bitrix24.sock
listen.owner = nginx
listen.group = nginx

; dynamic — процессы плодятся и схлопываются по нагрузке,
; для продакшена это разумный баланс между памятью и откликом
pm = dynamic

; Верхний предел параллельных процессов — по расчёту выше
pm.max_children = 50

; Сколько процессов держим постоянно живыми, не пересоздавая
pm.start_servers = 10
pm.min_spare_servers = 8
pm.max_spare_servers = 20

; После скольки запросов процесс перезапускается —
; защита от накопления памяти при утечках в коде модулей
pm.max_requests = 500

; Таймаут, после которого fpm сам убьёт зависший запрос
; и запишет его в slowlog — держите чуть меньше nginx-таймаута
request_terminate_timeout = 60
request_slowlog_timeout = 10
slowlog = /var/log/php-fpm/bitrix24-slow.log

; Отдельный статус-эндпоинт для мониторинга загрузки пула
pm.status_path = /fpm-status

pm.max_children = 50 — это не универсальная цифра, а результат расчёта под конкретные 8 ГБ и конкретную нагрузку. На 16 ГБ с тем же профилем нагрузки получится порядка 100-120, но проверяйте по факту через pm.status_path, а не только по формуле — реальный размер процесса скачет в зависимости от того, какие модули и REST-обработчики активны.

Частая ошибка на этом шаге: поднять pm.max_children до заоблачных значений, чтобы «уж точно хватило», без пересчёта под RAM. Сервер уходит в своп при пиковой нагрузке, и вместо быстрого 502 вы получаете вариант хуже — портал висит по 30-60 секунд, а потом всё равно падает в 504.

Шаг 4. Настраиваем Nginx как фронт

Если сохраняете связку с Apache — nginx только проксирует динамику на Apache и отдаёт статику сам, это конфигурация BitrixEnv по умолчанию, трогать её незачем. Если переходите на прямую связку с php-fpm, ключевой блок такой:

# Апстрим на unix-сокет php-fpm, отдельный пул под Битрикс24
upstream php_bitrix24 {
    server unix:/var/run/php-fpm/bitrix24.sock;
}

server {
    listen 443 ssl;
    http2 on; # с nginx 1.25.1 http2 включается отдельной директивой,
              # а не параметром listen — старый синтаксис пишет предупреждение в лог
    server_name portal.company.ru;

    root /home/bitrix/www;
    index index.php;

    # Сертификат подключаем через шаблоны BitrixEnv, не переопределяем вручную
    include /etc/nginx/bx/ssl.conf;

    location / {
        try_files $uri $uri/ /bitrix/urlrewrite.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_pass php_bitrix24;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        # Таймаут ожидания ответа от php-fpm — держим чуть больше
        # request_terminate_timeout из пула, иначе nginx оборвёт раньше fpm
        fastcgi_read_timeout 65;
        fastcgi_send_timeout 65;

        # Клиент мог закрыть вкладку — не убиваем скрипт из-за этого,
        # актуально для длинных импортов и бизнес-процессов
        fastcgi_ignore_client_abort on;
    }

    # Статус пула php-fpm — закрываем от внешнего доступа
    location = /fpm-status {
        allow 127.0.0.1;
        deny all;

        fastcgi_pass php_bitrix24;
        include fastcgi_params;
        # без SCRIPT_FILENAME статус не отдаётся: php-fpm не понимает,
        # что от него хотят, и возвращает "Access denied" или пустой ответ
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
}

Обратите внимание на fastcgi_ignore_client_abort on — без него разрыв соединения на стороне клиента (человек закрыл вкладку, пока грузился длинный отчёт) моментально убивает php-процесс, и фоновая операция, которая должна была доработать, обрывается на середине.

Шаг 5. Настраиваем кэширование статики

Каталог /bitrix/js, /bitrix/css, /upload, /bitrix/templates — это то, что нагружает канал, но не должно каждый раз идти через php вообще, и даже через nginx лишний раз ходить незачем:

location ~* \.(js|css|png|jpg|jpeg|gif|svg|woff2?|ttf|ico)$ {
    root /home/bitrix/www;

    # Браузер и CDN кэшируют файл на 30 дней —
    # у Битрикс24 в путях статики есть версионирование (?v=...),
    # поэтому долгий кэш не приводит к показу устаревшего файла
    expires 30d;
    add_header Cache-Control "public, immutable";

    # Не пишем в access_log каждый запрос картинки —
    # на нагруженном портале это ощутимая экономия дисковых IOPS
    access_log off;

    # gzip для текстовых форматов статики
    gzip_static on;
}

Если у вас включено ускорение сайта (композитный кэш) в настройках производительности портала, анонимные посетители внешнего сайта на этом же движке вообще не доходят до PHP — nginx отдаёт готовый HTML из кэша композита. Для внутреннего портала Битрикс24 это не так критично: сотрудники всегда авторизованы, композит на них не работает, и всю нагрузку по-прежнему держит пул php-fpm.

Частые ошибки и как их избежать

502 Bad Gateway при заходе нескольких человек одновременно. Пул php-fpm исчерпан: все pm.max_children заняты, новые запросы получают отказ в соединении. В логе php-fpm ищите server reached pm.max_children setting, consider raising it — если строка есть, лечится либо пересчётом пула под RAM (шаг выше), либо поиском, что именно держит процессы дольше нормы (медленный внешний API, необновлённая версия модуля с известной утечкой).

504 Gateway Timeout на тяжёлых операциях. fastcgi_read_timeout в nginx меньше, чем реально нужно операции — экспорту, синхронизации с 1С, тяжёлому отчёту. Nginx обрывает соединение раньше, чем php успевает досчитать. Решение — не задирать таймаут глобально, а вынести тяжёлые location (например, /bitrix/admin/, ваш REST-обработчик синхронизации) в отдельный location с увеличенным fastcgi_read_timeout, оставив короткий таймаут для обычных страниц.

Портал работает нормально днём и тормозит по вечерам, когда все выгружают отчёты. Это тот же дефицит пула, но проявляется не как жёсткий 502, а как рост времени ответа: свободные pm.max_children заканчиваются, запросы встают в очередь на уровне сокета. Диагностируется через pm.status_path — смотрите на listen queue и max children reached, если счётчик растёт — пул мал для этой нагрузки.

После перехода на php-fpm выросло число ошибок подключения к MySQL. Каждый php-fpm процесс может держать соединение с базой, и увеличенный pm.max_children умножает нагрузку на max_connections в MySQL. Расчёт пула под RAM должен учитывать не только память php, но и то, что MySQL тоже может упереться в лимит соединений при резком росте числа воркеров.

Из практики А2

На одном из проектов сервер под коробку выдавали через инфраструктурный отдел клиента — 4 ядра, 16 ГБ RAM, конфигурация приличная. Но пул php-fpm стоял с дефолтными настройками дистрибутива, pm.max_children = 5. Портал на 8 человек работал терпимо, потому что редко когда пять человек одновременно грузили страницу с тяжёлым отчётом. Проблема вылезла ровно в момент подключения интеграции с внешней 1С через REST API: каждый синхронизационный запрос занимал php-процесс на несколько секунд, и уже при трёх параллельных запросах от 1С плюс двух активных сотрудниках пул забивался полностью — сотрудники получали 502 в моменты синхронизации.

Пересчитали пул под фактическую память (после вычета MySQL и push-сервера осталось около 9 ГБ), подняли pm.max_children до 90 и вынесли обработчик REST-синхронизации в отдельный пул с меньшим pm.max_requests, чтобы не смешивать долгие интеграционные запросы с обычными пользовательскими — так падение одного пула не задевало второй.

Отдельно всплыла деталь с opcache.validate_timestamps: в первой конфигурации его оставили включённым «на всякий случай», и при активной разработке (в проекте шли доработки прямо на проде — не лучшая практика, но так было) каждый php-запрос дополнительно стучался в файловую систему проверять время модификации сотен файлов. На SSD это было незаметно поодиночке, но при возросшем числе параллельных процессов давало ощутимую просадку по CPU. Отключили timestamp-проверку и добавили в процесс деплоя явный сброс opcache — время отклика админки заметно выровнялось.

Ещё одно наблюдение: клиенты часто путают связку «nginx перед Apache» с «nginx вместо Apache» и просят убрать Apache просто ради красивой схемы в презентации. Если сервер и так не упирается в память, а конфиги ведутся через меню BitrixEnv — миграция на чистый php-fpm ради экономии 200-300 МБ памяти того не стоит, риск сломать что-то в момент перехода выше выгоды. Смысл появляется, когда сервер реально упирается в ресурсы или когда нужна тонкая настройка таймаутов по отдельным location, которую через Apache делать неудобно.

Итог

После этой настройки у вас пул PHP-FPM, рассчитанный под реальный объём памяти сервера, а не под дефолтные значения дистрибутива, Nginx с кэшируемой статикой и разумными таймаутами, и понимание, откуда берутся 502 и 504 под нагрузкой. Дальше стоит понаблюдать за pm.status_path в течение недели-двух в реальной работе и подкорректировать pm.max_children по факту — формула даёт стартовую точку, а не окончательное число. Если на каком-то шаге застряли — опишите ситуацию в комментарии или напишите нам напрямую.

Азамат

Азамат

Основатель «А Квадрат»

Работаю в web-деве с 2014 года. Прошел путь от фрилансера до фрилансера-руководителя))

Остались вопросы? Мы можем помочь!

Настройка уведомлений в Битрикс24: как не пропустить важное
Следующая статья 01.09.2026