8.12.15

Installing Apache httpd with HTTP/2 support from scratch on CentOS 7.1


On October 13, 2015, Apache http2 2.4.17 was released. This release, while just a point release, included modhttp2, a formalization within the Apache httpd software of modh2. Since CentOS 7.1, my preferred Linux distribution, doesn't yet include it, we need to compile it from source.

Dependencies


Since mod_http2 is dependent on nghttp2, we need to install this. We'll use the latest version, and compile it from source.

As well, we need a version of OpenSSL that supports ALPN. ALPN allows for application layer protocol negotiation, and is critical for clients to be able to negotiate the upgrade from HTTP 1.1 to HTTP/2. Again, since CentOS 7.1 only includes 1.0.1e, and we need at least 1.0.2, we have to compile it from source.

I'm assuming that you'll apply superuser permissions as appropriate to do things like make install, or moving / editing system files.

Prerequisites


There are several packages that we need to be able to build. We'll assume that we've got the Development group of tools installed.

  • zlib-devel is required by OpenSSL.
  • libev-devl is required by nghttpd.
  • pcre-devel is required by httpd.

System software required by the build.
: yum install -y zlib-devel libev-devel pcre-devel libxml2-devel

OpenSSL


Install the latest OpenSSL. Note that during the make-test phase, the tests will fail due to an expired test certificate, so you might just want to skip that phase.

wget https://www.openssl.org/source/openssl-1.0.2d.tar.gz && tar xf openssl-1.0.2d.tar.gz
cd openssl-1.0.2d
./config --prefix=/usr/local/openssl-1.0.2d shared zlib
make
make test
make install

Update the library path with the new libs.

echo "/usr/local/openssl-1.0.2d/lib " > /etc/ld.so.conf.d/openssl102d.conf
ldconfig

nghttp


Install the latest nghttp.

wget https://github.com/tatsuhiro-t/nghttp2/releases/download/v1.4.0/nghttp2-1.4.0.tar.gz && tar xf nghttp2-1.4.0.tar.gz
cd nghttp2-1.4.0
autoreconf -i
automake
autoconf
env OPENSSL_CFLAGS="-I/usr/local/openssl-1.0.2d/include" OPENSSL_LIBS="-L/usr/local/openssl-1.0.2d/lib -lssl -lcrypto" ./configure 
make
make install

Update the library path with the new libs.

echo "/usr/local/lib " > /etc/ld.so.conf.d/usr-local-lib.conf
ldconfig

APR / APR-util


The latest APR and APR-util are required to build httpd 2.4.x from source.

wget http://apache.mirror.vexxhost.com/apr/apr-1.5.2.tar.gz
cd apr-1.5.2
./configure
make
make install

wget http://apache.mirror.vexxhost.com/apr/apr-util-1.5.4.tar.gz
cd apr-util-1.5.4
./configure --with-apr=/usr/local/apr
make
make install

Apache httpd


Now we come to the payoff. We install Apache httpd, at least 2.4.17 as of this writing. We're using a custom layout using the config.layout file. My prefered layout is based on the Fedora layout, but stuffed into /usr/local, what with us compiling it ourselves, and the sysconf dir in the standard /etc.

wget http://apache.mirror.rafal.ca//httpd/httpd-2.4.17.tar.gz
(optional) config.layout:

Local layout
<Layout Local>
    prefix:        /usr/local
    exec_prefix:   ${prefix}
    bindir:        ${prefix}/bin
    sbindir:       ${prefix}/sbin
    libdir:        ${prefix}/lib
    libexecdir:    ${prefix}/libexec
    mandir:        ${prefix}/man
    sysconfdir:    /etc/httpd/conf
    datadir:       ${prefix}/share/httpd
    installbuilddir: ${libdir}/httpd/build
    errordir:      ${datadir}/error
    iconsdir:      ${datadir}/icons
    htdocsdir:     /var/www/html
    manualdir:     ${datadir}/manual
    cgidir:        /var/www/cgi-bin
    includedir:    ${prefix}/include/httpd
    localstatedir: /var
    runtimedir:    /run/httpd
    logfiledir:    ${localstatedir}/log/httpd
    proxycachedir: ${localstatedir}/cache/httpd/proxy
</Layout>

./configure --enable-http2 --enable-ssl --with-ssl=/usr/local --enable-so --enable-mpms-shared=all --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr --enable-pie --with-pcre --enable-mods-shared=all --disable-distcache --disable-imagemap --enable-layout=Local
make
make install

Httpd really should have its own user, so add the www group and apache user.

groupadd www
useradd -g www -m apache

Now you'll need to edit your httpd.conf, to make sure that it's set up properly. You need to enable the three following modules, http2, socache_shmcb, and ssl. As well, since we're doing ssl, using the worker module would give us the best performance, so make sure that it's enabled.

LoadModule http2_module /usr/libexec/mod_http2.so
LoadModule socache_shmcb_module /usr/libexec/mod_socache_shmcb.so
LoadModule ssl_module /usr/libexec/mod_ssl.so

Since we're on CentOS 7, and systemd is the law of the land, you need to add a service, then enable it.

/etc/systemd/system/httpd.service:
[Unit]
Description=The Apache HTTP Server

[Service]
Type=forking
EnvironmentFile=/etc/sysconfig/httpd
PIDFile=/run/httpd/httpd.pid
ExecStart=/usr/local/apache2/bin/apachectl start
ExecReload=/usr/local/apache2/bin/apachectl graceful
ExecStop=/usr/local/apache2/bin/apachectl stop
KillSignal=SIGCONT
PrivateTmp=true

[Install]
WantedBy=multi-user.target

With this, we'll need to create the environment file:

/etc/sysconfig/httpd
#OPTIONS=
LANG=C

And now, we can enable:

systemctl enable httpd.service

It'll start now, but once you reboot, you'll find that httpd won't start, because it can't access /var/run/httpd. This time, we need to add a conf file to /etc/tmpfiles.d, so that the appropriate directory is created in the tmpfs in /run at boot.

/etc/tmpfiles.d/httpd.conf:
d /run/httpd   710 root www

You can now create a module configuration file for mod_http2, and populate it as such:

/etc/httpd/conf/extra/httpd_http2.conf:
<IfModule http2_module>
    LogLevel http2:debug
</IfModule>
# http
Protocols h2c http/1.1

You'll need to edit the ssl configuration as well, to add the https protocol. At the end of the section in /etc/httpd/conf/extra/httpd_ssl.conf, add:

# https
Protocols h2 http/1.1

This assumes that you've got a certificate for your server. If you don't, then creating a self-signed cert, or acquiring a legit cert, is left as an exercise to the reader. Just make sure that it's in place when you go to start httpd, which you will do now:

systemctl start httpd.service

It's now time to actually test this behemoth. We're going to skip testing for HTTP/2 connectivity over http, since that's largely academic. Modern browsers like Firefox only support HTTP/2 with TLS. Since we put an SSL certificate in place earlier, this shouldn't be a problem.

First, make sure you have a SPDY indicator add on installed in your browser. This will give you a little lightning bolt in the URL bar that will indicate the protocol that you've connected with. A couple of indicators for popular browsers are:


Now visit the root of your new site, and you ought to be greeted with a page full on PHP info. If you've gone to the https URL, then you should see a pretty little blue lightning bolt in your URL bar, indicating that your site is being served with HTTP/2.

References? Sure. I'll actually link these some day, probably.

  • https://blog.apar.jp/linux/3484/ (Japanese)
  • https://httpd.apache.org/docs/2.4/install.html
  • https://icing.github.io/mod_h2/howto.html
  • http://pixelinc.co/ubuntu-14-04-3-apache-http-2-web-server-setup/
  • http://blog.astaz3l.com/2015/02/09/how-to-install-apache-on-centos/
  • https://www.howtoforge.com/how-to-use-multiple-php-versions-php-fpm-and-fastcgi-with-ispconfig-3-ubuntu-12.04-lts-p3