Let's Encrypt with Docker Tomcat
In the previous blog post we’ve used self-signed certificate with Docker Tomcat. However, in order to have a properly protected web site, we need to use a proper set of certificates. We’ll use the Let’s Encrypt authority to obtain the keys at no cost.
Preparing the server and DNS
First, create a virtual server running Ubuntu 17.10, then make sure you can SSH into that box or you can at least launch a console via the cloud vendor web page. Write down the server IP.
Second, register a DNS domain, for example at GoDaddy. I’ll register
your-page.eu but you’re free to register whatever domain you see fit. You will then need to edit the DNS records for that domain, and make sure that
A record points to your server’s IP.
Obtaining SSL certificates from Let’s Encrypt
Now let’s obtain the certificates from Let’s Encrypt. The easiest way is to use Certbot which comes pre-packaged in Ubuntu 17.10. Run the following in your box terminal:
sudo apt install certbot certbot certonly
Certbot is going to ask you a couple of questions. I tend to prefer to use the standalone mode (the certbot takes over port 80 and does everything on its own; this collides with Tomcat listening on 80 but since we need to stop Tomcat to renew the certificates anyway this is perfectly fine). Then just make sure to pass in both
www.your-page.eu so that both domains are SSL-protected.
When Certbot finishes, you’ll be able to find the certificate files at
/etc/letsencrypt/live/your-page.eu. We will now register the certificates into Tomcat.
Running dockerized Tomcat with the certificates
Let’s deploy your app in a way that everything can be started using the
docker-compose up -d command. The easiest way is to create a directory named
/root/app/ and place the following
docker-compose.yml file there:
version: '2' services: web: image: tomcat:9.0.5-jre8 ports: - "80:8080" - "443:8443" volumes: - /etc/letsencrypt:/etc/letsencrypt - ./server.xml:/usr/local/tomcat/conf/server.xml
Note: we need to map the entire
/etc/letsencryptinto the Docker container; just mapping the
/etc/letsencrypt/live/your-page.eufolder alone is not enough since those
pemfiles are symlinks which would stop working in Docker and Tomcat would fail with
Feel free to use the
server.xml from the self-signed openssl article, but change the appropriate connector part to:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol" maxThreads="150" SSLEnabled="true" > <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" /> <SSLHostConfig> <Certificate certificateKeyFile="/etc/letsencrypt/live/your-page.eu/privkey.pem" certificateFile="/etc/letsencrypt/live/aedict-online.eu/cert.pem" certificateChainFile="/etc/letsencrypt/live/aedict-online.eu/chain.pem" type="RSA" /> </SSLHostConfig> </Connector>
Now go into
/root/app and try to run the Tomcat server:
cd /root/app docker-compose up
pems are not password-protected so it should work.
Note: if Tomcat stops on
Deploying web application directoryand seems to do nothing, it may have ran out of entropy. You can verify this by running
cat /proc/sys/kernel/random/entropy_avail- if this prints anything less than 100-200 then just run
apt install havegedto help building up the entropy pool. Tomcat will take 2 minutes to start at first, but when the entropy is high, further starts will be much quicker. You can read more at Tomcat Hangs.
Now you can visit https://your-page.eu and you should see the Tomcat welcome page protected by https. Good job!
You can also verify at https://www.digicert.com/help/ that your SSL certificate is working properly.
Let’s Encrypt certificates only last for 90 days. Luckily the certificates can be renewed when they are older than 60 days, which gives us some time to do the renewal process. The certificates can be updated automatically using the Certbot. The Certbot can run hook scripts before and after the renewal happens, so that:
- we can stop Tomcat in order for the Certbot to take over the port 80,
- we can start Tomcat to reload certificates when the new certificates are in place
Let’s create two scripts:
#!/bin/bash set -e -o pipefail date cd /root/app docker-compose up -d
#!/bin/bash set -e -o pipefail date cd /root/app docker-compose down
docker-compose down will block until all containers are stopped, and it will unbind from port 80 prior terminating, which gives room for Certbot’s own server.
To run the renewal process automatically, run
and add the following line:
30 2 * * 1 certbot renew --pre-hook "/root/stop_server" --post-hook "/root/start_server" >> /var/log/le-renew.log
That will make Certbot to check for new certificates every week at night. Certbot will do nothing if the certificates do not need to be renewed (since they’re younger than 60 days). If the certificates need to be renewed (they are older than 60 days) it will stop the Tomcat server, update the certificates and then start the Tomcat server.