Configure the Application Server (Apache Tomcat on Linux)
Overview
This guide describes how to configure Apache Tomcat as the application server for Bloomreach Experience Manager (XM) on Linux. The instructions follow the recommended practices for the Developer Edition Stack and brXM Standard Stack.
Prerequisites
Before you begin, ensure the following requirements are met:
- Java is installed:
- Bloomreach Experience Manager 16: Oracle or OpenJDK Java 17 JDK (e.g.,
/usr/java/jdk-17.0.10) - Bloomreach Experience Manager 15: Oracle or OpenJDK Java 11 JDK (e.g.,
/usr/java/jdk-11.0.22) - Bloomreach Experience Manager 14: Oracle or OpenJDK Java 8 JDK (e.g.,
/usr/java/jdk-1.8)
- Bloomreach Experience Manager 16: Oracle or OpenJDK Java 17 JDK (e.g.,
- A supported relational database server (such as MySQL) is installed. See System Requirements for the full list.
Target Configuration
Following this guide results in:
- Bloomreach Experience Manager running under a dedicated user account (
cms) with home directory/opt/cms - Apache Tomcat installed under
/usr/local - Tomcat common libraries located at
/usr/local/share/tomcat-common/lib
Note: These are recommended paths. You can use different locations if required by your environment.
Preparation
Create a dedicated user account to run Bloomreach Experience Manager:
useradd -m -d /opt/cms cms
Install and Configure Apache Tomcat
Note: To simplify upgrades, separate Catalina Base from Catalina Home. Store all custom configuration in Catalina Base, and keep Catalina Home unmodified. Upgrading Apache Tomcat then only requires updating a symlink and restarting the service.
Install Apache Tomcat (Catalina Home)
-
Download the latest supported version from Apache Tomcat:
- Use version 10.1 for brXM 16
- Use version 9.0 (or 8.5) for brXM 15/14
-
Unpack the archive:
cd /usr/local tar -xzvf apache-tomcat-<LATEST>.tar.gz
- Create a symbolic link for easier upgrades:
ln -s apache-tomcat-<LATEST> tomcat
- Set directory and file permissions:
find /usr/local/tomcat/ -type d -print0 | xargs -0 chmod 755
find /usr/local/tomcat/ -type f -print0 | xargs -0 chmod 644
find /usr/local/tomcat/ -type f -name \*\.sh -print0 | xargs -0 chmod 755
Install Common Libraries
- Create the directory for shared libraries and place the required database connector JAR:
mkdir -p /usr/local/share/tomcat-common/lib cd /usr/local/share/tomcat-common/lib # Example: MySQL connector wget http://search.maven.org/remotecontent?filepath=com/mysql/mysql-connector-j/8.4.0/mysql-connector-j-8.4.0.jar -O mysql-connector-j-8.4.0.jar
Note: If you use a different database, replace the MySQL connector with the appropriate JDBC driver. See System Requirements for supported databases.
- For brXM versions before 16, add the following JARs if they are not already present in the distribution's
common/libdirectory:
# Geronimo JTA spec wget http://search.maven.org/remotecontent?filepath=org/apache/geronimo/specs/geronimo-jta_1.1_spec/1.1.1/geronimo-jta_1.1_spec-1.1.1.jar -O geronimo-jta_1.1_spec-1.1.1.jar # Jakarta Mail wget http://search.maven.org/remotecontent?filepath=com/sun/mail/jakarta.mail/1.6.7/jakarta.mail-1.6.7.jar -O jakarta.mail-1.6.7.jar # JCR wget http://search.maven.org/remotecontent?filepath=javax/jcr/jcr/2.0/jcr-2.0.jar -O jcr-2.0.jar
Configure Apache Tomcat (Catalina Base)
Note: Catalina Base is where Tomcat runs from and where all configuration changes are made. Keep Catalina Home unmodified.
Prepare Catalina Base
- Switch to the
cmsuser and create the required directory structure:
su - cms mkdir -p tomcat/bin tomcat/conf tomcat/logs tomcat/shared/lib heapdumps tomcat/temp tomcat/webapps tomcat/work ln -sf /usr/local/tomcat/bin/startup.sh tomcat/bin/startup.sh ln -sf /usr/local/tomcat/bin/shutdown.sh tomcat/bin/shutdown.sh cd /usr/local/tomcat/conf cp catalina.policy catalina.properties server.xml web.xml tomcat-users.xml ~/tomcat/conf cd ~/tomcat
Note: By default,
tomcat-users.xmlis referenced inserver.xml. If you do not use this file, Tomcat will log a SEVERE warning. To avoid this, comment out theUserDatabaseresource and realm inconf/server.xml.
Configure the Tomcat Instance
- To allow the CMS application to open the RMI port, append the following to
conf/catalina.policy:
grant codeBase "jar:file:${catalina.home}/webapps/" {
permission java.net.SocketPermission "*:1099", "connect, accept, listen";
};
- In
conf/catalina.properties, add theshared/libpath to the shared classloader:
shared.loader="${catalina.base}/shared/lib","${catalina.base}/shared/lib/*.jar"
- In the same file, add the
tomcat-common/libpath to the common classloader:
common.loader=<original common.loader path>,"/usr/local/share/tomcat-common/lib","/usr/local/share/tomcat-common/lib/*.jar"
Add Environment-Specific Configuration for Bloomreach Experience Manager
- If you do not want the distribution's
context.xmlto take precedence, remove it and create aconf/context.xmlfile with at least the following content. Adjust the parameters as needed for your environment:
<?xml version='1.0' encoding='utf-8'?> <Context> <!-- Disable session persistence across Tomcat restarts --> <Manager pathname="" /> <Parameter name="repository-address" value="rmi://127.0.0.1:1099/hipporepository" override="false"/> <Parameter name="repository-directory" value="${catalina.base}/../repository" override="false"/> <Parameter name="start-remote-server" value="false" override="false"/> <Parameter name="check-username" value="liveuser" override="false"/> <Resource name="mail/Session" auth="Container" type="jakarta.mail.Session" mail.smtp.host="localhost"/> <!--- use type="javax.mail.Session" for brXM 15 and lower --> <!-- JNDI resource exposing database connection goes here --> </Context>
Note: RMI and its related parameters (
repository-addressandstart-remote-server) are not supported as of version 17.0.0.
Session serialization and replication are not required or supported for the CMS web application, and are not needed by default for the site web application.
-
Add a JNDI resource to
conf/context.xmland aconf/repository.xmlfile configured for your database. For MySQL, see Configure Bloomreach Experience Manager for MySQL. For other databases, refer to Databases. -
Create a
bin/setenv.shfile with the following content. Adjust values such asJAVA_HOMEas needed:
JAVA_HOME=/usr/java/jdk-17.0.10 # or jdk-11.0.15, jdk-1.8 CATALINA_HOME="/usr/local/tomcat" CATALINA_BASE="/opt/cms/tomcat" CATALINA_PID="${CATALINA_BASE}/work/catalina.pid" CLUSTER_ID="$(whoami)-$(hostname -f)" MAX_HEAP=1024 MIN_HEAP=1024 REP_OPTS="-Drepo.bootstrap=false -Drepo.config=file:${CATALINA_BASE}/conf/repository.xml" JVM_OPTS="-server -Xmx${MAX_HEAP}m -Xms${MIN_HEAP}m -XX:+UseG1GC -Djava.util.Arrays.useLegacyMergeSort=true" DMP_OPTS="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/cms/heapdumps" JRC_OPTS="-Dorg.apache.jackrabbit.core.cluster.node_id=${CLUSTER_ID}" L4J_OPTS="-Dlog4j.configurationFile=file://${CATALINA_BASE}/conf/log4j2.xml -DLog4jContextSelector=org.apache.logging.log4j.core.selector.BasicContextSelector" VGC_OPTS="-verbosegc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:${CATALINA_BASE}/logs/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=2048k" # following --add-opens for brXM 16 on Tomcat 10.1.20 to .24 only. # It's a workaround needed in combination with Freemarker back-end templating and may also be omitted in a SPA set-up ADD_OPENS_OPTS="--add-opens java.xml/com.sun.org.apache.xml.internal.utils=ALL-UNNAMED" CATALINA_OPTS="${JVM_OPTS} ${VGC_OPTS} ${REP_OPTS} ${DMP_OPTS} ${RMI_OPTS} ${L4J_OPTS} ${JRC_OPTS} ${ADD_OPENS_OPTS}" export JAVA_HOME CATALINA_HOME CATALINA_BASE
- Make
bin/setenv.shexecutable:
chmod +x bin/setenv.sh
-
For older distributions: if
conf/log4j2.xmlis missing, download it from example log4j2.xml file.If you use this example, ensure that the
web.xmlof the CMS and site web applications contains an<env-entry>element of typejava.lang.String, with namelogging/contextNameand value "cms" or "site" as appropriate. -
(Optional) To further configure the JSP servlet, add the following parameters to
conf/web.xml:
<servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> <init-param> <param-name>fork</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>xpoweredBy</param-name> <param-value>false</param-value> </init-param> <!-- BEGIN extra init-params --> <init-param> <param-name>trimSpaces</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>development</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>checkInterval</param-name> <param-value>7200</param-value> </init-param> <init-param> <param-name>modificationTestInterval</param-name> <param-value>7200</param-value> </init-param> <init-param> <param-name>genStrAsCharArray</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>enablePooling</param-name> <param-value>false</param-value> </init-param> <!-- END extra init-params --> <load-on-startup>3</load-on-startup> </servlet>
Configure the Service
-
Create an init script at
/etc/init.d/cms. Adjust the variables at the start if you use a different user or home directory.The script name determines the user account. If you use a different user than
cms, rename the script accordingly.
#!/bin/bash ### BEGIN INIT INFO # Provides: tomcat # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start Tomcat at boot time # Description: Start Tomcat instance located at the user with the same name # as the script. Tomcat is started with the privileges of the user. ### END INIT INFO # Get basename and clean up start/stop symlink cruft (aka S20cms) appname=$(basename $0) appname=${appname##[KS][0-9][0-9]} appuser=${appname} apphome=/opt/${appuser}/tomcat config=${apphome}/bin/setenv.sh start_tomcat=${apphome}/bin/startup.sh stop_tomcat=${apphome}/bin/shutdown.sh CATALINA_PID="${apphome}/work/catalina.pid" if [[ -r ${config} ]]; then . ${config} else echo "Environment config missing: ${config}" exit 1 fi if [[ -n "${JAVA_HOME+x}" && -z ${JAVA_HOME} ]]; then echo "Please point JAVA_HOME in $(basename) to your SUN JRE of JDK" exit 1 fi export JAVA_HOME CATALINA_OPTS CATALINA_PID CATALINA_HOME CATALINA_BASE if [[ $(id -u) == 0 ]]; then SU="su - ${appuser} -c" elif [[ ${appuser} != $(/usr/bin/id -un) ]]; then echo "Access denied: You are neither a superuser nor the ${appuser} user" exit 1 fi test -r ${CATALINA_PID} && PID=$(cat ${CATALINA_PID}) cleanup() { /usr/bin/find ${apphome}/work/ ${apphome}/temp/ -maxdepth 1 -mindepth 1 -print0 | xargs -0 rm -rf } start() { echo -n "Starting ${appname}: " cd ${apphome} if [[ -n ${PID} ]]; then if ps -eo pid | grep -wq ${PID}; then echo "${appname} (${PID}) still running.." exit 1 else echo "(removed stale pid file ${CATALINA_PID}) " rm -f ${CATALINA_PID} fi fi cleanup ${SU} ${start_tomcat} > /dev/null if [[ $? ]]; then echo "${appname} started." else echo "${appname} failed to start." fi } stop() { echo -n "Shutting down ${appname}: " cd ${apphome} ${SU} ${stop_tomcat} > /dev/null if [[ -n ${PID} ]]; then echo "waiting for ${appname} to stop" for ((i=0;i<25;i++)); do RUNNING=$(ps -eo pid | grep -w ${PID}) if [[ ${i} == 24 ]]; then kill ${PID} > /dev/null 2>&1 && sleep 5s && \ kill -3 ${PID} > /dev/null 2>&1 && \ kill -9 ${PID} > /dev/null 2>&1 elif [[ ${RUNNING// /} == ${PID} ]]; then echo -n "." sleep 1s else break fi done fi test -e ${CATALINA_PID} && rm -f ${CATALINA_PID} echo "${appname} stopped." } case "${1}" in start) start ;; stop) stop ;; restart) if [[ -n ${PID} ]] && ps -eo pid | grep -wq ${PID}; then kill -3 ${PID} fi stop sleep 2s start ;; *) echo "Usage: ${0} {start|stop|restart}" ;; esac exit 0
- Register the service:
# Debian/Ubuntu update-rc.d cms defaults # Redhat chkconfig --add cms
Note: On Red Hat Enterprise Linux 7.2 and later, which use systemd, you can still use the init script as described in
/etc/init.d/README:Note that traditional init scripts continue to function on a systemd
system. An init script /etc/rc.d/init.d/foobar is implicitly mapped
into a service unit foobar.service during system initialization.