HTTP/2 в Apache часто выглядит как «одна директива», но на практике всё решают детали: согласование протокола через ALPN, корректный TLS на нужном виртуальном хосте, и аккуратная связка с PHP-FPM через proxy_fcgi. Ниже — рабочий чек-лист: включение mod_http2, примеры конфигураций и короткий troubleshooting по логам и тестам.
Как Apache договаривается об HTTP/2: h2, h2c и ALPN
HTTP/2 в Apache встречается в двух вариантах:
h2— HTTP/2 поверх TLS. Это основной сценарий для браузеров и публичных сайтов.h2c— HTTP/2 без шифрования. Обычно нужен только во внутренних сетях и в специфичных прокси-схемах.
Для режима h2 критичен механизм ALPN (Application-Layer Protocol Negotiation). Клиент в TLS рукопожатии объявляет поддерживаемые протоколы (например, h2 и http/1.1), а сервер выбирает один и сообщает об этом в ответе. Если ALPN не сработал или Apache не предложил h2, браузер останется на HTTP/1.1 даже при установленном mod_http2.
Типичный симптом: «включил HTTP/2, а в браузере всё равно HTTP/1.1». Чаще всего причина не в
mod_http2, а в TLS/ALPN: не тот vhost на 443, забылиProtocols, либо TLS завершается не на Apache.
Предварительные требования: версии, модули, MPM
Перед настройкой убедитесь, что стек реально поддерживает HTTP/2 и нужные модули загружены:
- Apache с
mod_http2иmod_ssl. - OpenSSL с поддержкой ALPN (в современных дистрибутивах обычно уже так).
- MPM: для связки Apache + PHP-FPM чаще выбирают
mpm_eventилиmpm_worker.mpm_preforkвозможен, но чаще это «наследие» схемы с mod_php и лишает смысла вынос PHP в FPM. - TLS на vhost: корректный сертификат, цепочка, SNI, протоколы и шифры.
Быстрая проверка загруженных модулей
apachectl -M | grep -E 'http2|ssl|proxy|proxy_fcgi|mpm'
В выводе ищите: http2_module, ssl_module, proxy_module, proxy_fcgi_module и один из MPM (часто mpm_event_module).
Если у вас нет валидного сертификата или вы наводите порядок с цепочками и SNI, удобнее сразу держать под рукой нормальные SSL-сертификаты и проверять итоговую конфигурацию после перевыпуска.

Включаем HTTP/2 в Apache: минимальный HTTPS vhost с h2
Практичнее включать HTTP/2 на уровне конкретного SSL-виртуального хоста (порт 443), особенно если на сервере несколько сайтов. Так проще диагностировать, где именно включён h2, и не получить побочные эффекты на других vhost.
Минимальный пример vhost для HTTPS + HTTP/2
Пути и имена файлов — примерные, адаптируйте под свою схему конфигов.
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCertificateKeyFile /etc/ssl/private/example.com.key
SSLCertificateChainFile /etc/ssl/certs/example.com.chain.crt
Protocols h2 http/1.1
DocumentRoot /var/www/example.com/public
ErrorLog ${APACHE_LOG_DIR}/example.com-ssl-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-ssl-access.log combined
</VirtualHost>
Ключевая директива — Protocols. Она явно разрешает h2 на этом vhost. Если модуль загружен, но Protocols не задана (или задана не там), клиент чаще всего останется на HTTP/1.1.
Где задавать Protocols
- Один сайт на сервере: допустимо прописать глобально (в
apache2.confилиhttpd.conf). - Несколько сайтов: лучше в каждом SSL-vhost, чтобы исключить сюрпризы и упростить поддержку.
Apache + PHP-FPM через proxy_fcgi: два рабочих варианта
HTTP/2 работает между клиентом и Apache. PHP-FPM — это бэкенд, до которого Apache ходит по FastCGI. Но проблемы обычно проявляются именно «на стыке»: таймауты, права на сокет, неверная прокладка путей и окружения.
Вариант 1: Unix-сокет (обычно предпочтительнее на одном хосте)
Unix-сокет часто быстрее и проще защитить: доступ ограничивается правами на файл сокета.
<VirtualHost *:443>
ServerName example.com
DocumentRoot /var/www/example.com/public
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCertificateKeyFile /etc/ssl/private/example.com.key
SSLCertificateChainFile /etc/ssl/certs/example.com.chain.crt
Protocols h2 http/1.1
<Directory /var/www/example.com/public>
AllowOverride None
Require all granted
</Directory>
DirectoryIndex index.php index.html
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
</FilesMatch>
ErrorLog ${APACHE_LOG_DIR}/example.com-ssl-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-ssl-access.log combined
</VirtualHost>
Шаблон proxy:unix:...|fcgi://localhost/ чувствителен к мелочам: путь к сокету, версия пула, права доступа. Если видите 503/502 — первым делом проверяйте сокет и права.
Вариант 2: TCP (удобно для разнесения ролей)
TCP проще использовать, когда FPM вынесен на другой хост/контейнер. Но порт обязательно закрывайте от внешнего мира.
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>
Минимальная «гигиена» рядом с FPM
- Явно задайте
DirectoryIndex(например,index.php index.html). - Если используете каталоги загрузок (uploads), запретите выполнение PHP в них отдельным правилом.
- Если
.htaccessне нужен — держитеAllowOverride None(меньше сюрпризов и накладных расходов).
Диагностика HTTP/2 и ALPN: openssl, curl и проверка vhost
Вместо гаданий «работает ли h2» лучше сразу проверять фактическое согласование протокола и то, какой vhost обслуживает домен на 443.
Проверка, какой vhost отвечает на 443
apachectl -t -D DUMP_VHOSTS
Эта команда часто экономит часы: выясняется, что редактировали один файл, а домен реально обслуживается другим vhost (порядок подключения конфигов, дефолтный хост, SNI).
Проверка ALPN через openssl
openssl s_client -connect example.com:443 -servername example.com -alpn h2 -tls1_2
В выводе ищите строку ALPN protocol: h2. Если выбран http/1.1 или ALPN пустой, сервер не согласовал HTTP/2 на этом TLS-хосте.
Проверка протокола ответа через curl
curl -I --http2 https://example.com/
При рабочем HTTP/2 в первой строке ответа будет HTTP/2 (и код ответа).
Если параллельно настраиваете защитные заголовки и хотите закрыть типовые уязвимости «по верхам», полезно свериться с чек-листом по заголовкам: HTTP security headers для Nginx и Apache.
Когда нагрузка растёт и нужно нормально разнести роли (Apache, PHP-FPM, БД, кэш), удобнее делать это на VDS: проще управлять версиями Apache/OpenSSL, MPM и лимитами по процессам/памяти.
Тюнинг производительности: чтобы HTTP/2 не ухудшил отклик
HTTP/2 добавляет мультиплексирование: по одному соединению клиент может держать много параллельных запросов. Это хорошо для фронта, но может быстро упереться в бэкенд.
Согласуйте параллелизм Apache и PHP-FPM
Частая история: включили mpm_event, клиент стал активнее параллелить запросы, а PHP-FPM упирается в маленький pm.max_children. В итоге «h2 есть», но TTFB и общее время ответа хуже.
- Проверьте параметры MPM Apache (число воркеров/потоков и лимиты соединений).
- Проверьте пул PHP-FPM:
pm,pm.max_children,pm.max_requests, таймауты и slowlog.
Таймауты прокси к FPM
Если появляются 504/502, «подвисания» или резкие хвосты по времени, смотрите на таймауты проксирования к FastCGI и реальное время выполнения PHP. На стороне Apache обычно всплывают настройки из семейства ProxyTimeout и аккуратность правила SetHandler или ProxyPassMatch (в зависимости от вашей схемы).
Troubleshooting: типовые проблемы HTTP/2, ALPN и proxy_fcgi
1) HTTP/2 не включается, но ошибок нет
Если клиент остаётся на HTTP/1.1, проверьте по порядку:
- Тестируете именно HTTPS на 443, а не 80.
Protocols h2 http/1.1находится в том vhost, который реально обслуживает домен (SNI, порядок конфигов, дефолтный хост).- TLS завершается на Apache. Если перед ним балансер/прокси — HTTP/2 и ALPN нужно включать и диагностировать на нём.
openssl s_clientпоказываетALPN protocol: h2.
2) В логах есть предупреждения от mod_http2
Сначала убедитесь, что вы смотрите правильные логи именно этого vhost (отдельные ErrorLog/CustomLog на хост сильно упрощают жизнь). Далее проверьте соответствие модулей и выбранного MPM, а также отсутствие конфликтов в протоколах для конкретного хоста.
3) 502/503 при работе PHP через proxy_fcgi
Обычно причина в доступности FPM или в правах на сокет. Базовый набор проверок:
systemctl status php8.3-fpm
ls -la /run/php/
ss -lntp | grep -E ':9000\b'
- Существует ли сокет, и тот ли путь указан в
SetHandler. - Пользователь Apache имеет доступ к сокету (группа/права).
- Если TCP: FPM реально слушает адрес/порт, и порт не открыт наружу.
4) Бесконечные редиректы или путаница http/https
Это не особенность HTTP/2, но часто всплывает после правок вокруг TLS. Если перед Apache есть обратный прокси, проверьте корректность X-Forwarded-Proto и доверие к прокси на стороне приложения/веб-сервера.
5) HTTP/2 работает, но сайт стал медленнее
Чаще всего HTTP/2 просто «ускорил» фронт и проявил реальные ограничения бэкенда:
- Очереди в PHP-FPM из-за малого
pm.max_children. - База данных стала узким местом из-за большего параллелизма.
- Диск/логирование не успевают (особенно на дешёвых или перегруженных хранилищах).
Лекарство одно: измеряйте. Удобно логировать время обработки на уровне Apache (например, добавив %D в формат логов), включать slowlog в PHP-FPM и смотреть метрики БД.

Эталонная основа: HTTP/2 + TLS + PHP-FPM на одном сервере
Ниже базовый каркас, который обычно «заводится» на одном хосте без специфики CMS. Его задача — показать, где включается h2 и как подключается PHP-FPM через proxy_fcgi.
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCertificateKeyFile /etc/ssl/private/example.com.key
SSLCertificateChainFile /etc/ssl/certs/example.com.chain.crt
Protocols h2 http/1.1
<Directory /var/www/example.com/public>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
DirectoryIndex index.php index.html
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
</FilesMatch>
ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>
Финальная проверка после изменений
После правок конфигурации сделайте минимальный набор проверок, чтобы не оставлять «тихие» ошибки:
- Проверка синтаксиса конфигов Apache.
- Проверка, что нужный vhost активен на 443.
- Проверка ALPN и фактического протокола (
h2). - Проверка динамики через PHP (несколько страниц/разделов, авторизация, формы).
apachectl configtest
apachectl -t -D DUMP_VHOSTS
openssl s_client -connect example.com:443 -servername example.com -alpn h2
curl -I --http2 https://example.com/
Итоги
В Apache ключ к HTTP/2 — не просто установка mod_http2, а корректное согласование протокола через ALPN на нужном TLS-vhost и явное разрешение h2 директивой Protocols. Дальше начинается «настоящая жизнь»: HTTP/2 повышает параллелизм, и связка Apache + proxy_fcgi + PHP-FPM должна выдерживать нагрузку без очередей, таймаутов и деградации по отклику. Если что-то не работает — начинайте с DUMP_VHOSTS, проверки ALPN и точечных логов по vhost: это быстрее всего приводит к корню проблемы.


