Tomcat 8.5, which will be the default in Spring Boot 1.4, supports HTTP/2.
How can HTTP/2 be enabled in a Spring Boot application?
Enabling HTTP/2 at the Spring Boot level In the application. properties file, enable HTTP/2 and restart the application. Now, let's use curl to validate the HTTP version in use. This provides us with a response, like the one shown below.
You can enable HTTP/2 support in your Spring Boot application with the server. http2. enabled configuration property. This support depends on the chosen web server and the application environment, since that protocol is not supported out-of-the-box by JDK8.
In Spring Boot 2.1 and above it is as simple as adding this property to your .properties (or .yml) file:
server.http2.enabled=true
You can also do it programmatically like this (in one of your configuration classes):
@Bean
public ConfigurableServletWebServerFactory tomcatCustomizer() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addConnectorCustomizers(connector -> connector.addUpgradeProtocol(new Http2Protocol()));
return factory;
}
You need to add the HTTP 2 upgrade protocol to Tomcat's connector. You can do that by customizing the embedded Tomcat container:
@Bean
public EmbeddedServletContainerCustomizer tomcatCustomizer() {
return (container) -> {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
((TomcatEmbeddedServletContainerFactory) container)
.addConnectorCustomizers((connector) -> {
connector.addUpgradeProtocol(new Http2Protocol());
});
}
};
}
@Bean
public EmbeddedServletContainerCustomizer tomcatCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
((TomcatEmbeddedServletContainerFactory) container)
.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
connector.addUpgradeProtocol(new Http2Protocol());
}
});
}
}
};
}
The most elegant and best-performing way to enable HTTP/2
with a Spring Boot application follows here.
First, as mentioned in Andy Wilkinson's answer, you need to enable HTTP/2 at Tomcat level:
@Bean
public EmbeddedServletContainerCustomizer tomcatCustomizer() {
return (container) -> {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
((TomcatEmbeddedServletContainerFactory) container)
.addConnectorCustomizers((connector) -> {
connector.addUpgradeProtocol(new Http2Protocol());
});
}
};
}
In case you are not using an embedded Tomcat, you can set up HTTP/2 listening like this:
<Connector port="5080" protocol="HTTP/1.1" connectionTimeout="20000">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
</Connector>
Remember that you need Tomcat >= 8.5.
Then, you should use HAProxy
(version >= 1.7) in front of Tomcat to take care of encryption.
The client will speak https to HAProxy, and HAProxy will speak cleartext HTTP/1.1 or HTTP/2 to the backend, as the client requested. There will be no unnecessary protocol translations.
The matching HAProxy-configuration is here:
# Create PEM: cat cert.crt cert.key ca.crt > /etc/ssl/certs/cert.pem
global
tune.ssl.default-dh-param 2048
ssl-default-bind-options no-sslv3 no-tls-tickets force-tlsv12
ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
chroot /var/lib/haproxy
user haproxy
group haproxy
defaults
timeout connect 10000ms
timeout client 60000ms
timeout server 60000ms
frontend fe_https
mode tcp
rspadd Strict-Transport-Security:\ max-age=31536000;\ includeSubDomains;\ preload
rspadd X-Frame-Options:\ DENY
bind *:443 ssl crt /etc/ssl/certs/cert.pem alpn h2,http/1.1
default_backend be_http
backend be_http
mode tcp
server domain 127.0.0.1:8080
# compression algo gzip # does not work in mode "tcp"
# compression type text/html text/css text/javascript application/json
Edit 2019
I face two problems when using mode "tcp"
Generally, since haproxy proxies a lower level tcp connection, there is no access to any http stuff
In Spring Boot 2 you first need a certificate - it can by generated like this:
keytool -genkey -keyalg RSA -alias my-the-best-api -keystore c:\tmp\keystore.store -storepass secret -validity 3650 -keysize 2048
Than you just need to add this certificate to classpath and add needed properties to application.properties:
server.http2.enabled=true
server.port = 8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With