Configure the Application Server (Apache Tomcat on Linux)
Introduction
Goal
Configure an application server using the Bloomreach Experience Manager standard stack, running Apache Tomcat on a Linux operating system.
Background
This page describes how to set up a Bloomreach Experience Manager application server according to our best practices. The end result is the most commonly used setup based on the Developer Edition Stack and the brXM Standard Stack.
Assumptions
- Oracle or OpenJDK Java 8 JRE (or JDK) already installed under: /usr/java/jre1.8.0
- Relational database server (MySQL or other supported database server) already installed
- Bloomreach Experience Manager will run under its own dedicated user called cms, with home-directory: /opt/cms
- Base Apache Tomcat installation under: /usr/local
-
Tomcat common libs under: /usr/local/share/tomcat-common/lib
Preparation
-
Create a user account so you can run Bloomreach Experience Manager under it's own user.
useradd -m -d /opt/cms cms
Install and Configure Apache Tomcat
Install Apache Tomcat (Catalina Home)
- Download the latest release of Apache Tomcat 8.5 or 9.0 and unpack it.
cd /usr/local tar -xzvf apache-tomcat-8.<LATEST>.tar.gz
- Create a symlink to it:
ln -s apache-tomcat-8.<LATEST> tomcat
Install Common Libraries
- Create the tomcat-common directory for the common classloader and place the required jars there:
mkdir -p /usr/local/share/tomcat-common/lib cd /usr/local/share/tomcat-common/lib 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 wget http://search.maven.org/remotecontent?filepath=javax/mail/mail/1.4.7/mail-1.4.7.jar -O mail-1.4.7.jar wget http://search.maven.org/remotecontent?filepath=javax/jcr/jcr/2.0/jcr-2.0.jar -O jcr-2.0.jar wget http://search.maven.org/remotecontent?filepath=com/mysql/mysql-connector-j/8.0.32/mysql-connector-j-8.0.32.jar -O mysql-connector-j-8.0.32.jar
Configure Apache Tomcat (Catalina Base)
Prepare Catalina Base
-
Create the necessary directories for the Catalina Base and copy the configuration files that will be modified later:
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
Configure the Tomcat Instance
-
To allow the CMS application to open the RMI port, edit conf/catalina.policy and add the following to the end:
grant codeBase "jar:file:${catalina.home}/webapps/" { permission java.net.SocketPermission "*:1099", "connect, accept, listen"; };
-
Edit conf/catalina.properties and add the shared/lib path to the shared classloader:
shared.loader="${catalina.base}/shared/lib","${catalina.base}/shared/lib/*.jar"
-
Edit conf/catalina.properties and add the tomcat-common/lib path 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
-
Add a conf/context.xml with at least the following (and adjust it to match 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="javax.mail.Session" mail.smtp.host="localhost"/> <!-- JNDI resource exposing database connection goes here --> </Context>
Session serialization and session replication for the CMS platform web application is neither required nor supported by BloomReach and for the site web application by default not needed.
-
At this point you also need to add a JNDI resource to conf/context.xml, and add a conf/repository.xml configuration file adjusted for your database. If using MySQL you should be able to use the examples provided at Configure Bloomreach Experience Manager for MySQL as-is. See Databases for other database servers.
-
Add a file bin/setenv.sh with the following contents (adjust where necessary):
JAVA_HOME=/usr/java/jre1.8.0 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" RMI_OPTS="-Djava.rmi.server.hostname=127.0.0.1" 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" CATALINA_OPTS="${JVM_OPTS} ${VGC_OPTS} ${REP_OPTS} ${DMP_OPTS} ${RMI_OPTS} ${L4J_OPTS} ${JRC_OPTS}" export JAVA_HOME CATALINA_HOME CATALINA_BASE
- Make the file bin/setenv.sh executable:
chmod +x bin/setenv.sh
- Add a conf/log4j2.xml
Download Example log4j2-dist.xml file.
If you use the log4j2.xml example above, make sure to add to the end of the web.xml of the cms webapp the following part:
<env-entry> <env-entry-name>logging/contextName</env-entry-name> <env-entry-type>java.lang.String</env-entry-type> <env-entry-value>cms</env-entry-value> </env-entry>
and add to the end of the web.xml of the site webapp the following part:
<env-entry> <env-entry-name>logging/contextName</env-entry-name> <env-entry-type>java.lang.String</env-entry-type> <env-entry-value>site</env-entry-value> </env-entry>
- (Optional) Modify the JSP servlet configuration in conf/web.xml by adding some extra parameters.
<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: /etc/init.d/cms, adjust the variables at the start if a different user or home directory is used.
#!/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 # # Copyright BloomReach 2017 # # 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
-
Install the service
# Debian/Ubuntu update-rc.d cms defaults # Redhat chkconfig --add cms
Please note that while Red Hat Enterprise Linux 7.2 uses systemd, it is still possible to use the above init script as stated in the RHEL 7.2 /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.
Next Steps
- Configure Apache HTTP Server as Reverse Proxy for Bloomreach Experience Manager
- Deploy a Project Distribution
- Configure the Application After First Deployment