Blog

Enabling HTTPS in your Java server using a free certificate

By  
Johannes Häyry
Johannes Häyry
·
On Feb 7, 2017 7:00:00 AM
·

Using HTTPS connections in web application client-server communication has grown to be more and more common nowadays. In fact, for some types of applications, it’s become a requirement. For example, if you want to use Geolocation API in a web app running in Chrome, you need to have HTTPS enabled. All big browser vendors require HTTPS if you want to use HTTP/2. Even your search rank in Google is higher, if you provide a secure connection. Besides, web app users today are expecting to see that green secure connection indicator in the URL bar. So how does one enable it? Luckily for you as a web app developer, making the web more secure means only a few easy steps, and it’s completely free when using a service called Let’s Encrypt.

What you need before starting

I assume you have a server somewhere and you are running some kind of Java server, such as Jetty or Tomcat. For obtaining and installing the certificate we’ll use a tool called Certbot. Certbot is an ACME (Automatic Certificate Management Environment) protocol client, which fetches a certificate from Let’s Encrypt—an open certificate authority launched by the EFF, Mozilla, and others. Let’s Encrypt is a relatively new CA aiming to lower the complexity of setting up and maintaining TLS (Transport Layer Security). You will need root access in your server to run Certbot.

I’ve tested the steps in this guide using Jetty, but the same steps work at least for Tomcat and WildFly (JBoss). I’ve written the guide to be applicable to practically any Java server. When testing, I used a dashboard web application written in Java using Vaadin Framework and Vaadin Charts.


Example Java web application using the Let's encrypt certificate

Installing Certbot ACME client

You can check if your OS distribution comes packaged with Certbot by visiting https://certbot.eff.org/. From the same address you’ll find more instructions for the specific environment, if you need them. If your OS doesn’t come with certbot, install it using certbot-auto. Certbot-auto is a wrapper script accepting the same control flags as certbot and updating the client code automatically. It requires root access.

wget https://dl.eff.org/certbot-auto
chmod a+x ./certbot-auto
./certbot-auto --help

Related reading that might interest you
Download our free guide to the Future of Web Apps

Obtaining a signed certificate

Certbot has a few plugins that can fetch and install certificates automatically. Unfortunately such a plugin is not available for Java servers. I recommend using either the standalone plugin or the webroot plugin. The standalone plugin starts a lightweight web server and binds it to port 80 or 443 and serves a verification for the Let’s Encrypt validation servers. This means that either port must be free while running the plugin i.e. the Java server must not be running if it uses those ports. To use the standalone plugin, run

certbot-auto certonly --standalone --standalone-supported-challenges http-01 -d yourdomain.com

The --standalone-supported-challenges option value can also be tls-sni-01 to use port 443.

The other choice for the plugin is to use the webroot plugin, which uses an existing running server to serve the ACME protocol verification files. E.g. if your Jetty webapps directory is /opt/jetty/webapps/, run

certbot-auto certonly --webroot -w /opt/jetty/webapps/ROOT -d yourdomain.com

With both webroot plugin and standalone plugin the certonly option certbot will fetch a certificate and store it to /etc/letsencrypt/live/<yourdomain>.

Certificates from Let’s Encrypt are short lived, only 90 days until they expire and must be renewed. Luckily certbot can do this renewal for you with the renew option.

certbot-auto renew

The renew command checks if the certificate actually needs to be updated, so it’s safe to run every day and doesn’t burn your ACME request rate limit. We’ll cover automating the renewal, but first let’s install the certificate to Java keystore.

Installing the certificate to Java keystore

The certificate now needs to be installed to the Java keystore. Before we can install the certificate, we need to combine the private key and the certificate to a PKCS12 format file.

openssl pkcs12 -export -in /etc/letsencrypt/live/yourdomain.com/fullchain.pem -inkey /etc/letsencrypt/live/yourdomain.com/privkey.pem -out /etc/letsenscrypt/live/yourdomain.com/pkcs.p12 -name mytlskeyalias -passout pass:mykeypassword

After the certificate is in PKCS12 format, we remove the previously stored certificate from the keystore. Of course, you need to do this step only if you have previously stored a certificate for your domain e.g. if you have just renewed a certificate and want to store an updated one.

keytool -keystore /path/to/my/keystore -delete -alias ‘mytlskeyalias’ -storepass ‘mystorepassword’

Import the .p12 file to keystore.

keytool -importkeystore -deststorepass mystorepassword -destkeypass mykeypassword -destkeystore /path/to/my/keystore -srckeystore /etc/letsencrypt/live/mydomain.com/pkcs.p12 -srcstoretype PKCS12 -srcstorepass mykeypassword -alias mytlskeyalias

Now the certificate is ready to be used in your Java server. It still needs to be configured though, but let’s automate the certificate renewal first.

Automating the certificate renewal

Obtaining and installing the certificate only once is not enough, as the certificate has an expiration date. Certificates from Let’s Encrypt are quite short lived - only 90 days. The certificates can also be revoked. For the above-mentioned reasons, you should check if your certificates need to be renewed every day. Let’s make a couple of scripts to automate this.

First let’s write a script ‘renew-cert.sh’ for running the validation and renewal of the certificate. You can then put this script into your crontab to be run once a day.

#!/bin/bash
certbot-auto renew --no-self-upgrade --quiet --renew-hook "store-renewed.sh"

The certbot command is the same we used earlier, but now we’ll throw in options --no-self-upgrade to prevent the script updating itself, which is not necessarily wanted in production environment, and --quiet to disable output other than errors. Certbot checks if the certificate needs to be renewed before actually renewing it. We’ll use the --renew-hook option to specify a script or command to be executed in case of the certificate being renewed.

Now, let’s write the script that is run in certbot renew hook. Create a script called ‘store-renewed.sh’ and put in those certificate conversion and keystore commands we used earlier: first pkcs12 conversion, then removing the old key, and finally importing the new key. You can download a sample bash script file and edit it to your own settings.

After updating the certificate in the keystore, you need to restart your Java server. The restart command depends on what server you are using and how you are running it e.g. if you are running Jetty as a service, add service jetty restart to the end of ‘store-renewed.sh’.

Configuring SSL/TLS in your Java server

Putting your certificate in a keystore for the Java server is not enough. You need to configure your server to use the certificate. I’m not going to cover individual server configurations, but here are a few links to how to configure Tomcat 8, Jetty 9 and WildFly 10. After you have configured your Java server to use the certificate, everything should be ready. Good work.

Write your first secure web application with Vaadin—the open source Java web UI framework. Did you know that Vaadin applications are more secure by default?

Read about security in Vaadin

Learn more about Vaadin
Discover the easiest way to build web apps in Java

Related reading that might interest you
Download our free guide to the Future of Web Apps

Johannes Häyry
Johannes Häyry
I'm a developer disguised as a product marketer. I usually write about new Vaadin releases or the upcoming cool features on the roadmap.
Other posts by Johannes Häyry