HTTP/2 в Apache обычно «не заводится» не из-за одного параметра, а из-за цепочки: модуль mod_http2 должен быть загружен, на TLS-уровне должно сработать согласование протокола через ALPN, а backend (PHP) обязан выдерживать выросшую параллельность запросов.
Зачем HTTP/2 в Apache и при чём тут ALPN
Когда говорят «включить HTTP/2», чаще всего имеют в виду HTTP/2 в браузерах. Для браузеров это почти всегда «h2 поверх TLS», и ключевой элемент здесь — ALPN (Application-Layer Protocol Negotiation).
В рукопожатии TLS клиент предлагает список протоколов (например, h2 и http/1.1), а сервер выбирает один. Если ALPN не сработал, вы легко получите ситуацию «модуль есть», но фактически всё продолжает ходить по HTTP/1.1.
Если клиент не видит выбранный протокол
h2в ALPN, то для него HTTP/2 «не существует», даже при установленномmod_http2.
При этом HTTP/2 касается в основном фронтенда: мультиплексирование, заголовки, управление потоками. Исполнение PHP-скриптов не меняется: Apache будет проксировать запросы в PHP-FPM через FastCGI, чаще всего с модулем proxy_fcgi.
Проверяем предпосылки: версии, модули, ALPN
Перед правкой конфигов имеет смысл подтвердить три вещи: Apache видит модуль HTTP/2, включён SSL, и TLS-стек реально умеет ALPN.
1) Apache и нужные модули
Проверьте версию и набор модулей:
apachectl -v
apachectl -M | grep -E 'http2|ssl|proxy|proxy_fcgi|headers'
Минимально полезный набор для типового сайта с PHP-FPM:
http2_module(mod_http2)ssl_module(mod_ssl)proxy_moduleиproxy_fcgi_module(проксирование к PHP-FPM)headers_module(диагностика и заголовки)
2) Проверка ALPN через OpenSSL
Самая быстрая проверка «а выбирается ли h2» — это openssl s_client с запросом ALPN:
openssl s_client -connect example.com:443 -servername example.com -alpn h2 -tls1_2 2>/dev/null | grep -E 'ALPN protocol|Protocol'
Ожидаемый признак успеха: строка вида ALPN protocol: h2. Если ALPN не отработал, чаще всего увидите выбор http/1.1 или отсутствие строки про ALPN.

Включаем HTTP/2: mod_http2 и директива Protocols
Даже при загруженном mod_http2 HTTP/2 не включится «сам». На практике решающая часть — директива Protocols на уровне конкретного TLS-виртуального хоста. Глобальное включение без разбора может неожиданно затронуть чужие сайты на сервере.
Включение модулей (Debian/Ubuntu)
a2enmod ssl http2 proxy proxy_fcgi headers rewrite
systemctl reload apache2
Пример TLS-виртуального хоста с h2 и fallback на HTTP/1.1
HTTP/1.1 стоит оставлять вторым протоколом: часть утилит, старых клиентов и мониторингов не умеют 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
# Диагностика на время внедрения
LogLevel http2:info ssl:warn
DocumentRoot /var/www/example/public
</VirtualHost>
Про h2c (HTTP/2 без TLS)
h2c — это HTTP/2 поверх обычного TCP. В интернете для браузерных сайтов почти никогда не нужен. Он уместен разве что во внутренних контурах (например, между балансировщиком и Apache) и со специализированными клиентами.
Apache + PHP-FPM через proxy_fcgi: две рабочие схемы
HTTP/2 может увеличить параллельность запросов от клиента, и это быстро упирается в backend. Поэтому важно не только «чтобы PHP открывался», но и чтобы связка была предсказуемой по таймаутам и лимитам.
Вариант A: PHP-FPM через Unix-сокет
Unix-сокет обычно проще в изоляции и немного экономнее по накладным расходам.
<VirtualHost *:443>
ServerName example.com
DocumentRoot /var/www/example/public
SSLEngine on
Protocols h2 http/1.1
<Directory /var/www/example/public>
AllowOverride All
Require all granted
</Directory>
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
</FilesMatch>
</VirtualHost>
Вариант B: PHP-FPM через TCP (127.0.0.1:9000)
Подходит для контейнеров, отдельных namespace или когда вы хотите проще диагностировать сетевую часть.
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>
Что важно именно при HTTP/2
- MPM: чаще всего выбирают
mpm_event(илиmpm_worker).mpm_preforkвозможен, но обычно хуже по памяти и масштабированию. - KeepAlive: HTTP/2 мультиплексирует запросы в одном соединении, но для клиентов HTTP/1.1 KeepAlive всё равно важен. Не отключайте его без причины.
- Пулы FPM и очереди: рост параллельности раскрывает узкие места
pm.max_children, медленные запросы к БД и внешним API.
TLS-настройки, которые чаще всего влияют на h2
Если TLS настроен «слишком старо» или «слишком агрессивно», браузер может откатиться на HTTP/1.1 или начать сыпать ошибками, которые легко перепутать с проблемами HTTP/2.
Практический минимум
- Держите включёнными TLS 1.2 и TLS 1.3 (если доступно).
- Следите за целостностью цепочки сертификатов (полный chain) — неполная цепочка ломает клиентов и усложняет диагностику.
- Не «крутите шифры» наугад: лучше сделать конфиг совместимым, чем идеально строгим ценой реальных пользователей.
Если вы как раз наводите порядок с сертификатами и цепочками, удобнее сразу использовать нормальные SSL-сертификаты и не ловить странные клиентские ошибки из-за несовместимых наборов.
Проверка: как убедиться, что реально работает HTTP/2
После изменений проверяйте протокол явно, а не «по ощущениям».
1) curl
curl -I --http2 -sS https://example.com | head -n 5
На многих системах будет видно HTTP/2 200 в статусной строке.
2) openssl + ALPN
openssl s_client -connect example.com:443 -servername example.com -alpn h2 2>/dev/null | grep -E 'ALPN protocol|Verify return code'
3) Диагностика конфигурации Apache
apachectl -t -D DUMP_VHOSTS
apachectl -t -D DUMP_MODULES | grep http2
Если нужно быстро понять, что делает mod_http2, на короткое время поднимайте LogLevel http2:info (или http2:debug) только в проблемном <VirtualHost *:443>.

Troubleshooting: частые проблемы и быстрые решения
Проблема 1: модуль включён, но браузер упорно на HTTP/1.1
- Проверьте наличие
Protocols h2 http/1.1именно в<VirtualHost *:443>, который обслуживает нужный домен по SNI. - Проверьте ALPN через
openssl s_client. - Убедитесь, что TLS не терминируется на внешнем прокси/балансировщике, который до Apache отдаёт HTTP/1.1.
- Проверьте, что тестируете правильный хост/сертификат (в многосайтовой конфигурации легко попасть не в тот vhost).
Проблема 2: «AHxxxxx: h2 session ...» и обрывы под нагрузкой
- Проверьте, какой MPM активен, и достаточно ли ресурсов (обычно
mpm_eventпроще масштабируется). - На короткое время включите
LogLevel http2:debugв проблемном vhost и соберите точные причины разрыва. - Сверьте, не является ли узким местом backend: очереди FPM,
pm.max_children, медленные запросы к БД.
Проблема 3: 503/504 на PHP при росте параллельных запросов
HTTP/2 сам по себе не «ломает PHP», он просто быстрее доводит систему до реальных лимитов.
- Посмотрите состояние FPM: занятые воркеры, очередь, загрузку CPU и память.
- Проверьте таймауты на стороне Apache при проксировании к FPM (не лечите причину бесконечным увеличением таймаутов).
- Включите slowlog в FPM и найдите конкретные медленные скрипты и запросы.
Проблема 4: «Protocol h2 is not supported» или модуль не поднимается
- Убедитесь, что установлен/включён пакет
mod_http2(или модуль есть в сборке Apache). - Проверьте зависимости (часто нужна библиотека nghttp2 в дистрибутивных пакетах).
- HTTP/2 включайте именно на TLS-виртуальном хосте, вместе с
mod_ssl.
Советы по эксплуатации: чтобы не получить сюрпризы
Не включайте HTTP/2 «везде», пока не понятен профиль трафика
Если на сервере много сайтов, включайте HTTP/2 точечно: на тех vhost’ах, где вы контролируете TLS, backend и метрики. Для остального — сначала замеры.
Смотрите не только на фронтенд: заголовки, куки и кэш
Проблемы «раздутые Cookie», «слишком большие заголовки», «тяжёлые ответы» отлично проявляются и на HTTP/2. Для комплексной настройки заголовков полезно держать под рукой материал про практику HTTP security headers в Apache и Nginx.
Если есть балансировщик, проверьте, где терминируется TLS
В реальных схемах TLS часто заканчивается на балансировщике. Тогда HTTP/2 может быть между клиентом и балансировщиком, а до Apache будет обычный HTTP/1.1. Это нормально, но важно понимать точку терминации. Для подобных архитектур пригодится разбор про терминацию протоколов на балансировщике, включая QUIC и HTTP/3.
Итог
Стабильная связка Apache + HTTP/2 строится сверху вниз:
- TLS/ALPN: клиент должен увидеть выбор
h2в ALPN, цепочка сертификатов корректна. - Apache: загружен
mod_http2, в TLS-vhost заданоProtocols h2 http/1.1, подходящий MPM. - Backend: PHP-FPM подключён через
proxy_fcgi, пулы и таймауты выдерживают параллельность.
Если проверять именно в этом порядке (ALPN → Protocols → proxy_fcgi → лимиты FPM), типовые кейсы «почему не h2» и «почему посыпались 503/504» решаются быстро и предсказуемо.


