Server-Side HTTP/2 (Preview)

Warning

Server-Side HTTP/2 support in akka-http is currently available as a preview. This means it is ready to be evaluated, but the APIs and behavior are likely to change.

Enable HTTP/2 support

To enabled HTTP/2 support akka-http2-support must be added as a dependency:

sbt
"com.typesafe.akka" %% "akka-http2-support" % "10.0.10"
maven
<dependency>
    <groupId>com.typesafe.akka</groupId>
    <artifactId>akka-http2-support_2.12</artifactId>
    <version>10.0.10</version>
</dependency>
gradle
dependencies {
  compile group: 'com.typesafe.akka', name: 'akka-http2-support_2.12', version: '10.0.10'
}

HTTP/2 can then be enabled through configuration:

akka.http.server.preview.enable-http2 = on

Use bindAndHandleAsync and HTTPS

Only secure HTTP/2 (also known as “over HTTPS” or “with TLS”) connections are supported as this is the prime mode of operation for this protocol. While un-encrypted connections are allowed by HTTP/2, clients that support this are rare. See the HTTPS section for how to set up HTTPS.

You can use Http().bindAndHandleAsyncHttp().get(system).bindAndHandleAsync() as long as you followed the above steps:

Scala
import akka.http.scaladsl.Http

  Http().bindAndHandleAsync(asyncHandler, interface = "localhost", port = 8443, httpsServerContext)
Java
import akka.http.javadsl.Http;
import static akka.http.javadsl.ConnectHttp.toHostHttps;

    Http.get(system)
      .bindAndHandleAsync(
        asyncHandler,
        toHostHttps("127.0.0.1", 8443).withCustomHttpsContext(httpsConnectionContext),
        materializer);

Note that bindAndHandle currently does not support HTTP/2, you must use bindAndHandleAsync.

Testing with cURL

At this point you should be able to connect, but HTTP/2 may still not be available.

You’ll need a recent version of cURL compiled with HTTP/2 support (for OSX see this article). You can check whether your version supports HTTP2 with curl --version, look for the nghttp2 extension and the HTTP2 feature:

curl 7.52.1 (x86_64-pc-linux-gnu) libcurl/7.52.1 OpenSSL/1.0.2l zlib/1.2.8 libidn2/0.16 libpsl/0.17.0 (+libidn2/0.16) libssh2/1.8.0 nghttp2/1.23.1 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL

When you connect to your service you may now see something like:

$ curl -k -v https://localhost:8443
(...)
* ALPN, offering h2
* ALPN, offering http/1.1
(...)
* ALPN, server accepted to use h2
(...)
> GET / HTTP/1.1
(...)
< HTTP/2 200
(...)

If your curl output looks like above, you have successfully configured HTTP/2. However, on JDKs up to version 9, it is likely to look like this instead:

$ curl -k -v https://localhost:8443
(...)
* ALPN, offering h2
* ALPN, offering http/1.1
(...)
* ALPN, server did not agree to a protocol
(...)
> GET / HTTP/1.1
(...)
< HTTP/1.1 200 OK
(...)

This shows curl declaring it is ready to speak h2 (the shorthand name of HTTP/2), but could not determine whether the server is ready to, so it fell back to HTTP/1.1. To make this negotiation work you’ll have to configure ALPN as described below.

Application-Layer Protocol Negotiation (ALPN)

Application-Layer Protocol Negotiation (ALPN) is used to negotiate whether both client and server support HTTP/2.

ALPN support comes with the JVM starting from version 9. If you’re on a previous version of the JVM, you’ll have to load a Java Agent to provide this functionality. We recommend the agent from the Jetty project, jetty-alpn-agent.

manually

This agent can be loaded with the JVM option -javaagent:/path/to/jetty-alpn-agent-2.0.6.jar.

  java -javaagent:/path/to/jetty-alpn-agent-2.0.6.jar -jar app.jar

sbt

sbt can be configured to load the agent with the sbt-javaagent plugin:

  .enablePlugins(JavaAgent)
  .settings(
    javaAgents += "org.mortbay.jetty.alpn" % "jetty-alpn-agent" % "2.0.6" % "runtime"
  )

This should automatically load the agent when running, testing, or even in distributions made with sbt-native-package.

maven

To configure maven to load the agent when running mvn exec:exec, add it as a ‘runtime’ dependency:

<dependency>
    <groupId>org.mortbay.jetty.alpn</groupId>
    <artifactId>jetty-alpn-agent</artifactId>
    <version>2.0.6</version>
    <scope>runtime</scope>
</dependency>

and use the maven-dependency-plugin:

<plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.5.1</version>
    <executions>
        <execution>
            <id>getClasspathFilenames</id>
            <goals>
                <goal>properties</goal>
            </goals>
        </execution>
     </executions>
</plugin>

to add it to the exec-maven-plugin arguments:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.6.0</version>
    <configuration>
        <executable>java</executable>
        <arguments>
            <argument>-javaagent:${org.mortbay.jetty.alpn:jetty-alpn-agent:jar}</argument>
            <argument>-classpath</argument>
            <classpath />
            <argument>com.example.HttpServer</argument>
        </arguments>
    </configuration>
</plugin>
The source code for this page can be found here.