Tomcat Jsvc on CentOS 7
The default yum packages for tomcat and tomcat-jsvc (version 7.0.54-2.el7_1
)
are broken on CentOS 7 (we're currently on 7.1.1503
). Newer packages available
from Fedora don't help. Here's how to make things work.
Jsvc is part of Apache commons daemon and makes Java apps (in this case Tomcat) behave nicer on Unix. A JVM app can run as a Unix daemon, and it can start as root to open files (including binding to privileged network ports like 80) and then downgrade capabilities to a non-privileged user (like "tomcat"). Unfortunately the systemd setup is broken (see bug 9097). The tomcat package scripts contain jsvc provisions, but just plain don't work.
Start by replacing file /usr/lib/systemd/system/tomcat-jsvc.service
:
# Systemd unit file for tomcat
#
# To create clones of this service:
# 1) By default SERVICE_NAME=tomcat. When cloned, the value must be defined
# before tomcat-sysd is called.
# 2) Create /etc/sysconfig/${SERVICE_NAME} from /etc/sysconfig/tomcat
# to override tomcat defaults
[Unit]
Description=Apache Tomcat Web Application Container JSVC wrapper
After=syslog.target network.target
[Service]
Type=forking
EnvironmentFile=/etc/tomcat/tomcat.conf
Environment="NAME=" "USE_JSVC=true"
EnvironmentFile=-/etc/sysconfig/tomcat
ExecStart=/usr/libexec/tomcat/server start
ExecStop=/usr/libexec/tomcat/server stop
[Install]
WantedBy=multi-user.target
and file /usr/libexec/tomcat/functions
:
#!/bin/bash
if [ -r /usr/share/java-utils/java-functions ]; then
. /usr/share/java-utils/java-functions
else
echo "Can't read Java functions library, aborting"
exit 1
fi
_save_function() {
local ORIG_FUNC=$(declare -f $1)
local NEWNAME_FUNC="$2${ORIG_FUNC#$1}"
eval "$NEWNAME_FUNC"
}
run_jsvc() {
JSVC=/usr/bin/jsvc
if [ -x ${JSVC} ]; then
TOMCAT_USER="tomcat"
OUTFILE=${CATALINA_BASE}/logs/catalina${NAME}.out
# pre-create the output file so we can change the owner so jsvc can later reopen it
/usr/bin/touch ${OUTFILE}
/usr/bin/chmod 0644 ${OUTFILE}
if [ "$UID" = "0" ]; then
/usr/bin/chown ${TOMCAT_USER} ${OUTFILE}
# guess that there's a group of the same name, but ignore errors
/usr/bin/chgrp ${TOMCAT_USER} ${OUTFILE} >/dev/null 2>&1 || true
fi
JSVC_OPTS="-pidfile /var/run/jsvc-tomcat${NAME}.pid -user ${TOMCAT_USER} -outfile ${OUTFILE} -errfile &1"
if [ "$1" = "stop" ]; then
JSVC_OPTS="${JSVC_OPTS} -nodetach -stop"
fi
exec "${JSVC}" ${JSVC_OPTS} ${FLAGS} -classpath "${CLASSPATH}" ${OPTIONS} "${MAIN_CLASS}" "${@}"
else
echo "Can't find ${JSVC} executable"
fi
}
_save_function run run_java
run() {
if [ "${USE_JSVC}" = "true" ] ; then
run_jsvc $@
else
run_java $@
fi
}
In addition, the base tomcat package is missing the library JAR file
tomcat-dbcp.jar
. You'll have to pull that out of a
matching version
of the
binary distribution
of Tomcat. Place the file tomcat-dbcp.jar
into directory /usr/share/java/tomcat
.
You should also:
- pre-create (touch) the process ID file
/run/jsvc-tomcat.pid
as usertomcat:tomcat
with permissions0644
- mask (hide) the standard tomcat service:
sudo systemctl stop tomcat.service
sudo systemctl mask tomcat.service
- reload systemd config to see the new setup:
sudo systemctl daemon-reload
You probably also want to edit /etc/logrotate.d/tomcat
:
/var/log/tomcat/catalina.out {
weekly
rotate 52
compress
missingok
create 0644 tomcat tomcat
postrotate
/usr/bin/kill -USR1 `/usr/bin/cat /var/run/jsvc-tomcat.pid`
endscript
}
Now you will use systemd to control tomcat:
sudo systemctl enable tomcat-jsvc
sudo systemctl start tomcat-jsvc
sudo systemctl stop tomcat-jsvc