HTTP/2 guide - Apache HTTP Server Version 2.4
Modules
Directives
FAQ
Glossary
Apache HTTP Server Version 2.4
Apache
HTTP Server
Documentation
Version 2.4
How-To / Tutorials
HTTP/2 guide
Available Languages:
en
es
fr
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.
The HTTP/2 protocol
HTTP/2 in Apache httpd
Build httpd with HTTP/2 support
Basic Configuration
MPM Configuration
Clients
Useful tools to debug HTTP/2
Server Push
Early Hints
See also
mod_http2
Comments
The HTTP/2 protocol
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:
HTTP/2 is a
binary protocol
, as opposed to HTTP 1.1 that is plain text. The latter is meant to be human readable (for example sniffing network traffic) meanwhile the former is not. More info in the official FAQ
question
h2
is HTTP/2 over TLS (protocol negotiation via ALPN).
h2c
is HTTP/2 over TCP.
frame
is the smallest unit of communication within an HTTP/2 connection, consisting of a header and a variable-length sequence of octets structured according to the frame type. More info in the official documentation
section
stream
is a bidirectional flow of frames within the HTTP/2 connection. The correspondent concept in HTTP 1.1 is a request/response message exchange. More info in the official documentation
section
HTTP/2 is able to run
multiple streams
of data over the same TCP connection, avoiding the classic HTTP 1.1 head of blocking slow request and avoiding to re-instantiate TCP connections for each request/response (KeepAlive patched the problem in HTTP 1.1 but did not fully solve it).
HTTP/2 in Apache httpd
The HTTP/2 protocol is implemented by its own httpd module, aptly named
mod_http2
. It implements the complete set
of features described by RFC 7540 and supports HTTP/2 over cleartext (http:), as
well as secure (https:) connections. The cleartext variant is 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.
Build httpd with HTTP/2 support
mod_http2
uses the library of
nghttp2
as its implementation base. In order to build
mod_http2
you need at least version 1.2.1 of
libnghttp2
installed on your system.
When you
./configure
your 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=
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
mod_ssl
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.
Basic Configuration
When you have a
httpd
built with
mod_http2
you need some
basic configuration for it becoming active. The first thing, as with every Apache module,
is that you need to load it:
LoadModule http2_module modules/mod_http2.so
The second directive you need to add to your server configuration is
Protocols h2 http/1.1
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:
Protocols h2 h2c http/1.1
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:
Protocols http/1.1

ServerName test.example.org
Protocols h2 http/1.1

This allows only HTTP/1 on connections, except SSL connections to
test.example.org
which offer HTTP/2.
Choose a strong SSLCipherSuite
The
SSLCipherSuite
needs to be configured with
a strong TLS cipher suite. The current version of
mod_http2
does not enforce any cipher but most
clients do so. Pointing a browser to a
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 reject list
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
Protocols http/1.1 h2
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
Protocols h2 h2c http/1.1
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:
ProtocolsHonorOrder Off
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
Protocols
with any

checks.
For more advanced tips on configuration, see the
modules section about dimensioning
and
how to manage multiple hosts with the same certificate
MPM Configuration
HTTP/2 is supported in all multi-processing modules that come with httpd. However, if
you use the
prefork
mpm, there will be severe restrictions.
In
prefork
mod_http2
will only process one request at at time
per connection. But clients, such as browsers, will send many requests at the same time.
If one of these takes long to process (or is a long polling one), the other requests will
stall.
mod_http2
will not work around this limit by default. The reason is that
prefork
is today only chosen, if you run processing engines that are not
prepared for multi-threading, e.g. will crash with more than one request.
If your setup can handle it, configuring
event
mpm is nowadays
the best one (if supported on your platform).
If you are really stuck with
prefork
and want multiple requests,
you can tweak the
H2MinWorkers
to make
that possible. If it breaks, however, you own both parts.
Clients
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
Useful tools to debug HTTP/2
The first tool to mention is of course
curl
. Please make sure that
your version supports HTTP/2 checking its
Features
$ curl -V
curl 7.45.0 (x86_64-apple-darwin15.0.0) libcurl/7.45.0 OpenSSL/1.0.2d zlib/1.2.8 nghttp2/1.3.4
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 [...]
Features: IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP
HTTP2
Mac OS homebrew notes
brew install curl --with-openssl --with-nghttp2
And for really deep inspection
wireshark
The
nghttp2
package also includes clients, such as:
nghttp
- useful to visualize the HTTP/2 frames and get a better idea of the protocol.
h2load
- useful to stress-test your server.
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.
Server Push
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?
mod_http2
inspect response header for
Link
headers
in a certain format:
Link ;rel=preload, ; rel=preload
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

Header add Link ";rel=preload"
Header add Link ";rel=preload"

If you want to use
preload
links without triggering a PUSH, you
can use the
nopush
parameter, as in
Link ;rel=preload;nopush
or you may disable PUSHes for your server entirely with the directive
H2Push Off
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
mod_http2
is the
Accept-Push-Policy Header Field
where a client can, for each request, define
what kind of PUSHes it accepts.
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 ordinarily not be visible.
Early Hints
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
H2EarlyHints on
(It is not enabled by default since some older browser tripped on such responses.)
If this feature is on, you can use the directive
H2PushResource
to
trigger early hints and resource PUSHes:

H2PushResource /xxx.css
H2PushResource /xxx.js

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
H2Push
is enabled, this will also start the PUSH right after the
103 response. If
H2Push
is disabled however, the 103 response will be send
nevertheless to the client.
Available Languages:
en
es
fr
Copyright 2026 The Apache Software Foundation.
Licensed under the
Apache License, Version 2.0
Modules
Directives
FAQ
Glossary