Linux uses System V init scripts. Although there can be some differences between distributions, generally it looks like this:
/etc/rc.d/init.d/ - contains the start and stop scripts (other distributions: /etc/init.d/)
/etc/rc.(x)/ - contains links to the start and stop scripts prefixed with S or K (start or kill respectively)
There are various run levels for various stages of system use.
rc1.d - Single User Mode
rc2.d - Single User Mode with Networking
rc3.d - Multi-User Mode - boot up in text mode
rc4.d - Undefined
rc5.d - Multi-User Mode - boot up in X Windows
rc6.d - Shutdown
Most Linux systems used as Application Servers boot into run level 3 (if not, your system admin needs to be questioned on why your server needs to boot into X-Windows and needlessly waste system resources).
Your task is to:
create a user for JBoss (recommended) so that JBoss can be restricted to accessing only the files and system resources that it has permission to access via the "jboss" user.
create a script called /etc/rc.d/init.d/jboss
create a link called /etc/rc3.d/S84jboss
optionally /etc/rc5.d/S84jboss and /etc/rc4.d/S84jboss
create a link called /etc/rc6.d/K15jboss
create the K15 link in /etc/rc1.d, /etc/rc2.d, /etc/rc0.d
-
As root type "adduser --system jboss" and enter a password in case you later want to login as user jboss; Normally you will treat jboss like the users apache, www, postgres,... and disable direct login. Su to jboss and install the server in $JBOSS_HOME. Make sure the $JBOSS_HOME directory can be read by "jboss" and that the $JBOSS_HOME/server/default/work directory can be read and written. In case some permissions are messed up check the RecommendedUNIXFilesystemPermissionsForJBossApplicationServer.
Note that SELinux environment uses "runuser" instead of "su" (see below). "runuser" requires a
valid shell like "bin/sh" for your JBOSS user.
-
As root (su - root) type vi /etc/rc.d/init.d/jboss and paste the below:
#! /bin/sh
start(){
echo "Starting jboss.."
# If using an SELinux system such as RHEL 4, use the command below
# instead of the "su":
# eval "runuser - jboss -c '/opt/jboss/current/bin/run.sh > /dev/null 2> /dev/null &'
# if the 'su -l ...' command fails (the -l flag is not recognized by my su cmd) try:
# sudo -u jboss /opt/jboss/bin/run.sh > /dev/null 2> /dev/null &
su -l jboss -c '/opt/jboss/current/bin/run.sh > /dev/null 2> /dev/null &'
}
stop(){
echo "Stopping jboss.."
# If using an SELinux system such as RHEL 4, use the command below
# instead of the "su":
# eval "runuser - jboss -c '/opt/jboss/current/bin/shutdown.sh -S &'
# if the 'su -l ...' command fails try:
# sudo -u jboss /opt/jboss/bin/shutdown.sh -S &
su -l jboss -c '/opt/jboss/current/bin/shutdown.sh -S &'
}
restart(){
stop
# give stuff some time to stop before we restart
sleep 60
# protect against any services that can't stop before we restart (warning this kills all Java instances running as 'jboss' user)
su -l jboss -c 'killall java'
# if the 'su -l ...' command fails try:
# sudo -u jboss killall java
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
*)
echo "Usage: jboss {start|stop|restart}"
exit 1
esac
exit 0
Also as root type "chmod 755 /etc/rc.d/init.d/jboss" in order to make the script executable. You should be able to test it by typing "service jboss stop", "service jboss start" and so forth. Note that the script hard codes $JBOSS_HOME so make sure that it reflects your JBOSS_HOME. Because the console output is also in the server.log we're just sending it to /dev/null.
The restart target in this script does not perform the same actions as a stop followed by a start; it contains a hard-coded 60-second sleep before killing Java the hard way. This has several negative effects, including:
making a restart take at least 60 seconds (incurring at least 60 seconds service downtime)
potentially aborting a JBoss instance that would have shut down of its own accord in due course (the corollary of this is that the stop target is not guaranteed to stop the running JBoss instance)
Alternatively, JBoss 4.0.1 (and higher) comes with prebaked init scripts in the bin directory, jboss_init_redhat.sh and jboss_init_suse.sh. You can copy one of these scripts to /etc/rc.d/init.d/jboss, then make the links below, or create a symbolic link from /etc/rc.d/init.d/jboss to one of them. These scripts don't pipe logging to /dev/null, but to a real file, so you'll have to add one additional step:
mkdir $JBOSS_HOME/log
chown jboss $JBOSS_HOME/log
You will also need to modify the start and stop commands to use "runuser" instead of "su" if using a SELinux distribution such as RHEL 4.
JBOSSUS=${JBOSSUS:-"jboss"} # put this before JBOSS_CONSOLE def
SUBIT="runuser - $JBOSSUS -c " # replace su by runuser due to SELinux
JBOSS_CONSOLE="$JBOSS_HOME/log/jboss.log" # instead of nothing
chown $JBOSSUS $JBOSS_CONSOLE # make log writable by JBOSS user
JBOSSSH=${JBOSSSH:-"$JBOSS_HOME/bin/run.sh -c default"} # change "all" for "default"
-
The links will be used to identify at which run levels JBoss should be started and stopped. In general this is probably what you want (do as root):
ln -s /etc/rc.d/init.d/jboss /etc/rc3.d/S84jboss
ln -s /etc/rc.d/init.d/jboss /etc/rc5.d/S84jboss
ln -s /etc/rc.d/init.d/jboss /etc/rc4.d/S84jboss
ln -s /etc/rc.d/init.d/jboss /etc/rc6.d/K15jboss
ln -s /etc/rc.d/init.d/jboss /etc/rc0.d/K15jboss
ln -s /etc/rc.d/init.d/jboss /etc/rc1.d/K15jboss
ln -s /etc/rc.d/init.d/jboss /etc/rc2.d/K15jboss
Linux will execute the equivilent of "service jboss start" for the "S" links and "service jboss stop" for the K links.
RedHat has a chkconfig command to manage these links, which may or may not work (it uses comments in the top of the script to determine which run-levels it should be started/stopped in). For Debian or Ubuntu, use update-rc.d(8). For SuSe, use the insserv command to properly register the new jboss script--skip the symlinking you see above, this will be ignored and will not run JBoss at boot time).
-
Have a look at http://wrapper.tanukisoftware.org/ - the Java Service Wrapper is a very powerful service wrapper for any Java application and works fine with JBoss.
You can also have a look at the Windows Java Service page, which has more instructions and configuration options for the Java Service Wrapper.
A basic wrapper.conf would look like this:
wrapper.java.command=/usr/java/bin/java
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
wrapper.java.classpath.1=../lib/wrapper.jar
wrapper.java.classpath.2=run.jar
wrapper.java.classpath.3=/usr/java/lib/tools.jar
wrapper.java.library.path.1=../lib
wrapper.java.additional.1=-server
wrapper.java.additional.2=-Dprogram.name=run.sh
wrapper.java.initmemory=256
wrapper.java.maxmemory=256
wrapper.app.parameter.1=org.jboss.Main
wrapper.app.parameter.2=-c
wrapper.app.parameter.3=default
wrapper.console.format=PM
wrapper.console.loglevel=INFO
wrapper.logfile=wrapper.log
wrapper.logfile.format=LPTM
wrapper.logfile.loglevel=INFO
wrapper.logfile.maxsize=1m
wrapper.logfile.maxfiles=1
wrapper.syslog.loglevel=NONE
Also be aware of the Solaris bug where the wait command doesn't work properly.
I use a jboss start/stop script like this:
#!/bin/ksh
JBOSS_HOME=/usr/local/jboss
JAVA_HOME=/usr/java
CONFIG=<set it here or pass it as a variable>
BIND=<set it here or pass it as a variable>
PIDFILE=${JBOSS_HOME}/jboss_${CONFIG}.pid
LAUNCH_JBOSS_IN_BACKGROUND=true
PATH=$PATH:${JBOSS_HOME}/bin:${JAVA_HOME}/bin
export JBOSS_HOME JAVA_HOME CONFIG RUN_CONF PIDFILE LAUNCH_JBOSS_IN_BACKGROUND P
ATH
case $1 in
start)
${JBOSS_HOME}/bin/run_jboss.sh -b ${BIND} -c ${CONFIG} 2>&1 &
;;
stop)
PID=`cat ${PIDFILE}`
/usr/bin/kill -HUP ${PID}
rm ${PIDFILE}
;;
*)
echo "usage: $0 (start|stop)"
;;
esac
Simple but effective. I moved my config stuff to the run_${CONFIG}.conf file in the bin directory. The run_jboss.sh is just a copy of run.sh with the non relevant stuff taken out and the reference to my config specific run.conf file updated. I also do the write to the pid file from there.
Here is is, pardon the Solaris specific slant, you can see the patch for the wait section. Pardon my mixed variable syntax, I use ${VAR} they use don't and I haven't cleaned up. I hope this helps someone:
#!/bin/sh
### ====================================================================== ###
## ##
## JBoss Bootstrap Script ##
## ##
### ====================================================================== ###
### $Id: run.sh 73862 2008-05-30 18:27:03Z mmoyses $ ###
DIRNAME=`dirname $0`
PROGNAME=`basename $0`
GREP="grep"
# Set conf if specified, else set to production
JBOSSCONF="production"
CONF_SPECIFIED=false
JBOSS_HOME=/usr/local/jboss
JAVA_HOME=/usr/java
arg_count=1
eval SWITCH=\${$arg_count}
while [ ! -z "$SWITCH" ]
do
if [ "$SWITCH" = "-c" ]; then
eval JBOSSCONF=\$`expr $arg_count + 1`
CONF_SPECIFIED=true
break
fi
arg_count=`expr $arg_count + 1`
eval SWITCH=\${$arg_count}
done
if [ x${CONF_SPECIFIED} = "xfalse" ]
then
set -- "-c" ${JBOSSCONF} $@
fi
# Use the maximum available, or set MAX_FD != -1 to use that
MAX_FD="maximum"
#
# Helper to complain.
#
warn() {
echo "${PROGNAME}: $*"
}
#
# Helper to puke.
#
die() {
warn $*
exit 1
}
# Read an optional running configuration file
if [ "x$RUN_CONF" = "x" ]; then
if [ ! -z "$JBOSSCONF" ] && [ -f "$DIRNAME/../server/$JBOSSCONF/run.conf" ]; then
RUN_CONF="$DIRNAME/../server/$JBOSSCONF/run.conf"
else
RUN_CONF="$DIRNAME/run_${JBOSSCONF}.conf"
fi
fi
echo $RUN_CONF
if [ -r "$RUN_CONF" ]; then
. "$RUN_CONF"
fi
MAX_FD_LIMIT=`ulimit -H -n`
ulimit -n $MAX_FD_LIMIT
JAVA="$JAVA_HOME/bin/java"
# Setup the classpath
runjar="$JBOSS_HOME/bin/run.jar"
if [ ! -f "$runjar" ]; then
die "Missing required file: $runjar"
fi
JBOSS_BOOT_CLASSPATH="$runjar"
# Tomcat uses the JDT Compiler
# Only include tools.jar if someone wants to use the JDK instead.
# compatible distribution which JAVA_HOME points to
if [ "x$JAVAC_JAR" = "x" ]; then
JAVAC_JAR_FILE="$JAVA_HOME/lib/tools.jar"
else
JAVAC_JAR_FILE="$JAVAC_JAR"
fi
if [ "x$JBOSS_CLASSPATH" = "x" ]; then
JBOSS_CLASSPATH="$JBOSS_BOOT_CLASSPATH"
else
JBOSS_CLASSPATH="$JBOSS_CLASSPATH:$JBOSS_BOOT_CLASSPATH"
fi
if [ "x$JAVAC_JAR_FILE" != "x" ]; then
JBOSS_CLASSPATH="$JBOSS_CLASSPATH:$JAVAC_JAR_FILE"
fi
# If -server not set in JAVA_OPTS, set it, if supported
SERVER_SET=`echo $JAVA_OPTS | $GREP "\-server"`
if [ "x$SERVER_SET" = "x" ]; then
# Check for SUN(tm) JVM w/ HotSpot support
if [ "x$HAS_HOTSPOT" = "x" ]; then
HAS_HOTSPOT=`"$JAVA" -version 2>&1 | $GREP -i HotSpot`
fi
fi
# Setup JBosst Native library path
JBOSS_NATIVE_DIR="$JBOSS_HOME/bin/native"
if [ -d "$JBOSS_NATIVE_DIR" ]; then
if [ "x$LD_LIBRARY_PATH" = "x" ]; then
LD_LIBRARY_PATH="$JBOSS_NATIVE_DIR"
else
LD_LIBRARY_PATH="$JBOSS_NATIVE_DIR:$LD_LIBRARY_PATH"
fi
export LD_LIBRARY_PATH
if [ "x$JAVA_OPTS" = "x" ]; then
JAVA_OPTS="-Djava.library.path=$JBOSS_NATIVE_DIR"
else
JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$JBOSS_NATIVE_DIR"
fi
fi
# Setup JBoss sepecific properties
JAVA_OPTS="-Dprogram.name=$PROGNAME $JAVA_OPTS"
# Setup the java endorsed dirs
JBOSS_ENDORSED_DIRS="$JBOSS_HOME/lib/endorsed"
# Display our environment
echo "========================================================================="
echo ""
echo " JBoss Bootstrap Environment"
echo ""
echo " JBOSS_HOME: $JBOSS_HOME"
echo ""
echo " JAVA: $JAVA"
echo ""
echo " JAVA_OPTS: $JAVA_OPTS"
echo ""
echo " CLASSPATH: $JBOSS_CLASSPATH"
echo ""
echo "========================================================================="
echo ""
while true; do
if [ "x$LAUNCH_JBOSS_IN_BACKGROUND" = "x" ]; then
# Execute the JVM in the foreground
"$JAVA" $JAVA_OPTS \
-Djava.endorsed.dirs="$JBOSS_ENDORSED_DIRS" \
-classpath "$JBOSS_CLASSPATH" \
org.jboss.Main "$@"
JBOSS_STATUS=$?
else
# Execute the JVM in the background
"$JAVA" $JAVA_OPTS \
-Djava.endorsed.dirs="$JBOSS_ENDORSED_DIRS" \
-classpath "$JBOSS_CLASSPATH" \
org.jboss.Main "$@" &
JBOSS_PID=$!
echo $JBOSS_PID > $JBOSS_HOME/jboss_${JBOSSCONF}.pid
# Trap common signals and relay them to the jboss process
trap "kill -HUP $JBOSS_PID" HUP
trap "kill -TERM $JBOSS_PID" INT
trap "kill -QUIT $JBOSS_PID" QUIT
trap "kill -PIPE $JBOSS_PID" PIPE
trap "kill -TERM $JBOSS_PID" TERM
# Wait until the background process exits
WAIT_STATUS=128
while [ "$WAIT_STATUS" -ge 128 ]; do
wait $JBOSS_PID 2>/dev/null
WAIT_STATUS=$?
if [ "${WAIT_STATUS}" -gt 128 ]; then
SIGNAL=`expr ${WAIT_STATUS} - 128`
SIGNAL_NAME=`kill -l ${SIGNAL}`
echo "*** JBossAS process (${JBOSS_PID}) received ${SIGNAL_NAME} signal. ***" >&2
fi
done
if [ "${WAIT_STATUS}" -lt 127 ]; then
JBOSS_STATUS=$WAIT_STATUS
else
JBOSS_STATUS=0
fi
fi
# If restart doesn't work, check you are running JBossAS 4.0.4+
# http://jira.jboss.com/jira/browse/JBAS-2483
# or the following if you're running Red Hat 7.0
# http://developer.java.sun.com/developer/bugParade/bugs/4465334.html
if [ "$JBOSS_STATUS" -eq 10 ]; then
echo "Restarting JBoss..."
else
exit $JBOSS_STATUS
fi
done
I am using JBossAS without Apache. I am using JBossAS to serve both static and dynamic content. If I run JBossAS as user 'jboss', then 'jboss' doesn't have access to port 80 (or any other port below 1024). Is there a way to grant access to user 'jboss' to port 80?
What I would not like about the init script above is, that "restart" kills all the java apps for the user, but starts only the jboss anew. This is not healthy for a production system.
Much nicer is:
include this in your init-script for stopping (untested from the top of my head):
and you are a little bit better off, than relying on jboss' shutdown script, which does not kill an unstable jboss (which CAN happen, and then you need a gut shutdown-script, beeing able to handle this incident)...