This tutorial is about how to get Apache Tomcat with APR secured with free 'A' grade SSL as per Qualys ssllabs test. It should not take you more than 5 minutes in a clean Centos 7 VPS.
In this copy and paste tutorial we will use CentOS Linux release 7.4.1708 (minimal install) with public IP, Apache Tomcat 8.0.48, Oracle JDK 1.8.0_161 and FQDN hostname resolvable to your server's public IP.
First make sure we use latest software
yum -y upgrade
Secure the host with firewall
Open only ports 80, 443 and SSH port of your choice.
SSHPORT=paste_your_cutom_ssh_port_here
sed -i "s/^#Port 22/Port ${SSHPORT}/" /etc/ssh/sshd_config
systemctl restart sshd
yum -y install mc iptables unzip firewalld
systemctl enable firewalld && systemctl start firewalld
firewall-cmd --zone=public --add-port=${SSHPORT}/tcp --permanent
firewall-cmd --zone=public --remove-port=22/tcp --permanent
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --zone=public --add-port=443/tcp --permanent
firewall-cmd --reload
firewall-cmd --list-ports
Install Tomcat and JDK
Tomcat will run under regular user and use privileged ports 80 and 443. Another option would be to redirect ports 80 and 443 to default Tomcat ports 8080 and 8443 with iptables. In this tutorial we use Linux capabilities to allow for binding to low ports.
cd /opt && curl -C - -L -O -s -S -H "Cookie: oraclelicense=accept-securebackup-cookie" \
"http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jdk-8u161-linux-x64.tar.gz"
tar xzf jdk-8u161-linux-x64.tar.gz
ln -s jdk1.8.0_161 jdk
export TOMCAT_USER=tomcat
adduser $TOMCAT_USER
su - $TOMCAT_USER
wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.0.48/bin/apache-tomcat-8.0.48.tar.gz
tar xzf apache-tomcat-8.0.48.tar.gz && rm -f apache-tomcat-8.0.48.tar.gz
ln -s apache-tomcat-8.0.48 tomcat
cat >> ~/.bashrc <<EOF
export JAVA_HOME=/opt/jdk
export JRE_HOME=\$JAVA_HOME
export JAVA_OPTS="-Xms128m -Xmx256m -XX:MaxMetaspaceSize=128m -Djava.awt.headless=true -Dfile.encoding=UTF-8"
export CATALINA_OPTS="\$CATALINA_OPTS -Djava.library.path=/opt/native"
export CATALINA_HOME=\$HOME/tomcat
export PATH=/opt/jdk/bin:\$HOME/tomcat/bin:\$PATH
EOF
exit
Install APR library for Tomcat (tomcat-native)
APR can be used with both HTTP and HTTPS connectors.
yum -y install gcc make openssl-devel apr-devel
cd /opt
cp /home/tomcat/tomcat/bin/tomcat-native.tar.gz .
tar xzf tomcat-native.tar.gz
cd /opt/tomcat-native-1.2.16-src/native/
JAVA_HOME=/opt/jdk ./configure --with-apr=/usr/bin/apr-1-config
make && make install
ln -s /usr/local/apr/lib /opt/native
Allow Java to bind privileged ports (<1024) instead of using port forwarding or high (default) ports
setcap cap_net_bind_service=+ep `readlink -f \`which java\``
echo $(dirname `find /opt/jdk/jre -name libjli.so`) > /etc/ld.so.conf.d/java_setcap.conf
ldconfig
Get free Letsencrypt certificate for use with the Tomcat
Update your contact email below.
wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -ivh epel-release-latest-7.noarch.rpm
yum-config-manager --disable epel
yum --enablerepo=epel install certbot -y
certbot certonly --standalone --preferred-challenges http -d $(hostname -f) -m your.contact@email --agree-tos -n
You should get "Congratulations! Your certificate and chain have been saved at: PATH TO YOUR PEMS" message.
Install haveged to provide more entropy for SSL routines
yum -y install --enablerepo=epel haveged rng-tools
systemctl enable haveged
systemctl start haveged
cat /dev/random | rngtest -c 1000 2>&1 | grep successes
Expect 99-1000 sucesses. Without haveged
Tomcat bootup was taking a 200 seconds. With haveged
it now takes 0.5 sec.
Setup HTTPS APR connector in Tomcat's server.xml
We will change default HTTP port 8080 to 80 as well as insert Connector with port 443.
sed -i.bak 's/<Connector port="8080" protocol="HTTP\/1.1"/<Connector port="80" protocol="org.apache.coyote.http11.Http11AprProtocol"/' /home/${TOMCAT_USER}/tomcat/conf/server.xml
Insert the following uncommented Connector nearby existing (commented out by default) Connector for HTTPS.
<Connector port="443" scheme="https" secure="true" SSLEnabled="true" URIEncoding="UTF-8" protocol="org.apache.coyote.http11.Http11AprProtocol"
SSLCertificateFile="${catalina.base}/cert.pem"
SSLCertificateKeyFile="${catalina.base}/privkey.pem"
SSLPassword=""
SSLVerifyClient="none"
SSLCertificateChainFile="${catalina.base}/chain.pem"
SSLProtocol="all -SSLv2 -SSLv3"
SSLHonorCipherOrder="on"
SSLCipherSuite="EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"
compression="on"
compressableMimeTypes="application/json,text/html,text/css,text/plain,application/javascript" />
Copy your certificates so that they are readable by Tomcat.
cp -v /etc/letsencrypt/live/$(hostname -f)/*.pem /home/${TOMCAT_USER}/tomcat
chown ${TOMCAT_USER}: /home/${TOMCAT_USER}/tomcat/*.pem
Start Tomcat and verify its startup result
su - tomcat -c "startup.sh"
cat /home/${TOMCAT_USER}/tomcat/logs/catalina.out
Qualys SSLLabs verification
The test was performed on Feb 1, 2018. Things could change since then.