Ssl – How to build Apache httpd 2.4.20 on CentOS 7 with http2 support

apache-2.4http2httpdhttpsssl

I've spent nearly a day trying to make Apache httpd builds with ALPN and http2 support for EL6 and EL7 for my company and society, as I previously did for NGINX (Built statically against OpenSSL 1.0.2h).

First, I tried to rebuild src rpms with OpenSSL 1.0.2h taken from Fedora and install resulted rpms (openssl-devel-1.0.2h-1.el7.centos.x86_64.rpm, openssl-1.0.2h-1.el7.centos.x86_64.rpm) to replace system's one. Yes, I know, this is not right way for public builds, but I need to know if will work at all.

Then I've rebuilt nghttp2-1.7.1-1.fc24.src.rpm and installed resulted libnghttp2-devel-1.7.1-1.el7.centos.x86_64.rpm and libnghttp2-1.7.1-1.el7.centos.x86_64.rpm.

Finally, after removing some patches and hacking apr and apr-util I've succeeded to build httpd-2.4.18-1.fc23.src.rpm into httpd-2.4.18-1.el7.centos.x86_64.rpm.

Plain HTTP/1.1 worked for me ok, and ALPN support was also present, but HTTP/2 did not work:

$ curl -v --insecure --http2 --tlsv1.2 https://192.168.1.148
* Rebuilt URL to: https://192.168.1.148/
*   Trying 192.168.1.148...
* Connected to 192.168.1.148 (192.168.1.148) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* ALPN, server accepted to use h2
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
* Server certificate:
*       subject: E=root@centos7.dcodeit.net,CN=centos7.dcodeit.net,OU=SomeOrganizationalUnit,O=SomeOrganization,L=SomeCity,ST=SomeState,C=--
*       start date: май 25 13:11:19 2016 GMT
*       expire date: май 25 13:11:19 2017 GMT
*       common name: centos7.dcodeit.net
*       issuer: E=root@centos7.dcodeit.net,CN=centos7.dcodeit.net,OU=SomeOrganizationalUnit,O=SomeOrganization,L=SomeCity,ST=SomeState,C=--
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55ccf55b44c0)
> GET / HTTP/1.1
> Host: 192.168.1.148
> User-Agent: curl/7.43.0
> Accept: */*
>
* http2_recv: 16384 bytes buffer at 0x55ccf55b4e08 (stream 1)
* http2_recv: 16384 bytes buffer at 0x55ccf55b4e08 (stream 1)
* Unexpected EOF
* Closing connection 0
curl: (56) Unexpected EOF

I thought that there can be problems with some of Fedora's patches and tried to rebuild some other parts without any luck.
Finally, I removed all "devel" rpms, downloaded latest stable httpd-2.4.20, put apr and apr-util unmodified latest sources to its srclib directory and tried to build with:

CFLAGS="-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic"; export CFLAGS
LDFLAGS="-Wl,-z,relro,-z,now"; export LDFLAGS
"./configure" \
"--prefix=/etc/httpd" \
"--exec-prefix=/usr" \
"--bindir=/usr/bin" \
"--sbindir=/usr/sbin" \
"--mandir=/usr/share/man" \
"--libdir=/usr/lib64" \
"--sysconfdir=/etc/httpd/conf" \
"--includedir=/usr/include/httpd" \
"--libexecdir=/usr/lib64/httpd/modules" \
"--datadir=/usr/share/httpd" \
"--enable-layout=Fedora" \
"--with-installbuilddir=/usr/lib64/httpd/build" \
"--enable-mpms-shared=all" \
"--enable-suexec" \
"--with-included-apr" \
"--with-suexec" \
"--enable-suexec-capabilities" \
"--with-suexec-caller=apache" \
"--with-suexec-docroot=/var/www" \
"--without-suexec-logfile" \
"--with-suexec-syslog" \
"--with-suexec-bin=/usr/sbin/suexec" \
"--with-suexec-uidmin=1000" \
"--with-suexec-gidmin=1000" \
"--enable-pie" \
"--with-pcre" \
"--enable-mods-shared=all" \
"--enable-ssl" \
"--with-ssl=/root/openssl-1.0.2h" \
"--enable-ssl-staticlib-deps" \
"--with-nghttp2=/root/nghttp2-1.11.0" \
"--enable-nghttp2-staticlib-deps" \
"LDFLAGS=-Wl,-z,relro,-z,now" \
"CFLAGS=-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic"

As you can see, I'm trying to build mod_ssl and mod_http2 statically with latest libraries versions, but http2 still does not work with exactly same error message: server drops connection without any reply. There is no data can be found in logs: requests are not shown in logs at all, while http/1.1, http/1.1 over SSL and h2c requests are properly logged and handled.

My configuration file is now nearly stock one (from unmodified httpd-2.4.20), but with enabled mod_ssl, mod_http2 and "Protocols h2 http/1.1".

One more strange thing: I tried to add "LogLevel http2:info" to debug http2, but I'm unable to see any initialization lines like "[http2:info] [pid XXXXX:tid numbers] mod_http2 (v1.0.0, nghttp2 1.3.4), initializing…". However, I believe http2 module is on, as there is no config error for this log level. Also I checked it with h2c (http2 over plain http) and it perfectly works with curl and "101 Switching protocols" reply.

So, I tried to build it statically, dynamically, with different lib versions, finally I used clean, unmodified sources for nghttp2, openssl, apr, apr-util, configuration files without any luck, however HTTP/2 and ALPN work normally separately.

Please advise.

Best Answer

I notice you are using this cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

However that cipher is black listed for HTTP/2: https://www.rfc-editor.org/rfc/rfc7540

And by default mod_http2 will not allow you to negotiate with blacklisted ciphers: https://httpd.apache.org/docs/2.4/mod/mod_http2.html#h2moderntlsonly

So I wonder if that is the only problem and you just need to enable more modern cipher suites? Specifically a ECDHE with GCM rather than CBC suite like TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA25. You could always turn above flag off for your curl test but Chrome similarly uses this blacklist so you'll need to enable other ciphers anyway (and why wouldn't you want to since you've gone through the hassle of upgrading your openssl for this).

If that's not the issue then you could check out the step by step instructions I give here on how to build from source: https://www.tunetheweb.com/performance/http2/. I use Centos 7 and these steps work for me.