This is the howto guide for the HTTP/2 implementation in Apache httpd. This feature is production-ready and you may expect interfaces and directives to remain consistent releases.
HTTP/2 is the evolution of the world's most successful application layer protocol, HTTP. It focuses on making more efficient use of network resources. It does not change the fundamentals of HTTP, the semantics. There are still request and responses and headers and all that. So, if you already know HTTP/1, you know 95% about HTTP/2 as well.
There has been a lot written about HTTP/2 and how it works. The most normative is, of course, its RFC 7540 (also available in more readable formatting, YMMV). So, there you'll find the nuts and bolts.
But, as RFC do, it's not really a good thing to read first. It's better to first understand what a thing wants to do and then read the RFC about how it is done. A much better document to start with is http2 explained by Daniel Stenberg, the author of curl. It is available in an ever growing list of languages, too!
Too Long, Didn't read: there are some new terms and gotchas that need to be kept in mind while reading this document:
The HTTP/2 protocol is implemented by its own httpd module, aptly named
h2c
',
the secure one 'h2
'. For h2c
it allows the direct
mode and the Upgrade:
via an initial HTTP/1 request.
One feature of HTTP/2 that offers new capabilities for web developers is Server Push. See that section on how your web application can make use of it.
libnghttp2
installed on your system.
When you ./configure
you Apache httpd source tree, you need to give it
'--enable-http2
' as additional argument to trigger the build of the module.
Should your libnghttp2
reside in an unusual place (whatever that is on your
operating system), you may announce its location with '--with-nghttp2=<path>
'
to configure
.
While that should do the trick for most, they are people who might prefer a statically
linked nghttp2
in this module. For those, the option --enable-nghttp2-staticlib-deps
exists. It works quite similar to how one statically links openssl to
Speaking of SSL, you need to be aware that most browsers will speak HTTP/2 only on https:
URLs, so you need a server with SSL support. But not only that, you will need a SSL library
that supports the ALPN
extension. If OpenSSL is the library you use, you need
at least version 1.0.2.
When you have a httpd
built with
The second directive you need to add to your server configuration is
This allows h2, the secure variant, to be the preferred protocol on your server connections. When you want to enable all HTTP/2 variants, you simply write:
Depending on where you put this directive, it affects all connections or just the ones to a certain virtual host. You can nest it, as in:
This allows only HTTP/1 on connections, except SSL connections to test.example.org
which offer HTTP/2.
The h2
enabled server with a inappropriate
cipher suite will force it to simply refuse and fall back to HTTP 1.1. This is a common mistake
that is done while configuring httpd for HTTP/2 the first time, so please keep it in mind to avoid
long debugging sessions! If you want to be sure about the cipher suite to choose please avoid
the ones listed in the HTTP/2 TLS blacklist.
The order of protocols mentioned is also relevant. By default, the first one is the most preferred protocol. When a client offers multiple choices, the one most to the left is selected. In
the most preferred protocol is HTTP/1 and it will always be selected unless a client only supports h2. Since we want to talk HTTP/2 to clients that support it, the better order is
There is one more thing to ordering: the client has its own preferences, too. If you want, you can configure your server to select the protocol most preferred by the client:
makes the order you wrote the Protocols irrelevant and only the client's ordering will decide.
A last thing: the protocols you configure are not checked for correctness
or spelling. You can mention protocols that do not exist, so there is no need
to guard
For more advanced tips on configuration, see the modules section about dimensioning and how to manage multiple hosts with the same certificate.
HTTP/2 is supported in all multi-processing modules that come with httpd. However, if
you use the
In
If your setup can handle it, configuring
If you are really stuck with
Almost all modern browsers support HTTP/2, but only over SSL connections: Firefox (v43), Chrome (v45), Safari (since v9), iOS Safari (v9), Opera (v35), Chrome for Android (v49) and Internet Explorer (v11 on Windows10) (source).
Other clients, as well as servers, are listed on the Implementations wiki, among them implementations for c, c++, common lisp, dart, erlang, haskell, java, nodejs, php, python, perl, ruby, rust, scala and swift.
Several of the non-browser client implementations support HTTP/2 over cleartext, h2c. The most versatile being curl.
The first tool to mention is of course curl. Please make sure that
your version supports HTTP/2 checking its Features
:
And for really deep inspection wireshark.
The nghttp2 package also includes clients, such as:
Chrome offers detailed HTTP/2 logs on its connections via the special net-internals page. There is also an interesting extension for Chrome and Firefox to visualize when your browser is using HTTP/2.
The HTTP/2 protocol allows the server to PUSH responses to a client it never asked for. The tone of the conversation is: "here is a request that you never sent and the response to it will arrive soon..."
But there are restrictions: the client can disable this feature and the server may only ever PUSH on a request that came from the client.
The intention is to allow the server to send resources to the client that it will most likely need: a css or javascript resource that belongs to a html page the client requested. A set of images that is referenced by a css, etc.
The advantage for the client is that it saves the time to send the request which may range from a few milliseconds to half a second, depending on where on the globe both are located. The disadvantage is that the client may get sent things it already has in its cache. Sure, HTTP/2 allows for the early cancellation of such requests, but still there are resources wasted.
To summarize: there is no one good strategy on how to make best use of this feature of HTTP/2 and everyone is still experimenting. So, how do you experiment with it in Apache httpd?
Link
headers
in a certain format:
If the connection supports PUSH, these two resources will be sent to the client. As a web developer, you may set these headers either directly in your application response or you configure the server via
If you want to use preload
links without triggering a PUSH, you
can use the nopush
parameter, as in
or you may disable PUSHes for your server entirely with the directive
And there is more:
The module will keep a diary of what has been PUSHed for each connection (hashes of URLs, basically) and will not PUSH the same resource twice. When the connection closes, this information is discarded.
There are people thinking about how a client can tell a server what it already has, so PUSHes for those things can be avoided, but this is all highly experimental right now.
Another experimental draft that has been implemented in
PUSH might not always trigger the request/response/performance that one expects or hopes for. There are various studies on this topic to be found on the web that explain benefits and weaknesses and how different features of client and network influence the outcome. For example: just because the server PUSHes a resource does not mean a browser will actually use the data.
The major thing that influences the response being PUSHed is the request that was
simulated. The request URL for a PUSH is given by the application, but where do the
request headers come from? For example, will the PUSH request a accept-language
header and if yes with what value?
Apache will look at the original request (the one that triggered the PUSH) and copy the
following headers over to PUSH requests: user-agent
, accept
,
accept-encoding
, accept-language
, cache-control
.
All other headers are ignored. Cookies will also not be copied over. PUSHing resources that require a cookie to be present will not work. This can be a matter of debate. But unless this is more clearly discussed with browser, let's err on the side of caution and not expose cookie where they might oridinarily not be visible.
An alternative to PUSHing resources is to send Link
headers to the
client before the response is even ready. This uses the HTTP feature called "Early Hints" and
is described in RFC 8297.
In order to use this, you need to explicitly enable it on the server via
(It is not enabled by default since some older browser tripped on such responses.)
If this feature is on, you can use the directive
This will send out a "103 Early Hints"
response to a client as soon
as the server starts processing the request. This may be much early than
the time the first response headers have been determined, depending on your web
application.
If