I'm more of an nginx head these days (and I don't have any problems getting HTTP/2 working with that) but I'm completely flummoxed by Apache and cannot seem to get it to serve a site over HTTP/2.

The Server is Debian 8. I've installed Apache 2.4.27 and openssl1.1.0f by enabling the Debian 'testing' repo.

Here's some useful information and server configs:

Apache Version

root@server:~# apachectl -V
Server version: Apache/2.4.27 (Debian)
Server built:   2017-07-16T21:01:10
Server's Module Magic Number: 20120211:68
Server loaded:  APR 1.5.1, APR-UTIL 1.5.4
Compiled using: APR 1.5.2, APR-UTIL 1.5.4
Architecture:   64-bit
Server MPM:     prefork
  threaded:     no
    forked:     yes (variable process count)
Server compiled with....
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D HTTPD_ROOT="/etc/apache2"
 -D SUEXEC_BIN="/usr/lib/apache2/suexec"
 -D DEFAULT_PIDLOG="/var/run/apache2.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="mime.types"
 -D SERVER_CONFIG_FILE="apache2.conf"

Apache Modules

root@server:~# apachectl -M
Loaded Modules:
 core_module (static)
 so_module (static)
 watchdog_module (static)
 http_module (static)
 log_config_module (static)
 logio_module (static)
 version_module (static)
 unixd_module (static)
 access_compat_module (shared)
 alias_module (shared)
 auth_basic_module (shared)
 authn_core_module (shared)
 authn_file_module (shared)
 authz_core_module (shared)
 authz_host_module (shared)
 authz_user_module (shared)
 autoindex_module (shared)
 deflate_module (shared)
 dir_module (shared)
 env_module (shared)
 expires_module (shared)
 filter_module (shared)
 headers_module (shared)
 http2_module (shared)
 mime_module (shared)
 mpm_prefork_module (shared)
 negotiation_module (shared)
 php5_module (shared)
 reqtimeout_module (shared)
 rewrite_module (shared)
 setenvif_module (shared)
 socache_shmcb_module (shared)
 ssl_module (shared)
 status_module (shared)

OpenSSL Version

root@server:/root# openssl version
OpenSSL 1.1.0f  25 May 2017

Apache Base Config

root@server:~# cat /etc/apache2/apache2.conf
DefaultRuntimeDir ${APACHE_RUN_DIR}
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5


HostnameLookups Off

ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn

IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf

Include ports.conf

<Directory />
    Options FollowSymLinks
    AllowOverride None
    Require all denied

<Directory /usr/share>
    AllowOverride None
    Require all granted

<Directory /var/www/>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted

AccessFileName .htaccess

<FilesMatch "^\.ht">
    Require all denied

LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

IncludeOptional conf-enabled/*.conf

IncludeOptional sites-enabled/*.conf

Apache SSL Config

root@server:~# cat /etc/apache2/mods-available/ssl.conf
<IfModule mod_ssl.c>
    SSLRandomSeed startup builtin
    SSLRandomSeed startup file:/dev/urandom 512
    SSLRandomSeed connect builtin
    SSLRandomSeed connect file:/dev/urandom 512

    AddType application/x-x509-ca-cert .crt
    AddType application/x-pkcs7-crl .crl

    SSLPassPhraseDialog  exec:/usr/share/apache2/ask-for-passphrase

    SSLSessionCache shmcb:${APACHE_RUN_DIR}/ssl_scache(512000)
    SSLSessionCacheTimeout 300


    SSLHonorCipherOrder on

    SSLProtocol all -SSLv3

    SSLCompression off
    SSLSessionTickets off

    SSLUseStapling on
    SSLStaplingResponderTimeout 5
    SSLStaplingReturnResponderErrors off
    SSLStaplingCache shmcb:/var/run/ocsp(128000)

    SSLOpenSSLConfCmd DHParameters "/etc/apache2/ssl/dhparam.pem"

    <FilesMatch "\.php$">
        SSLOptions +StdEnvVars

    BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown

Apache HTTP2 Config

root@server:~# cat /etc/apache2/mods-enabled/http2.conf
H2Push on
H2PushPriority * after
H2PushPriority text/css before
H2PushPriority image/jpeg after 32
H2PushPriority image/png after 32
H2PushPriority application/javascript interleaved

Apache Security Config

root@server:~# cat /etc/apache2/conf-available/security.conf
ServerTokens Prod
ServerSignature Off
TraceEnable Off

<IfModule mod_headers.c>
    Header set X-UA-Compatible "IE=Edge"
    Header always set Strict-Transport-Security "max-age=15768000"

    <FilesMatch "\.(appcache|atom|bbaw|bmp|crx|css|cur|eot|f4[abpv]|flv|geojson|gif|htc|ico|jpe?g|js|json(ld)?|m4[av]|manifest|map|mp4|oex|og[agv]|opus|otf|pdf|png|rdf|rss|safariextz|svgz?|swf|topojson|tt[cf]|txt|vcard|vcf|vtt|webapp|web[mp]|webmanifest|woff2?|xloc|xml|xpi)$">
        Header unset X-UA-Compatible

    Header always append X-Frame-Options SAMEORIGIN
    Header set X-Content-Type-Options nosniff
    Header set X-XSS-Protection "1; mode=block"

<IfModule mod_setenvif.c>
    SetEnvIf Request_URI "^/(browserconfig\.xml|manifest\.json|robots\.txt|sitemap\.xml|.well-known/.*)$" dontlog

<IfModule mod_rewrite.c>
    <FilesMatch "^/(browserconfig\.xml|manifest\.json|robots\.txt|sitemap\.xml)$">
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . /index.php [L]

<FilesMatch "(?:^|/)\.">
    Require all denied

<FilesMatch "(?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$">
    Require all denied

Apache VirtualHost Config

root@server:~# cat /etc/apache2/sites-available/www_xxxxxx_com.conf
ServerName server

<VirtualHost *:80>
    ServerName xxxxxx.com
    Redirect 301 / https://www.xxxxxx.com/

<VirtualHost *:80>
    ServerName www.xxxxxx.com
    Redirect 301 / https://www.xxxxxx.com/

<VirtualHost *:443>
    ServerName xxxxxx.com
    Redirect 301 / https://www.xxxxxx.com/

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/xxxxxx.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem
    SSLCACertificateFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem

    Protocols h2 http/1.1

<VirtualHost *:443>
    ServerName www.xxxxxx.com
    ServerAdmin webmaster@localhost
    DocumentRoot /data/www_xxxxxx_com/public_html

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined env=!dontlog

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/xxxxxx.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem
    SSLCACertificateFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem

    Protocols h2 http/1.1

    <Directory /data/www_xxxxxx_com/public_html/>
        AllowOverride All
        Require all granted

I tested all this using https://tools.keycdn.com/http2-test which came out negative, plus using curl (version 7.55.1 - with HTTP2 support):

➜  ~ curl -v --http2 https://www.xxxxxx.com
* Rebuilt URL to: https://www.xxxxxx.com/
*   Trying XXX.XXX.XXX.XXX...
* Connected to www.xxxxxx.com (XXX.XXX.XXX.XXX) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /usr/local/etc/openssl/cert.pem
  CApath: /usr/local/etc/openssl/certs
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=xxxxxx.com
*  start date: Aug 24 11:07:00 2017 GMT
*  expire date: Nov 22 11:07:00 2017 GMT
*  subjectAltName: host "www.xxxxxx.com" matched cert's "www.xxxxxx.com"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.

HTTP/1.1 200 OK
Date: Thu, 24 Aug 2017 15:30:35 GMT
Server: Apache
Strict-Transport-Security: max-age=15768000
X-Frame-Options: SAMEORIGIN
Upgrade: h2
Connection: Upgrade
Set-Cookie: PHPSESSID=knqh31ge9fqd60g4r40r7ngum4; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
X-UA-Compatible: IE=Edge
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Type: text/html; charset=UTF-8

Does anyone have any idea what I'm missing here, because it's driving me bonkers?



Oh for goodness sake - why do I almost always figure stuff like this out AFTER I post the question. Oh well - hope this helps someone else.

The answer lies in the error log:

[Thu Aug 24 17:55:09.795729 2017] [http2:info] [pid 16949] AH03090: mod_http2 (v1.10.7, feats=CHPRIO+SHA256+INVHD+DWINS, nghttp2 1.24.0), initializing...
[Thu Aug 24 17:55:09.795846 2017] [http2:warn] [pid 16949] AH10034: The mpm module (prefork.c) is not supported by mod_http2. The mpm determines how things are processed in your server. HTTP/2 has more demands in this regard and the currently selected mpm will just not do. This is an advisory warning. Your server will continue to work, but the HTTP/2 protocol will be inactive.
[Thu Aug 24 17:55:09.827124 2017] [mpm_prefork:notice] [pid 16949] AH00163: Apache/2.4.27 (Debian) OpenSSL/1.0.2l configured -- resuming normal operations

So there we go - just use 'event' or 'worker' MPM instead of prefork.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.