Activate HTTP/2 on web servers
Son of SPDY
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 http://nginx.org/packages/mainline/ubuntu/ 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 http://nginx.org/keys/nginx_signing.key $ 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
:
[nginx] name=nginx repo baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/ gpgcheck=0 enabled=1
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).
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:
10.0.0.1 - - [21/Dec/2015:05:46:30 -0500] "GET /tile-399.jpg HTTP/2.0" 200 846 "https://10.0.0.31/" ...
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 https://10.0.0.31
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.
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.
Buy this article as PDF
(incl. VAT)