Tools HTTP/2 and Web Servers Lead image: Lead Image © Soloviova Liudmyla,
Lead Image © Soloviova Liudmyla,

Activate HTTP/2 on web servers

Son of SPDY

HTTP/2 offers reduced website load times and other performance benefits, along with the promise of server push. By Oliver Frommel

Numerous implementations of the new HTTP/2 protocol have been published: After implementation in browsers, distributed web servers followed. In this article, I describe how you can activate HTTP/2 in Nginx and look at support in the Apache and H2O web servers.

At the end of September last year, the commercial Nginx Plus web server gained support for the HTTP/2 protocol [1]. A short time later, the code made its way into the freely available Nginx version 1.9.5. Nginx can function as, among other things, a proxy running HTTP/2 on the client side and communicating with back-end servers via HTTP 1.1, FastCGI, SCGI, and uWSGI.

The HTTP/2 implementation is financially supported by Dropbox and Automattic, the company behind WordPress. At the time this article was written, the latest Nginx version was 1.9.9, which had already removed a few of the bugs in the HTTP/2 implementation. Until now, the server push feature, in which a web server initiates the transfer of files the client will need, has not been implemented.

Installing Nginx

Nginx can be installed relatively easily. The developers offer repositories for many distributions that contain the stable version and a developer version of the web server [2]. To install Nginx 1.9.9 on Ubuntu, for instance, add the following line to the /etc/apt/sources.list file:

deb trusty nginx

This example uses the mainline repository, which contains the latest Nginx version necessary for HTTP/2 support. The following call downloads the signing key that the package manager uses to verify the package and adds it to local memory:

$ wget
$ sudo apt-key add nginx_signing.key

Now you have to update the repository data before you install the Nginx server:

$ apt-get update
$ apt-get install nginx

The installation runs similarly with Red Hat-based distributions like CentOS or Fedora. You install the repository key after download as follows:

$ rpm --import nginx_signing.key

When configuring the repository, you cannot use the RPM provided; rather, you must enter the mainline directory manually into /etc/yum.repos.d/nginx.repo:

name=nginx repo

For distributions other than CentOS 7, modify the distribution name and the version number accordingly. You can easily test whether the installed Nginx version has HTTP/2 support with the

/sbin/nginx -V

call (Figure 1).

A call to nginx -V reveals whether the web server supports the HTTP/2 protocol.
Figure 1: A call to nginx -V reveals whether the web server supports the HTTP/2 protocol.

HTTP/2 is simple to configure, needing only the http2 inline directive; this ensures that Nginx can also open TLS port 443, such as in the /etc/nginx/conf.d/default.conf file:

listen 443 ssl http2;

HTTP/2 generally requires TLS (the specification does not demand this, but all browsers only use HTTP/2 with encryption), so you must equip Nginx with all the appropriate certificates, which can be either bought or self-signed. One alternative is the free Let's Encrypt [3] certificate, which is recognized by the current browsers as secure by cross-signing. If you have the certificate and the private key, add this to the Nginx configuration:

ssl_certificate /etc/pki/nginx/server.crt;
ssl_certificate_key /etc/pki/nginx/server.key;

HTTP/2 Connection Test

If you restart the server now, it should be accessible via HTTP/2. To test, you can install extensions for Chrome or Firefox, which use an icon in the location bar to show whether an HTTP/2 connection has occurred (Figure 2). The protocol is also reflected in the Nginx log with the message: - - [21/Dec/2015:05:46:30 -0500] "GET /tile-399.jpg HTTP/2.0" 200 846 "" ...
A blue lightning bolt icon in Firefox indicates support for the HTTP/2 protocol.
Figure 2: A blue lightning bolt icon in Firefox indicates support for the HTTP/2 protocol.

A variety of libraries require cURL, which has supported HTTP/2 since version 7.43, including SSL libraries like OpenSSL and nghttp2. On most distros, however, a new version is not included, so you have to compile it manually; after you have done so, call cURL with the --http2 control:

$ cURL -v --http2

The verbose mode (-v) shows additional communication details (Figure 3). If you are using a self-signed certificate, you can disable verification with -k. In the test, I had problems with an older version of cURL, so in case of doubt, it is always recommended to update to a new release.

The cURL command-line tool shows details of the HTTP/2 call.
Figure 3: The cURL command-line tool shows details of the HTTP/2 call.

As seen in Figure 3, cURL reveals details about how it negotiates the protocol when connecting. Nginx uses the Application Layer Protocol Negotiation (ALPN) expansion for TLS, which the web server uses to offer the HTTP/2 protocol to a client; otherwise, it reverts to HTTP 1.1

The HTTP/2 headers cannot be viewed with cURL, however, because the tool uses HTTP/1.1 headers after decoding the HTTP/2 streams. A development objective of HTTP/ 2 was to be transparent for applications on the server and client sides. The HTTP 1 semantics with the well-known HTTP methods (GET, POST, …) and response and status codes remain, and the binary framing of HTTP/2 is only used internally. To examine this step more closely, you can use tools (e.g., Wireshark) that support HTTP/2 [4].

Higher Performance with HTTP/2

One HTTP/2 goal is to reduce website load times by transferring several requests over a single TCP connection to reduce overhead. To do so, HTTP/2 introduces a new layer, in which the customary HTTP protocol elements are broken down into binary packages (frames). The headers and usage data are embedded in different frames, which are sent over a stream, bundling the requests and responses that are part of a connection between client and server. Several streams are handled within a single TCP connection.

Prioritization of requests ensures that important requests receive preferential treatment, to prevent head-of-line blocking; that is, message transport halts because the client or server has to wait for an important package. Server push, in which the server sends data needed by the client of its own accord, has not yet been implemented in Nginx. According to the developers, it might be contained in a future version.

In a test, I embedded 400 images in an HTML page, much like the "Gophertiles" test for HTTP/2 implementation in the Go programming language [5]. In theory, the performance should be worse with HTTP 1.1, because the number of simultaneous connections between client and server is limited. Initially, however, I could not tell any difference between the two. When I restricted the bandwidth of the network interface to 1MBps with the Wonder Shaper tool, a clear difference was apparent. The HTTP/2 version was about 20% faster than the HTTP 1.1 version.

Apache Manual Labor

The Apache web server has run HTTP/2 since version 2.4.17, which means you have to compile the web server yourself on most Linux distributions if you want to use HTTP/2. Apache requires a whole series of config options to function normally and use the directory layout you are likely familiar with from your distribution. On Red Hat or CentOS, you can take a look at the source RPM from Apache and copy the config option used there. Even better, you can modify the SPEC file for the new Apache version and build an RPM yourself. Admittedly, it is not especially easy to find out which patches you have to delete and which you have to keep to build the package successfully.

To activate HTTP/2, the source code must be configured with the --enable-http2 option, which requires the libnghttp2 library included with CentOS 7. Otherwise, manual installation is initiated. The server also requires the OpenSSL library – at least in version 1.0.2 – for ALPN support, although the older version 1.0.1 is installed in many Linux distros. A complete update is therefore difficult because many applications then have to be relinked to the current OpenSSL version. However, installing a current OpenSSL version in parallel with the old (e.g., in /usr/local) does not pose any problems.

If you have compiled the Apache web server successfully, you must activate the protocol in the server configuration to use HTTP/2:

Protocols h2 http/1.1

The HTTP/2 module must be loaded for this to function. In the same file, the log level of the module can then be set:

LoadModule http2_module modules/
<IfModule http2_module>
        LogLevel http2:info

Apache can take advantage of server push if the feature is activated with the H2Push directive. The web server then inspects the link header of a response and spontaneously sends the resources listed there to the client. The H2PushPriority instruction [6] improves performance by setting the order and priority in which pushed responses are sent out.

H2O, the Newcomer

Another interesting candidate to use for testing HTTP/2 sites is H2O [7], a relatively new web server from Japan released under the MIT License. H2O is faster than Nginx in benchmarks and provides a whole range of other much-needed features along with HTTP/2, such as forward secrecy for TLS, support for the proxy protocol, and TLS session resumption, a technique that halves the time needed to make TLS connections and reduces computing time by up to 10%.

H20 does not have as many features as Nginx and Apache, but the most important components for running a professional website have been implemented, such as FastCGI interface support for programming languages. H2O also has a built-in Ruby interface to supply script support for processing requests.

H2O has to be compiled from the source code, but that can be done fairly simply, because the package already contains most of the dependencies. Only the CMake build tool and the libuv library (version 1.0.0 or greater) are needed. If you want to use WebSockets, you have to install libwslay, which is rarely contained in distributions. If the TAR archive has been downloaded and extracted, the following command chain installs the program:

$ cmake -DWITH_BUNDLED_SSL=on .
$ make
$ sudo make install

Although the developers consider LibreSSL to be the better SSL library, because it is deemed safer and provides newer crypto-algorithms, they recommend the somewhat faster OpenSSL for benchmarks. The program can be compiled with the included library (-DWITH_BUNDLED_SSL) or with an SSL library already installed system wide. To start the server, enter:

$ /usr/local/bin/h2o -c h2o.conf

For HTTP/2, the developers have developed a technique called CASPer (cache-aware server push), to ensure the efficient interaction of browser cache and HTTP/2 server push. It makes little sense for the server to transfer files that the browser already has saved in its cache; to prevent this, CASPer, with the use of checksums and cookies, keeps a record of files that have already been transferred. More advanced features in H2O include a proxy function for WebSockets and smart caching of file descriptors.


HTTP/2 is in more widespread use than you would think, as you can see if you pay attention to the HTTP/2 indicator on your browser as you surf. For instance, large sites like Google and Twitter naturally make use of HTTP/2. Web hosts like CloudFlare and content delivery networks like Akamai also are already offering HTTP/2 to their customers.

Few sources of error crop up after updating to HTTP/2. When activated, websites function as expected. If you are lucky, your performance will benefit from lower overhead. If your website depends on every ounce of performance, you should perform comprehensive tests, because common tweaks to HTTP/1 could backfire with HTTP/2. In the future, web server improvements such as server push are expected, as the newcomer H2O demonstrates.