Automated script for Let’s encrypt HTTPS certificate for JIRA and Tomcat

Author: Ivan Tichý | Last change: 2016-01-04 19:16:16

This is How to use Let’s encrypt HTTS certificates primarily for JIRA or any Tomcat application server. There is a Bash script that will do it for you. You can put it into your Cron jobs to update your certificate every three months.

Why ?

Let’s encrypt will give you free signed certificate you can use for HTTPS. This will help you to get rid of browsers warning messages when you use self-signed certificate.

Preconditions:

  • Installed JIRA or Tomcat
  • Tomcat that is set to use https (how to is here: https://confluence.atlassian.com/…-124008.html  – hint: you need just the part with editing server.xml and web.xml, nothing more).
  • Be sure you have not created or you have deleted all previously created certificates from keystore.

I use Debian Jessie and JIRA 7.0.2 with Tomcat 8.0.17. Please understand that this article and script has been created for my JIRA instance, but it can be used (after modification) with other application running with Tomcat.

How does it work?

Let’s encrypt client will start a web server on you domain to prove you manage the domain (means other people should not be able to get certificate with yours domain name in it). For this I use iptables to redirect communication from port 80 to 9999 with Let’s encrypt client configured to listen on port 9999. For this particular moment you actual web server will not be visible (a few seconds), but you do not have to stop it or do anything else. Other option could be Apache proxy in front of Tomcat.

Step 1

Install Let’s encrypt client. You need to have git client installed on your server.

apt-get install git -y # if you do not have it
mkdir -p /var/git/letsencrypt
cd /var/git
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt

Step 2

Note: for testing purposes keep line with –test-cert uncommented and the other one commented out. Let’s encrypt strictly limits amount of issued certificates. So test with test option on (certificate will be signed by a fake authority). Run this script:

#!/bin/bash
#author Ivan Tichy
#Please modify these values according to your environment
certdir=/etc/letsencrypt/live/jira.ivantichy.cz/ #just replace the domain name after /live/
keytooldir=/opt/atlassian/jira/jre/bin/ #java keytool located in jre/bin
mydomain=jira.ivantichy.cz #put your domain name here
myemail=xxxxxxx@gmail.com #your email
networkdevice=eth0 #your network device  (run ifconfig to get the name)
keystoredir=/home/jira/.keystore #located in home dir of user that you Tomcat is running under - just replace jira with your user you use for Tomcat, see ps -ef to get user name if you do not know

#the script itself:
cd /var/git/letsencrypt
git pull origin master
iptables -I INPUT -p tcp -m tcp --dport 9999 -j ACCEPT
iptables -t nat -I PREROUTING -i $networkdevice -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9999

./letsencrypt-auto certonly --standalone --test-cert --break-my-certs -d $mydomain --standalone-supported-challenges http-01 --http-01-port 9999 --renew-by-default --email $myemail --agree-tos
#./letsencrypt-auto certonly --standalone -d $mydomain --standalone-supported-challenges http-01 --http-01-port 9999 --renew-by-default --email $myemail --agree-tos

iptables -t nat -D PREROUTING -i $networkdevice -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9999
iptables -D INPUT -p tcp -m tcp --dport 9999 -j ACCEPT

$keytooldir/keytool -delete -alias root -storepass changeit -keystore $keystoredir
$keytooldir/keytool -delete -alias tomcat -storepass changeit -keystore $keystoredir

openssl pkcs12 -export -in $certdir/fullchain.pem -inkey $certdir/privkey.pem -out $certdir/cert_and_key.p12 -name tomcat -CAfile $certdir/chain.pem -caname root -password pass:aaa

$keytooldir/keytool -importkeystore -srcstorepass aaa -deststorepass changeit -destkeypass changeit -srckeystore $certdir/cert_and_key.p12 -srcstoretype PKCS12 -alias tomcat -keystore $keystoredir
$keytooldir/keytool -import -trustcacerts -alias root -deststorepass changeit -file $certdir/chain.pem -noprompt -keystore $keystoredir


# restart your Tomcat server – mine is running JIRA
service jira stop
service jira start

Step 3

Test your server here https://www.ssllabs.com/ssltest/ . To get rid of weak DH issues add -Djdk.tls.ephe­meralDHKeySize=2048 to JVM options and add ciphers attribute to Connector tag in your server.xml. Here is my connector configuration:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
   maxHttpHeaderSize="8192" SSLEnabled="true"
   maxThreads="150" minSpareThreads="25"
   enableLookups="false" disableUploadTimeout="true"
   acceptCount="100" scheme="https" secure="true"
   clientAuth="false" sslProtocol="TLS" useBodyEncodingForURI="true" ciphers="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_SHA256,TLS_ECDHE_RSA_WITH_AES_128_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_SHA,TLS_ECDHE_RSA_WITH_AES_256_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_SHA384,TLS_ECDHE_RSA_WITH_AES_256_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_SHA,TLS_DHE_RSA_WITH_AES_128_SHA256,TLS_DHE_RSA_WITH_AES_128_SHA,TLS_DHE_DSS_WITH_AES_128_SHA256,TLS_DHE_RSA_WITH_AES_256_SHA256,TLS_DHE_DSS_WITH_AES_256_SHA,TLS_DHE_RSA_WITH_AES_256_SHA" />

Comments

Martin Cleaver [Blended Perspectives Inc] on 2016-01-05 18:39:38 wrote:

Have you verified that Application Links work with Let's Encrypt?

Saltypoison on 2016-01-28 19:34:22 wrote:

Thank you for this! I modified your script to generate a keystore for a different service (Ubooquity) and had great success. http://ubooquity.userecho.com/topic/1113624-/

Ivan on 2016-02-11 14:48:18 wrote:

Thanks !

Ahmed on 2016-02-14 00:32:29 wrote:

I'm trying to get this to work with Nginx but I'm not sure I can get it to work. I was doing a reverse proxy to http://localhost:8080

do I still keep that setting?

Atanas on 2016-02-16 08:38:50 wrote:

Hi Ahmed, if your nginx is terminating the SSL (which probably is true), then you need to check how to configure nginx with letsencrypt, it's much easier than doing it for tomcat

best atanas

scotv on 2016-04-01 20:30:57 wrote:

when I execute ./letsencrypt-auto certonly... I got 404 error for jira.homesite/.well-known/acme-challenge/g0oG..

How do you config this route.

I searched in google, most people use nginx for mapping the request to local path.

Is there any way to config this routing in tomcat.

Because, I install jira with tomcat, I dont want to install nginx.

andre on 2016-04-07 00:16:54 wrote:

thanks a lot! works like charm :)

pety on 2016-07-04 13:40:56 wrote:

Excellent, works perfectly!

Jonathan on 2016-07-18 17:27:40 wrote:

Thanks, Ivan Tichy, your script helped me solve an issue with Grails and Let's Encrypt certificates! :-)

Ceriel on 2016-08-22 17:07:01 wrote:

Thank you, this script finally triggered me to start using Let's encrypt certificates.

Mladen on 2016-09-02 09:07:30 wrote:

Why is this script opening port 9999 and configuring letsencrypt-auto with –http-01-port 9999 but connector of Tomcat is configured with port 8443?

Mladen on 2016-09-02 09:46:35 wrote:

Ok, got the part about port 9999. Temp opening and disabling I don't know why letsencrypt requires it.

Danny on 2016-09-03 00:07:52 wrote:

Adding

export CATALINA_OPTS="-Djdk.tls.ephemeralDHKeySize=2048"

to /usr/share/tom­cat7/bin/seten­v.sh on Ubuntu with Tomcat 7 didn't worked for me to get rid of weak DH issues. So I ended up using the following ciphers which is giving me an overall rating of A:

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA

Source

Mladen on 2016-09-07 15:31:48 wrote:

I have a problem with Tomcat 8.5.5 07-Sep-2016 15:10:13.146 SEVERE [main] org.apache.ca­talina.connec­tor.Connector­.<init> Protocol handler instantiation failed
java.lang.Clas­sNotFoundExcep­tion: org.apache.co­yote.http11.Http11Pro­tocol
at java.net.URLClas­sLoader.findClas­s(URLClassLoa­der.java:381)

if I put protocol=„HTTP/1.1“ it didn't work either.

The documentation of Tomcat changed between 8.0.17 and 8.5:

https://tomcat.apache.org/…l-howto.html https://tomcat.apache.org/…l-howto.html

Mladen on 2016-09-07 16:07:51 wrote:

Got it running on Tomcat 8.5 with protocol=„org­.apache.coyote­.http11.Http11Ni­oProtocol“
sslImplementa­tionName=„org­.apache.tomcat­.util.net.jsse­.JSSEImplemen­tation“ keystoreFile=„${u­ser.home}/.ke­ystore“ keystorePass=„chan­geit“

But Google chrome is displaying „Your connection is not private“ however this is the step forwards, since no NIO errors displayed in the log. Anyone knows what should I double check now? My keys are NOT generated using params such as –test-cert or –staging

Mladen on 2016-09-11 13:27:30 wrote:

I've installed Tomcat native and APR connector and it working for me.

http://www.sheroz.com/…tu-1204.html

I also got my configuration documented here: https://mladenadamovic.wordpress.com/…ntu-minimal/

Jaroslav Lhotak on 2016-10-13 14:31:23 wrote:

Hello Ivan, great post! A stupid question – do you have any hint how perform the similar auto-renewal on Windows. We're using ACME Win port (https://github.com/…t-win-simple) for IIS instances but Tomcat is kinda weird on Win. Thank you for any hint/link. Jarda

Craig on 2016-11-04 20:26:24 wrote:

Jaroslav – did you get anywhere with the ACME Win port and Tomcat? I am trying to do the same for my Windows JIRA Server, where port 80 is handled by Tomcat instead of by IIS.

asdasda on 2017-01-03 12:18:17 wrote:

Thank you, it works! Note that there is no need to do that iptables magic – you can use letsencrypt renew; to obtain the certificate just do

letsencrypt certonly –webroot -w /home/letsencryp­t/webroot

And configure your Tomcat to serve static files as follows:

<Context docBase=„/home/let­sencrypt/webro­ot/.well-known“ path=„/.well-known“ />

pb on 2017-01-13 17:58:29 wrote:

Thanks for the writeup! Just a heads up – letsencrypt client is now called certbot. Navigating to https://github.com/…/letsencrypt redirects to https://github.com/certbot/certbot

root on 2017-02-09 07:27:38 wrote:

the keytool option -keystore $keystoredir says error that its a directory,

„keytool error: java.io.FileNot­FoundException: /usr/java/jdk1­.8.0_51 (Is a directory)“

it should be a file ex: -keystore jira.jks

Bur on 2017-02-13 08:45:23 wrote:

Thanks you, convenient and simple!

Florian Barbet on 2017-04-21 01:44:49 wrote:

Seriously, thank you bro ; you are AMAZIIIIINNNNNNNG <3

Stefan on 2017-09-06 06:38:40 wrote:

Thank you for your script! I get a 404 error during verification. I can verify that the standalone server is creating a webserver listening on port 9999 but only on IPv6. Could this be the problem? Thank you

Divyesh Kanzariya on 2017-10-02 15:44:43 wrote:

Thanks for automated script :) can you elaborate how to implement this in reverse proxy .

Insert new comment