How to get Tomcat to see HTTPS when it’s terminated elsewhere
It’s very common to terminate HTTPS (TLS) at higher up in your server stack but you still need your webapp running in tomcat to generate the urls using https even though tomcat is called with http internally in your network. This seems to be a very common problem that I keep seeing year after year so this short article will show you how to accomplish that and how to test it’s working.
In this diagram https is terminated at firewall but that could as well be loadbalancer or even http server like Nginx or Apache. For the test setup I’m actually using Nginx and for instructions on how to setup HTTPS with Nginx check out my post on setting up Nginx with Let’s Encrypt. Once you’ve setup https with Nginx add following location block to the server block with HTTPS. This will proxy all requests to tomcat http port 8080.
location ~ / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE_ADDR $remote_addr; proxy_pass http://localhost:8080; }
Tomcat is actually really easy to configure so that it is able to generate URLs with https when the https is terminated somewhere higher in the stack. All you need is to add proxyPort, scheme, and secure to the connector in server.xml. Below is an example. If you are using both http and https then just create a new connector for https traffic that is running in different port and proxy only the https traffic to that port.
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" proxyPort="443" scheme="https" secure="true" />
Now to check that it is actually working correctly you need to check your servlet container is seeing those values correctly. For that purpose I’ve created a simple webapp which you can deploy and call through your stack. It shows if each of the three checks pass and additionally shows the request URL and server name so you can also check that any virtual hosts you use are also passed correctly to the servlet container.
Download HTTPS Checker webapp. See the source in Github.