HOWTO: configure Jetty for SSL/HTTPS

- tested with Jetty 9.3.6 on Raspbian JESSIE, configuration is suitable for any current Debian based Linux system, of course including Ubuntu.

Introduction

I am using Jetty as a platform to develop and test web services, as well as to operate web services productively for private purpose. In this context it is neccessary to secure the web server, at least in a basic manner. However this task has prooved to be time consuming and somewhat annoying, as it never works from scratch. Jetty changes the way it is configured significantly with nearly every update, while documentation is never up-to-date. So this guide will most likely be suitable for Jetty 9.3.6 only (as a consequence I probably won't upgrade to newer Jetty within the next 2 - 3 years).

In this guide, we're using just one password in all places where a password is needed, and we're creating a self-signed certificate instead of a purchased one. For my own purpose that is good enough, even in productive configurations. But it's of course up to you to use more than one password for keys and to purchase some "official" trusted certificate.

Requirements

Jetty 9.3.6 and Oracle Java 8 installed, JAVA_HOME pointing to the Java 8 installation,
Jetty placed in /opt/jetty.

Step by step

Login as root or use all commands in sudo context. Let's begin in the /opt/jetty/lib folder:

   cd /opt/jetty/lib
         

Create an obfuscated password:

   java -cp ./jetty-util-9.3.6.v20151106.jar org.eclipse.jetty.util.security.Password top08secret15
         
this will give us an output like
   OBF:1mm61ku51y7v1ikq1mpx1vgv1t331vfz1mt51ino1y831kqp1mio
   MD5:02057101e96453c5e3e3ebcef5169625
         
This is our example password: top08secret15. It's obfuscated representation is OBF:1mm61ku51y7v1ikq1mpx1vgv1t331vfz1mt51ino1y831kqp1mio.
Keep both strings in some safe place, maybe a crypted file or just a piece of paper (I assume you chose your own password intsead of this example ;-) .

In order to create a key, a new keystore and a certificate, let's create a (temporary) folder:
   mkdir /opt/certificate
   cd /opt/certificate
         
In the new folder, first create a private key:
   openssl genrsa -des3 -out jetty.key
         
   Generating RSA private key, 2048 bit long modulus
   .........................................................................+++
   .....................................................................................................................+++
   e is 65537 (0x10001)
   Enter pass phrase for jetty.key: top08secret15
   Verifying - Enter pass phrase for jetty.key: top08secret15
         
Now, create a certificate, which - in our example - is to expire after 5500 days (15 years). You need some name and address data, which may be fictional if the certificate is self signed:
   openssl req -new -x509 -days 5500 -key jetty.key -out jetty.crt
         
   Enter pass phrase for jetty.key: top08secret15
   You are about to be asked to enter information that will be incorporated
   into your certificate request.
   What you are about to enter is what is called a Distinguished Name or a DN.
   There are quite a few fields but you can leave some blank
   For some fields there will be a default value,
   If you enter '.', the field will be left blank.
   -----
   Country Name (2 letter code) [AU]:UK
   State or Province Name (full name) [Some-State]: Yorkshire
   Locality Name (eg, city) []: Middleton-in-Teesdale
   Organization Name (eg, company) [Internet Widgits Pty Ltd]: Teesside People
   Organizational Unit Name (eg, section) []: IT
   Common Name (e.g. server FQDN or YOUR name) []: highforce.teesvalley.info
   Email Address []: webmaster@teesvalley.info
         
Import the certificate - as "trusted" - into the local keystore:
   keytool -keystore keystore -import -alias jetty -file jetty.crt -trustcacerts
		 
   Enter keystore password: top08secret15
   Re-enter keystore password: top08secret15
   . . . a lot of output . . .
   Trust this certificate? [no]: yes
   Certificate added to keystore
		 
Not sure about the next step, which creates another certificate (maybe obsolete):
   openssl req -new -key jetty.key -out jetty.csr
		 
   Enter pass phrase for jetty.key: top08secret15
   You are about to be asked to enter information that will be incorporated
   into your certificate request.
   What you are about to enter is what is called a Distinguished Name or a DN.
   There are quite a few fields but you can leave some blank
   For some fields there will be a default value,
   If you enter '.', the field will be left blank.
    . . . enter the same date as for jetty.crt above . . . 
   Please enter the following 'extra' attributes
   to be sent with your certificate request
   A challenge password []: top08secret15
   An optional company name []: Teesside People		 
		 
The certificate needs to be formatted to be suitable for Jetty:
   openssl pkcs12 -inkey jetty.key -in jetty.crt -export -out jetty.pkcs12
         
   Enter pass phrase for jetty.key: top08secret15
   Enter Export Password: top08secret15
   Verifying - Enter Export Password: top08secret15
         
Now, import the formatted certificate into the keystore:
   keytool -importkeystore -srckeystore jetty.pkcs12 -srcstoretype PKCS12 -destkeystore keystore
	     
   Enter target keystore password: top08secret15
   Enter source keystore password: top08secret15
   Entry for alias 1 imported successfully.
   Import completed: 1 entry imported successfully, 0 entries failed or cancelled.
		 

Until this point, this (not really comfortable) procedure is quite stable. The next step is to bring the certificate and passwords into the Jetty configuration. This, as mentioned above, seems to vary with every Jetty update. With Jetty 9.3.6 proceed as follows:

There is a default key store - /opt/jetty/etc/keystore - delivered with Jetty and placed within the installation. This keystore is adapted to Jetty's default configuration, so when it's replaced by another one, Jetty is no more executable unless the configuration is adapted. Therefore it might be a good decision to backup the existing /opt/jetty/etc/keystore before proceeding with the next step.
Having done the backup, copy the new keystore, containing the certificate created obove, into place, thus overwriting the existing default keystore:

   cp -f /opt/certificate/keystore /opt/jetty/etc
	     
Also copy the key and certificate files into /opt/jetty/etc:
   cp -f /opt/certificate/jetty.* /opt/jetty/etc
	     
Now edit opt/jetty/start.ini and add the following two lines at the end of the file:
   vi /opt/jetty/start.ini
   . . .
   # ---------------------------------------
   # Module: websocket
   --module=websocket

   # ---------------------------------------
   # Module: jstl
   --module=jstl

   --module=ssl
   --module=https
	     
In opt/jetty/modules/ssl.mod make sure that the Connector port to listen on line is commented in and set to port 8443 (or the local SSL port of your choice). Additionally, comment in the Keystore password, KeyManager password and Truststore password lines and replace the obfuscated password entries by the respective obfuscated password created in the very first step above:
   vi /opt/jetty/modules/ssl.mod
   . . .
   ## Connector port to listen on
   jetty.ssl.port=8443
   . . .
   ## Keystore password
   jetty.sslContext.keyStorePassword=OBF:1mm61ku51y7v1ikq1mpx1vgv1t331vfz1mt51ino1y831kqp1mio
   . . .
   ## KeyManager password
   jetty.sslContext.keyManagerPassword=OBF:1mm61ku51y7v1ikq1mpx1vgv1t331vfz1mt51ino1y831kqp1mio

   ## Truststore password
   jetty.sslContext.trustStorePassword=OBF:1mm61ku51y7v1ikq1mpx1vgv1t331vfz1mt51ino1y831kqp1mio
   . . .
	     
Now, as the last step, modify /opt/jetty/start.d/ssl.ini the same way, i.e. comment in the Connector port to listen on line, setting the correct SSL port, and also comment in the Keystore password, KeyManager password and Truststore password lines and also replace the obfuscated password entries by the one created in the first step:
   vi /opt/jetty/start.d/ssl.ini
   . . .
   ## Connector port to listen on
   jetty.ssl.port=8443
   . . .
   ## Keystore password
   jetty.sslContext.keyStorePassword=OBF:1mm61ku51y7v1ikq1mpx1vgv1t331vfz1mt51ino1y831kqp1mio
   . . .
   ## KeyManager password
   jetty.sslContext.keyManagerPassword=OBF:1mm61ku51y7v1ikq1mpx1vgv1t331vfz1mt51ino1y831kqp1mio

   ## Truststore password
   jetty.sslContext.trustStorePassword=OBF:1mm61ku51y7v1ikq1mpx1vgv1t331vfz1mt51ino1y831kqp1mio
   . . .
	     
That's it. Having worked carefully, avoiding mistakes - in particular when typing the password - Jetty will support SSL after re-starting the service. To test the configuration, place an example HTML file named index.html into /opt/jetty/webapps/root and browse https://localhost:8443 . The browser should require you to confirm the certificate before granting access to the page.

Have fun!