Jetty’s HTTP/2 support is surprisingly easy to enable, but it requires a specific keystore format that trips up most people.

Let’s see it in action. Imagine you have a simple Jetty server running on port 8443, and you want to upgrade it to HTTP/2.

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.http2.server.HTTP2CServerConnector; // For HTTP/2 Cleartext
import org.eclipse.jetty.http2.server.HTTP2ServerConnector; // For HTTP/2 TLS

public class JettyHttp2Server {

    public static void main(String[] args) throws Exception {
        Server server = new Server();

        // --- Configuration for HTTP/2 over TLS (Recommended) ---
        SslContextFactory sslContextFactory = new SslContextFactory();
        sslContextFactory.setKeyStorePath("path/to/your/keystore.jks"); // Your Java Keystore file
        sslContextFactory.setKeyStorePassword("your_keystore_password");
        sslContextFactory.setKeyManagerPassword("your_key_password"); // Password for the private key

        HTTP2ServerConnector sslConnector = new HTTP2ServerConnector(server, sslContextFactory);
        sslConnector.setPort(8443);
        server.addConnector(sslConnector);

        // --- Configuration for HTTP/2 Cleartext (Not Recommended for production) ---
        // HTTP2CServerConnector http2cConnector = new HTTP2CServerConnector(server);
        // http2cConnector.setPort(8080);
        // server.addConnector(http2cConnector);

        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        // Add your servlets or resources here
        server.setHandler(context);

        server.start();
        server.join();
    }
}

The magic happens with HTTP2ServerConnector. This connector, unlike the standard ServerConnector, is specifically designed to negotiate and handle HTTP/2 connections over TLS. If you’re just experimenting or have a very controlled internal network, you could use HTTP2CServerConnector for HTTP/2 cleartext (without TLS), but browsers will generally refuse to connect to non-TLS HTTP/2.

So, how does this actually work? HTTP/2 is a multiplexed protocol, meaning multiple requests and responses can be interleaved over a single TCP connection. To enable this, Jetty needs to be aware of the HTTP/2 framing layer. The HTTP2ServerConnector integrates this layer. For TLS, it also performs the ALPN (Application-Layer Protocol Negotiation) handshake. During the TLS handshake, the client and server negotiate which application protocols they support. For HTTP/2 over TLS, the agreed-upon protocol identifier is h2. If this negotiation succeeds, Jetty knows to treat the subsequent stream as HTTP/2.

The core problem most people run into is the SslContextFactory. It needs a Java Keystore (.jks file) that contains a private key and its corresponding certificate. This keystore must be generated with specific algorithms that Jetty (and modern browsers) expect for HTTP/2. A common mistake is using an older keystore or one generated with algorithms not compatible with HTTP/2’s TLS requirements.

Here’s the mental model:

  1. Client Initiates: A browser or client wants to connect to your server.
  2. TLS Handshake (with ALPN): The client and server establish a secure TLS connection. Crucially, during this handshake, they exchange supported application protocols. The client offers http/1.1 and h2. The server, if configured correctly, will also offer h2. They agree on h2.
  3. HTTP/2 Connection: Once TLS is established and h2 is agreed upon via ALPN, Jetty’s HTTP2ServerConnector takes over. It understands the HTTP/2 framing and multiplexing.
  4. Requests/Responses: Multiple requests are sent as frames on the single connection, and responses are received similarly, all managed by Jetty’s HTTP/2 engine.

The SslContextFactory is the gatekeeper for TLS. It loads your identity (private key and certificate) from the keystore. Jetty uses this identity to authenticate itself to the client during the TLS handshake. The passwords are required to unlock the keystore and the private key within it.

The most surprising true thing about enabling HTTP/2 in Jetty is that the HTTP2CServerConnector does not require a keystore, but it’s almost never usable for web traffic because browsers will only initiate HTTP/2 over TLS. You can configure a server to listen on a cleartext port and accept HTTP/2 connections, but your primary use case will always be the TLS connector.

If you’ve correctly configured your SslContextFactory and are still not seeing HTTP/2, the next error you’ll likely encounter is a TLS handshake failure, often with an ALPN negotiation error in the client’s or server’s logs.

Want structured learning?

Take the full Http2 course →