Enable HTTP/2 with Tomcat in Spring Boot

HTTP/2 is a major upgrade to the HTTP protocol that offers significant performance improvements over its predecessor, HTTP/1.1. In this blog post, we'll explore how to enable HTTP/2 support in a Spring Boot application using Tomcat as the embedded web server. We'll cover the necessary configurations, best practices, and example usage to help you take advantage of the benefits of HTTP/2 in your Spring Boot projects.

Table of Contents#

  1. Prerequisites
  2. Configuring Tomcat for HTTP/2
  3. Spring Boot Application Configuration
  4. Testing HTTP/2 Support
  5. Best Practices
  6. Example Usage
  7. References

Prerequisites#

Before we begin, make sure you have the following:

  • A Spring Boot project (version 2.0 or higher)
  • Java 8 or higher
  • Tomcat 9 or higher (since HTTP/2 support was introduced in Tomcat 9)
  • Note for Java 8 users: HTTP/2 requires ALPN (Application-Layer Protocol Negotiation) support. Since Java 8 does not include ALPN natively, you need to add an ALPN implementation such as spring-boot-starter-undertow (which includes Undertow's ALPN support) or the Jetty ALPN agent. Spring Boot's default Tomcat setup requires additional configuration for ALPN on Java 8.

Configuring Tomcat for HTTP/2#

Step 1: Add Tomcat Dependency#

If you're using Spring Boot's default embedded Tomcat server, you don't need to add an explicit dependency. However, if you're using a different server or need to manage the Tomcat version explicitly, you can add the following dependency to your pom.xml (for Maven) or build.gradle (for Gradle):

Maven

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>

Gradle

implementation 'org.springframework.boot:spring-boot-starter-tomcat'

Step 2: Configure Tomcat Connector#

To enable HTTP/2, we need to configure the Tomcat connector to use the HTTP/2 protocol. In your Spring Boot application's configuration file (e.g., application.properties or application.yml), add the following properties:

application.properties

server.tomcat.protocol-header=x-forwarded-proto
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.add-remote-ip-header=true
server.tomcat.max-http-post-size=0
server.port=8443
server.ssl.enabled=true
server.ssl.protocol=TLSv1.2
server.ssl.enabled-protocols=TLSv1.2,TLSv1.3
server.ssl.ciphers=ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-CHACHA20-POLY1305,ECDHE-RSA-CHACHA20-POLY1305,DHE-RSA-AES128-GCM-SHA256,DHE-RSA-AES256-GCM-SHA384
server.ssl.client-auth=want
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=changeit
server.ssl.key-alias=tomcat

application.yml

server:
  port: 8443
  ssl:
    enabled: true
    protocol: TLSv1.2
    enabled-protocols: TLSv1.2,TLSv1.3
    ciphers: ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-CHACHA20-POLY1305,ECDHE-RSA-CHACHA20-POLY1305,DHE-RSA-AES128-GCM-SHA256,DHE-RSA-AES256-GCM-SHA384
    client-auth: want
    key-store-type: PKCS12
    key-store: classpath:keystore.p12
    key-store-password: changeit
    key-alias: tomcat
  tomcat:
    protocol-header: x-forwarded-proto
    remote-ip-header: x-forwarded-for
    add-remote-ip-header: true
    max-http-post-size: 0

These properties configure the Tomcat connector to use HTTPS (required for HTTP/2) and specify the SSL/TLS settings. Make sure to replace the key-store and key-store-password values with your actual keystore file and password.

Spring Boot Application Configuration#

Step 1: Add SSL Configuration#

If you're using HTTPS (which is required for HTTP/2), you need to configure SSL in your Spring Boot application. You can generate a self-signed certificate or use a trusted certificate from a certificate authority (CA).

Generating a Self-Signed Certificate You can use the keytool utility (provided with Java) to generate a self-signed certificate:

keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650

Follow the prompts to enter the required information (e.g., keystore password, key password, CN, etc.).

Step 2: Configure Spring Boot to Use SSL#

In your Spring Boot application's main class (e.g., Application.java), add the following annotation to enable SSL:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
 
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Testing HTTP/2 Support#

Step 1: Start the Application#

Run your Spring Boot application using your preferred method (e.g., mvn spring-boot:run or gradle bootRun).

Step 2: Check HTTP/2 Support#

You can use tools like curl or a web browser to check if HTTP/2 is enabled.

Using curl

curl -I --http2 https://localhost:8443

If HTTP/2 is enabled, you should see the HTTP/2 protocol in the response headers.

Using a Web Browser Open your web browser and navigate to https://localhost:8443. Check the browser's developer tools (e.g., Chrome DevTools) to see if the connection is using HTTP/2.

Best Practices#

  • Use HTTPS: HTTP/2 requires HTTPS, so always use secure connections for your applications.
  • Keep Dependencies Up to Date: Regularly update your Spring Boot, Tomcat, and other dependencies to ensure security and performance improvements.
  • Test Thoroughly: Test your application thoroughly to ensure that HTTP/2 is working as expected and that there are no compatibility issues with your existing code.
  • Monitor Performance: Use monitoring tools to track the performance of your application and identify any bottlenecks or issues related to HTTP/2.

Example Usage#

Here's a simple example of a Spring Boot controller that returns a "Hello, World!" message:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class HelloWorldController {
 
    @GetMapping("/")
    public String helloWorld() {
        return "Hello, World!";
    }
}

You can access this endpoint using https://localhost:8443/ (assuming your application is running on port 8443).

References#