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?
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?
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.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());
}
});
}
}
};
}
h2c
will work as-is but not many (any?) browsers support it. If you want it to work securely (h2
), you'll need to jump through some hoops with Tomcat Native. –
Bellringer 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
libtcnative
as noted in the Spring Boot docs. Spring Boot 2.1.x will ship with Tomcat 9. –
Public Spring Boot 2.2.0+ ships by default with Tomcat 9.0.x which supports HTTP/2 out of the box when using JDK 9 or later. Link
© 2022 - 2024 — McMap. All rights reserved.