Оптимизация nginx для PHP и Битрикс

Тюним nginx для максимальной производительности: gzip, кэширование, fastcgi_cache, worker_processes, буферы. Production-ready конфигурация.

Дмитрий Мещеряков
Дмитрий Мещеряков
📅 17 июля 2026 г.📖 7 мин чтения

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

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

Базовая структура конфига

nginx
# /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
worker_rlimit_nofile 65535;
pid /run/nginx.pid;
events {
    worker_connections 4096;
    use epoll;
    multi_accept on;
}
http {
    # Базовые настройки
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    keepalive_requests 1000;
    types_hash_max_size 2048;
    server_tokens off;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    # Логи
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    'rt=$request_time uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" urt="$upstream_response_time"';
    access_log /var/log/nginx/access.log main buffer=16k;
    error_log /var/log/nginx/error.log warn;
    # Gzip
    include /etc/nginx/conf.d/gzip.conf;
    # FastCGI Cache
    include /etc/nginx/conf.d/fastcgi-cache.conf;
    # Сайты
    include /etc/nginx/sites-enabled/*;
}

Gzip сжатие

nginx
# /etc/nginx/conf.d/gzip.conf
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 1000;
gzip_types
    text/plain
    text/css
    text/xml
    text/javascript
    application/json
    application/javascript
    application/x-javascript
    application/xml
    application/xml+rss
    application/vnd.ms-fontobject
    application/x-font-ttf
    font/opentype
    image/svg+xml;
💡 Совет

gzip_comp_level: Значение от 1 до 9. Уровень 6 — оптимальный баланс между сжатием и нагрузкой на CPU. Уровень 9 даёт всего на 1-2% лучше сжатие, но в 2-3 раза медленнее.

Как безопасно включить fastcgi_cache

⚠️ Важно

Это самая эффективная и самая опасная настройка в списке. fastcgi_cache кэширует готовый ответ PHP целиком — включая ответ, сформированный для авторизованного пользователя. Без корректного исключения по кукам сессии один посетитель увидит корзину и личные данные другого.

Обязательный минимум: не кэшировать при наличии куки сессии, не кэшировать POST, не кэшировать зону личного кабинета и оформления заказа. И проверить это до выкладки — тем же способом, что и композит: запросить страницу с куками авторизованного пользователя и без них, сравнить ответы.

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

nginx
# /etc/nginx/conf.d/fastcgi-cache.conf
# Зона кэша
fastcgi_cache_path /var/cache/nginx/fastcgi 
    levels=1:2 
    keys_zone=FASTCGI_CACHE:100m 
    inactive=60m 
    max_size=1g
    use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout updating invalid_header http_500 http_503;
fastcgi_cache_background_update on;
fastcgi_cache_lock on;
fastcgi_cache_lock_timeout 5s;
# Не кэшировать для авторизованных
map $http_cookie $no_cache {
    default 0;
    "~*PHPSESSID" 1;
    "~*BITRIX_SM_LOGIN" 1;
    "~*BITRIX_SM_UIDH" 1;
}

Конфиг сайта с кэшированием

nginx
# /etc/nginx/sites-enabled/bitrix.conf
upstream php-fpm {
    server unix:/run/php/php8.2-fpm.sock;
    keepalive 32;
}
server {
    listen 80;
    listen 443 ssl http2;
    server_name example.com www.example.com;
    root /var/www/html;
    index index.php index.html;
    # SSL
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    # HSTS
    add_header Strict-Transport-Security "max-age=31536000" always;
    # Лимиты
    client_max_body_size 100M;
    client_body_buffer_size 128k;
    client_body_timeout 60s;
    client_header_timeout 60s;
    # Статика с долгим кэшем
    location ~* \.(jpg|jpeg|gif|png|svg|webp|ico|css|js|woff|woff2|ttf|eot|pdf)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
        # Открываем CORS для шрифтов
        location ~* \.(woff|woff2|ttf|eot)$ {
            add_header Access-Control-Allow-Origin "*";
        }
    }
    # Запрет служебных файлов
    location ~ /(\.ht|\.git|\.env|\.svn) {
        deny all;
        return 404;
    }
    location ~ ^/(bitrix/\.settings|bitrix/php_interface/dbconn) {
        deny all;
        return 404;
    }
    # Битрикс urlrewrite
    location / {
        try_files $uri $uri/ @bitrix;
    }
    location @bitrix {
        fastcgi_pass php-fpm;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root/bitrix/urlrewrite.php;
        # Кэширование для анонимных
        fastcgi_cache FASTCGI_CACHE;
        fastcgi_cache_valid 200 301 302 10m;
        fastcgi_cache_bypass $no_cache;
        fastcgi_no_cache $no_cache;
        add_header X-Cache-Status $upstream_cache_status;
    }
    # PHP
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass php-fpm;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $document_root;
        # Таймауты
        fastcgi_read_timeout 300s;
        fastcgi_send_timeout 300s;
        fastcgi_connect_timeout 60s;
        # Буферы
        fastcgi_buffer_size 128k;
        fastcgi_buffers 256 16k;
        fastcgi_busy_buffers_size 256k;
        fastcgi_temp_file_write_size 256k;
        # Keepalive
        fastcgi_keep_conn on;
        # Не кэшируем админку
        location ~ ^/bitrix/(admin|tools)/ {
            fastcgi_pass php-fpm;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_cache off;
        }
    }
}

Оптимизация буферов

nginx
# Для больших ответов PHP
fastcgi_buffer_size 128k;
fastcgi_buffers 256 16k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
# Proxy буферы (если есть reverse proxy)
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
⚠️ Важно

Размер буферов: Если видите в логах an upstream response is buffered to a temporary file, увеличьте fastcgi_buffers. Но не ставьте слишком большие значения — это съест память.

Кэширование композитного сайта Битрикс

nginx
# /etc/nginx/sites-enabled/bitrix-composite.conf
# Проверка наличия композитного кэша
map $uri $composite_cache_file {
    default "/bitrix/html_pages${uri}index@.html";
}
server {
    # ... базовые настройки ...
    location / {
        # Сначала проверяем композитный кэш
        if (-f "$document_root$composite_cache_file") {
            rewrite ^ $composite_cache_file last;
        }
        try_files $uri $uri/ @bitrix;
    }
    # Композитные страницы
    location ~ ^/bitrix/html_pages/ {
        internal;
        # Заголовки
        add_header X-Bitrix-Composite "nginx";
        add_header Cache-Control "no-store, no-cache, must-revalidate";
        # Типы контента
        types {
            text/html html;
        }
    }
}

Rate limiting

nginx
# /etc/nginx/conf.d/rate-limit.conf
# Зоны лимитов
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_conn_zone $binary_remote_addr zone=conn:10m;
server {
    # ... 
    # Лимит на API
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        limit_conn conn 10;
        # ... fastcgi ...
    }
    # Строгий лимит на логин
    location = /bitrix/admin/ {
        limit_req zone=login burst=3;
        # ... fastcgi ...
    }
}

Security headers

nginx
# /etc/nginx/conf.d/security.conf
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# CSP (настройте под свой сайт)
# add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;

Как проверить конфигурацию nginx

bash
# Проверить синтаксис
nginx -t
# Перезагрузить без даунтайма
nginx -s reload
# Посмотреть текущие соединения
nginx -V 2>&1 | grep -o with-http_stub_status_module
# Если модуль есть, добавить:
location = /nginx_status {
    stub_status;
    allow 127.0.0.1;
    deny all;
}

Мониторинг производительности

bash
# Топ медленных запросов из лога
awk '{print $NF}' /var/log/nginx/access.log | sort -rn | head -20
# Статистика кодов ответа
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# Запросы в секунду
tail -f /var/log/nginx/access.log | pv -l -i10 -r > /dev/null

Итоги

ПараметрРекомендация
worker_processesauto (= CPU cores)
worker_connections2048-4096
keepalive_timeout65
gzip_comp_level6
fastcgi_buffers256 16k
fastcgi_cache100m-1g

Приведённые значения — отправная точка, а не универсальные константы. На что смотреть при подборе:

worker_processes — по числу ядер (auto делает это сам), worker_connections — по доступной памяти и характеру нагрузки. Увеличивать второе бесполезно, если упирается PHP-FPM: очередь просто переедет на уровень выше.

gzip_comp_level 6 — разумный компромисс. Девятый уровень даёт единицы процентов выигрыша в размере при заметно большей нагрузке на процессор. Если нужен реальный прирост — включайте brotli, а не поднимайте уровень gzip.

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

fastcgi_cache — только с проверенным исключением персональных страниц. Это единственный пункт списка, ошибка в котором приводит к утечке данных, а не к замедлению.

Ограничение частоты запросов настраивайте с burst. Жёсткий лимит без всплеска отсекает нормальных пользователей: обычная страница подтягивает десятки ресурсов почти одновременно.

Заголовки безопасности проверяйте после включения. Content-Security-Policy, добавленный по образцу из статьи, с высокой вероятностью сломает сторонние скрипты — счётчики, чаты, платёжные виджеты. Начинайте с режима отчётов, а не сразу с блокировки.

💡 Совет

И порядок работы, который экономит больше всего времени. Меняйте по одному параметру и измеряйте. Конфиг, собранный из десяти изменений сразу, невозможно откатить осмысленно: когда что-то ломается, вы не знаете, какая именно строка виновата. nginx -t перед каждой перезагрузкой и curl -I после — минимальный цикл проверки.

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

Чем опасен fastcgi_cache на сайте с авторизацией?

Тем, что он кэширует готовый ответ PHP целиком, включая ответ, сформированный для авторизованного пользователя. Без корректного исключения по кукам сессии один посетитель увидит корзину и личные данные другого. Обязательный минимум: не кэшировать при наличии куки сессии, не кэшировать POST-запросы, не кэшировать зону личного кабинета и оформления заказа. И проверить до выкладки: запросить страницу с куками авторизованного пользователя и без них, сравнить ответы.

Как надёжнее описать исключения из fastcgi_cache?

Через обнуление переменной, которую проверяет fastcgi_cache_bypass, а не набором отдельных флагов. Причина в том, что легко завести флаг, аккуратно его выставлять и нигде не проверять, — а ошибка в этом месте означает утечку персональных данных, а не неправильную вёрстку.

Какой уровень gzip выбрать?

Шестой. Значения идут от 1 до 9, и уровень 6 — оптимальный баланс между сжатием и нагрузкой на процессор: девятый даёт всего на 1–2% лучше сжатие, но работает в 2–3 раза медленнее. Если нужен реальный прирост, включайте brotli, а не поднимайте уровень gzip.

Как подобрать worker_processes и worker_connections?

Параметр worker_processes ставится по числу ядер, и значение auto делает это само. worker_connections подбирается по доступной памяти и характеру нагрузки, обычно 2048–4096. Увеличивать его бесполезно, если упирается PHP-FPM: очередь просто переедет на уровень выше, а показатели не изменятся.

Что делать при ошибке об upstream response, записанном во временный файл?

Увеличить fastcgi_buffers: сообщение означает, что ответ PHP не помещается в буфер и nginx пишет его на диск. Но не ставьте слишком большие значения — буферы выделяются на каждое соединение, и это съест память. Отправная точка обычно 256 буферов по 16 килобайт.

Можно ли кэшировать статику на 30 дней?

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