1

When I deploy a spring boot application on an external tomcat server, do I need to configure HTTP2 on the tomcat server as well my spring boot application? I am a bit confused here about how the communication occurs when I call my spring application deployed inside of Tomcat via the browser or any other client say, Postman.

I have enabled HTTP2 on Tomcat and verified the same:

0:0:0:0:0:0:0:1 - - [08/Jan/2023:18:28:44 +0530] "GET / HTTP/2.0" 200 11408
0:0:0:0:0:0:0:1 - - [08/Jan/2023:18:28:44 +0530] "GET /tomcat.svg HTTP/2.0" 200 68761
0:0:0:0:0:0:0:1 - - [08/Jan/2023:18:28:44 +0530] "GET /tomcat.css HTTP/2.0" 200 5895

and I have configured my spring boot application to use HTTP2 as well using the steps mentioned in this link.

When I am calling my RestController deployed in the external tomcat, I am still getting HTTP 1.1

127.0.0.1 - - [08/Jan/2023:23:41:26 +0530] "HEAD /demo-0.0.1-SNAPSHOT/ HTTP/1.1" 200 -
127.0.0.1 - - [08/Jan/2023:23:41:51 +0530] "HEAD /demo-0.0.1-SNAPSHOT/getMessage HTTP/1.1" 200 -

where demo-0.0.1-SNAPSHOT is the deployed artifact.

I verified the same using curl

HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 41
Date: Sun, 08 Jan 2023 18:11:51 GMT

What am I missing here?

My application.properties file looks like:

# configuring SSL
server.port=8443
server.ssl.key-store-type=pkcs12
server.ssl.key-store=classpath:springboot.p12
server.ssl.key-store-password=password
server.ssl.key-alias=springboot

# enabling http2
server.http2.enabled=true

and I have created the Keystore correctly using the following command:

keytool -genkeypair -alias springboot -keyalg RSA -keysize 4096 -storetype PKCS12 -keystore springboot.p12 -validity 3650 -storepass password

enter image description here

EDIT 1: Spring Boot version - 2.7.2 Tomcat server - 9.0.70

In my server.xml, I have commented and edited the following Connector:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="200" SSLEnabled="true">
        <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
        <SSLHostConfig>
            <Certificate certificateKeystoreFile="ssl/tomcat.jks"
                         certificateKeyAlias="tomcat"
                         certificateKeystorePassword="password"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>

which has helped me enable TLS as well as HTTP2 both on Tomcat. The problem is when I am deploying a spring boot application and making rest calls to that application's RestController, I am getting HTTP1.1 response. Making calls to Tomcat webservices is giving correct HTTP2 response.

Adithya
  • 2,923
  • 5
  • 33
  • 47

2 Answers2

1

Tomcat as standalone sever has by default in it's sever.xml disabled the connector for http 2.

Spring Boot 2, up to Tomcat 9

If this is a spring boot 2 deployed as war application then this could be using up to Tomcat 9.

You must find your Tomcat 9 (Server.xml) connector for http2 under the deployed server conf directory and uncomment this connector, while also providing the necessary certificate files.

You need to uncomment the

   <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
               maxThreads="150" SSLEnabled="true" >
        <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
        <SSLHostConfig>
            <Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
                         certificateFile="conf/localhost-rsa-cert.pem"
                         certificateChainFile="conf/localhost-rsa-chain.pem"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>

Spring Boot 3, Tomcat 10 or later

In case you have a spring boot 3 deployed as war application then this should be using Tomcat 10 or later.

You must find your Tomcat 10 (Server.xml) connector for http2 under the deployed server conf directory and uncomment while also providing the necessary certificate file.

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true">
        <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
        <SSLHostConfig>
            <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>
Panagiotis Bougioukos
  • 15,955
  • 2
  • 30
  • 47
  • As per https://stackoverflow.com/questions/68810106/fastest-connection-for-tomcat-9-0-in-2021-nio-or-apr, I can go ahead with NIO protocol. Should I use APR? I am not using Tomcat native binaries. I have normal distribution version downloaded. Hope that helps. Added spring boot and tomcat versions – Adithya Jan 09 '23 at 04:17
  • @Adithya as you can see this can be opinion based question. Check the documentation and then decide which suits you better. – Panagiotis Bougioukos Jan 09 '23 at 08:18
  • That's fine. I am currently using NIO as mentioned in my edits. My issue as I mentioned is with spring boot applications rest controller. Tomcat network calls are already showing HTTP2 protocol correctly. – Adithya Jan 09 '23 at 09:49
  • @Adithya share the curl commands you execute both for tomcat and for application web services that return `http1.1` vs `http2` – Panagiotis Bougioukos Jan 09 '23 at 10:23
  • curl -k -sI https://localhost:8443/ curl -k -sI https://localhost:8443/demo-0.0.1-SNAPSHOT – Adithya Jan 09 '23 at 11:30
0

I found the solution. While deploying a spring boot application on external tomcat there is no need to specify Server SSL and HTTP2 parameters in the spring properties file as Tomcat will handle all the HTTPS requests. I was trying to mix 2 things.

Configuring the Spring Boot application to support HTTP2 will work if we are deploying using an embedded Tomcat server and I was able to verify that with Chrome browser.

As of writing this post, Postman still doesn't support HTTP2 requests, hence, I was seeing HTTP 1.1 protocol in the Tomcat access log. The same thing I believe is the issue with curl request. As my certificate is self-signed, I am using options -k and -sI. Maybe that's the reason, I am getting the response :

HTTP/1.1 200
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 10 Jan 2023 18:09:29 GMT

when running curl -k -sI https://localhost:8443. I will figure out why I am getting HTTP 1.1 and update it here.

Sharing this answer to help anyone coming across this question next time.

Adithya
  • 2,923
  • 5
  • 33
  • 47