I recently decide to reconfigure one of my Apache Tomcat instances to make use of Apache Portable Runtime connector and improve performance with native server technologies. Haven’t you ever wondered what the very first Tomcat log entry was all about, it states:
“INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: …”
The official documentation was pretty sparse and some supporting topics are left for you to go hunt down elsewhere. So I decided to write a more concise guide here to cover two main topics: the connector and the supporting Open SSL certificates. Believe it or not, this is concise compared to documents that I needed to read to get this done.
Building the connector from source (on Linux):
Of course there are a few simple prerequisites, I needed the typical Linux build tools (c/cpp compiler, linker, etc..) as well as Apache Ant on my machine. In addition, since I’m planning on using SSL, I had already built and installed OpenSSL.
I needed to build the connector from source code, which just comes with the territory when using Java’s native technology (JNI). The source code for the connector and the native library is included within the $CATALINA_BASE/bin directory.
To build the native connector:
# Untar the source and create a symlink
tar -xvf tomcat-native-tar.gz
ln -s tomcat-native-1.1.16-src native
# Build the native library with SSL support
./configure --with-apr=/usr/local/apr --with-ssl=/usr/local/ssl/ssl-0.9.8g
These commands have compiled, linked and installed several Tomcat files (libtcnative*.*) into my APR base directory’s lib directory (in my case, I specified /usr/local/apr during the above configuration command). Now, I need to jar the Tomcat native file and move it to a place that Tomcat includes in its classpath.
# Using Ant, build the jar
# Move the jar to the Tomcat's library
mv dist/*.jar $CATALINA_BASE/lib
Since Tomcat doesn’t know to look for library files in the APR directories, I needed to let Tomcat know where to find the native libs (libtcnative*.*). I added the following to CATALINA_OPTS
Finally, I made a couple of adjustments to Tomcat’s server.xml file ($CATALINA_BASE/conf/server.xml):
- I commented out the standard HTTP connector
- I removed the SSLEngine=”on” parameter from the APR Listener configuration
- I added a new APR connector configuration listening on port 443
These edits essentially resulted in the following:
<Listener className="org.apache.catalina.core.AprLifecycleListener" />
<Connector port="443" maxHttpHeaderSize="8192" maxThreads="150"
acceptCount="100" scheme="https" secure="true"
SSLEnabled="true" SSLCertificateFile="server.crt" SSLCertificateKeyFile="server.key" />
Creating the supporting SSL files using OpenSSL
I need the certificate and key files that I included in Tomcat’s server.xml configuration above. I am using OpenSSL to create self-signed SSL files as opposed to just buying a certificate from a real root authority (like Verisign, Thwart, etc…).
First I created my own Certificate Authority. I only need to create one of these snake oil Certificate Authorities to sign as many server requests as I need.
# Create a CA directory in my home directory
chmod 0770 ~/CA
# Generate a Triple DES encrypted key using 2K bits: my-ca.key
# This is going to prompt you for this key's passphrase
openssl genrsa -des3 -out my-ca.key 2048
# Generate my Certificate Authority certificate: my-ca.crt
openssl req -new -x509 -days 3650 -key my-ca.key -out my-ca.crt
# Only allow me to read my CA key
chmod 0400 *.key
Now I’m ready to create some server keys and certificates.
# Changing to Tomcat's configuration directory
# Generate a Triple DES encrypted server key using 2K bits: server-secure.key
# This is going to prompt you for this key's passphase
openssl genrsa -des3 -out server-secure.key 1024
# Now create a version that does not prompt for a passphrase: server.key
# Otherwise, Tomcat will wait for this passphrase on startup
# which is not good if this is headless server startup
openssl rsa -in server-secure.key -out server.key
# Create a Certificate Signing Request: server.csr
openssl req -new -key server.key -out server.csr
# And finally, create a certificate: server.crt
# Signed by my own Certificate Authority, created earlier
openssl x509 -req -in server.csr -out server.crt -sha1 -CA ~/CA/my-ca.crt -CAkey ~/CA/my-ca.key -CAcreateserial -days 3650
# And of course, only the owner should be able to read the private keys
chmod 0400 *.key
That’s it, simple. I also added my new certificate to my keystore so that running applications can use the certificate for other things. When I ran keytool, I was prompted for a keystore password. Since I had never changed the default keystore password, it was ‘changeit’.
keytool -keystore $JAVA_HOME/jre/lib/security/cacerts -importcert -file server.crt -alias tomcat