Blogs / Marko Zmak / running eZ Publish daemons in virtual host environment

running eZ Publish daemons in virtual host environment

Wednesday 05 January 2011 7:08:17 am

  • Currently 5 out of 5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

By : Marko Žmak

The recommended way of using the ezfind and ezodf extensions on a server with multiple eZP installations is to have only one instance of Solr server and one instance of OO conversion server for all the eZP installations.

Running single instances of this servers for multiple eZP installations is not a problem if you have full access to your server, but if you happen to have many eZP installation in a limited virtual hosting environment, setting this two servers can be a little bit tricky. So here is how you'll do it...

Situation and demands

Situation:

  • a server in a virtual hosting (chroot) environment with many eZP installations on different user accounts (each for a different client)
  • no direct access to the root user

Demands:

  • only one Solr server and only one OO conversion server instance for all eZP installations
  • start both servers as daemons at boot time
  • being able to start/stop/restart the daemons
  • don't run daemons as root (for security reasons)

The idea

In order for this to work we have to run the OO conversion server as a user which has access to all the eZP installations, and write access to their "var" folders - this is because the OO conversion server writes the converted file inside the "var" folder of the eZP instance that requested the conversion. So the idea goes like this:

  • run daemons under the user of the web server (e.g. www, nobody, apache) - it's the only one that for sure has access to all the eZP installations
  • have another user for starting/stopping daemons
  • for each daemon create a wrapper script to start as www user or stop it

Step by step

0) Install pre-requisites

Install the usual pre-requisites for Solr and OO conversion daemons that are described in their documentation.

1) Create an user for starting daemons

Create a new user with a shell access (let's call it ezdaemon), or ask your server admin to do it.

2) Install OO conversion macro

Install the needed conversion macro for ezdaemon user. The instructions for installation of the macro can be found here:

http://doc22.ez.no/Extensions/ODF-Import-Export/eZODF-extension

Note: There's a way for running OpenOffice and our OO conversion server without installing an XWindows server on the server. It's described later in the "Tweaks" section of this post.

3) Extract the eZP installation

In the home folder of ezdaemon user unpack the eZP installation. We only need this to get the servers in ezfind and ezodf extensions. Note that the versions of this two extensions unpacked here must match (or be compatible with) the versions of the same extensions used in all of your eZP installations.

4) Create the wrapper scripts

Create the scripts for starting the daemons as a user under which is your web server running. Let's say it's "nobody" user. I have started from the RHEL script that comes with the ezfind extension, and modified it to suit this specific needs. I've attached the full scripts along with this post.

5) Install the scripts as daemons

Ask your server admin to install your scripts as daemons. If running RHEL or similar OS, just put the scripts in the "/etc/init.d/" folder.
Also, ask the server admin to give the user ezdaemon sudo privileges for this two scripts.

6) Run the daemons

Run the daemons using the wrapper script. For example like this:

sudo /etc/init.d/ezodf start
sudo /etc/init.d/solr start

Prior to running them make sure that the needed ports are open on the server (the ports are described in the docs for both servers).

Wrapper script - Solr

Usage: /etc/init.d/solr {start|stop|restart|reload|status}

Code:

#!/bin/bash
#
# eZ Find init script for RHEL and CENTOS.
# 
# Usage:
# 
# Set the correct SOLR_HOME value, and copy this file to /etc/init.d
# Symlink to /etc/init.d/solr to /etc/rc3.d/S70solr and /etc/rc5.d/S70solr
#
# Example:
# cp solr /etc/init.d/solr
# cd /etc/init.d && chmod 755 solr
# cd /etc/rc3.d && ln -s ../init.d/solr S70solr
# cd /etc/rc5.d && ln -s ../init.d/solr S70solr
# cd /etc/rc3.d && ln -s ../init.d/solr K70solr
# cd /etc/rc5.d && ln -s ../init.d/solr K70solr

DESC="Solr indexing server"
NAME=solr
JAVA_HOME=

SOLR_HOME=/home/ezdaemon/ezpublish/extension/ezfind/java
HOME=/home/ezdaemon
LOGDIR=$HOME/log
LOG_STDOUT=$LOGDIR/solr_stdout.log
LOG_STDERR=$LOGDIR/solr_stderr.log

source /etc/rc.d/init.d/functions

for JAVA in "$JAVA_HOME/bin/java" "/usr/bin/java" "/usr/local/bin/java"
do
    if [ -x $JAVA ]
        then
        break
    fi
done
if [ ! -x $JAVA ]
then
    echo "Unable to locate java. Please set JAVA_HOME environment variable."
    exit
fi

RETVAL=0

d_start() {
    CURRENT_DIR=`pwd`
    daemon --user=nobody --check $NAME --pidfile $HOME/var/run/solr.pid "cd $SOLR_HOME && nohup $JAVA -jar $SOLR_HOME/start.jar" >> $LOG_STDOUT 2>> $LOG_STDERR &
    RETVAL=$?
    sleep 1 # Sleep 1 second, to make sure java is registered.
    pid=`pidof java`
    echo $pid > $HOME/var/run/solr.pid
    cd $CURRENT_DIR
    [ $RETVAL -eq 0 ] && su - nobody -c "touch $HOME/var/lock/subsys/$NAME"
    return $RETVAL
}

d_stop() {
    killproc -p $HOME/var/run/solr.pid $NAME >> /dev/null 2&>1
    RETVAL=$?
    [ $RETVAL -eq 0 ] && rm -f $HOME/var/lock/subsys/$NAME
echo "#$RETVAL#"
    return $RETVAL
}

d_restart() {
    d_stop >> /dev/null 2&>1
    sleep 2
    d_start >> /dev/null 2&>1
}

d_reload() {
    killproc -p $HOME/var/run/solr.pid $NAME -HUP 2&>1
    RETVAL=$?
    return $RETVAL
}

d_status() {
    status -p $HOME/var/run/solr.pid $NAME >> /dev/null 2&>1
    return $?
}

case "$1" in
  start)
    echo " * Starting $DESC ($NAME)"
    d_status
    if [ $? -eq 0 ]
    then
      echo "   ...already running."
    else
      if d_start
      then
        echo "   ...done."
      else
        echo "   ...failed."
        RETVAL=1
      fi
    fi
    ;;
  stop)
    echo " * Stopping $DESC ($NAME)"
    if d_stop
    then
      echo "   ...done."
    else
      echo "   ...failed."
      RETVAL=1
    fi
    ;;
  restart)
    echo " * Restarting $DESC ($NAME)"
    d_status
    if [ $? -ne 0 ]
    then
      echo "   ...not running."
      RETVAL=1
    else
      if d_restart
      then
        echo " * ...done."
      else
        echo " * ...failed."
        RETVAL=1
      fi
    fi
    ;;
  reload)
    echo " * Reloading $DESC ($NAME): "
    d_reload
    echo "   ...done."
    ;;
  status)
    d_status
    if [ $? -eq 0 ]
    then
      echo " * $DESC ($NAME) is running"
    else
      echo " * $DESC ($NAME) is not running"
    fi
    ;;
  *)
    echo $"Usage: $0 {start|stop|restart|reload|status}"
    RETVAL=1
esac

exit $RETVAL

Wrapper script - OO

Usage: /etc/init.d/ezodf {start|stop|restart|reload|status}

Code:

#!/bin/bash
#
# eZ ODF Conversion daemon init script for RHEL and CENTOS.
# 
# Usage:
# 
# Set the correct folder variables values, and copy this file to /etc/init.d
# Symlink to /etc/init.d/ezodf to /etc/rc3.d/S70ezodf and /etc/rc5.d/S70ezodf
#
# Example:
# cp ezodf /etc/init.d/ezodf
# cd /etc/init.d && chmod 755 ezodf
# cd /etc/rc3.d && ln -s ../init.d/ezodf S70ezodf
# cd /etc/rc5.d && ln -s ../init.d/ezodf S70ezodf
# cd /etc/rc3.d && ln -s ../init.d/ezodf K70ezodf
# cd /etc/rc5.d && ln -s ../init.d/ezodf K70ezodf


DESC="eZ ODF Conversion daemon"
NAME=ezodf

HOME=/home/ezdaemon
VARDIR=$HOME/var
LOGDIR=$HOME/log

LOG_STDOUT=$LOGDIR/${NAME}_stdout.log
LOG_STDERR=$LOGDIR/${NAME}_ezodf_stderr.log

SCRIPT=$HOME/ezpublish/extension/ezodf/scripts/daemon.php
PHP=/usr/local/bin/php
PIDFILE=$VARDIR/run/ezodf.pid

source /etc/rc.d/init.d/functions

RETVAL=0

d_start() {
    CURRENT_DIR=`pwd`
    daemon --user=nobody --check $NAME --pidfile $PIDFILE "nohup $PHP $SCRIPT" >> $LOG_STDOUT 2>> $LOG_STDERR &
    RETVAL=$?
    sleep 1
    pid=`pgrep -u nobody php`
    echo $pid > $PIDFILE 
    cd $CURRENT_DIR
    [ $RETVAL -eq 0 ] && su - nobody -c "touch $VARDIR/lock/subsys/$NAME"
    return $RETVAL
}

d_stop() {
    killproc -p $PIDFILE $NAME >> /dev/null 2&>1
    RETVAL=$?
    [ $RETVAL -eq 0 ] && rm -f $VARDIR/lock/subsys/$NAME
    return $RETVAL
}

d_restart() {
    d_stop >> /dev/null 2&>1
    sleep 1
    d_start >> /dev/null 2&>1
}

d_reload() {
    killproc -p $PIDFILE $NAME -HUP 2&>1
    RETVAL=$?
    return $RETVAL
}

d_status() {
    status -p $PIDFILE $NAME >> /dev/null 2&>1
    return $?
}

case "$1" in
  start)
    echo " * Starting $DESC ($NAME)"
    d_status
    if [ $? -eq 0 ]
    then
      echo "   ...already running."
    else
      if d_start
      then
        echo "   ...done."
      else
        echo "   ...failed."
        RETVAL=1
      fi
    fi
    ;;
  stop)
    echo " * Stopping $DESC ($NAME)"
    if d_stop
    then
      echo "   ...done."
    else
      echo "   ...failed."
      RETVAL=1
    fi
    ;;
  restart)
    echo " * Restarting $DESC ($NAME)"
    d_status
    if [ $? -ne 0 ]
    then
      echo "   ...not running."
      RETVAL=1
    else
      if d_restart
      then
        echo " * ...done."
      else
        echo " * ...failed."
        RETVAL=1
      fi
    fi
    ;;
  reload)
    echo " * Reloading $DESC ($NAME): "
    d_reload
    echo "   ...done."
    ;;
  status)
    d_status
    if [ $? -eq 0 ]
    then
      echo " * $DESC ($NAME) is running"
    else
      echo " * $DESC ($NAME) is not running"
    fi
    ;;
  *)
    echo $"Usage: $0 {start|stop|restart|reload|status}"
    RETVAL=1
esac

exit $RETVAL

Tweaks

1) OpenOffice without the XWindows Server

If you want to run OpenOffice without the XWindows Server (which can spare you some headaches) you have to run it with the -headless parameter. To add this parameter you will have to edit the extension/ezodf/scripts/daemon.php script inside the eZP installation of the ezdaemon user. Just change this line:

$convertShellCommand = escapeshellcmd( $ooexecutable . " -writer
-invisible" ) . " " .


to this:

$convertShellCommand = escapeshellcmd( $ooexecutable . " -writer
-invisible -headless" ) . " " .

I have also proposed an enhancement that would allow to do this without hacking the script:

http://issues.ez.no/IssueView.php?Id=17308&activeItem=1


2) Running on non default ports

It's recommended to run the Solr and OO conversion server on non default ports. First, it's generally more secure not use default ports. And second, in this way you leave the default port free for some quick testings of new eZP installations.

To change the port on which the OO conversion server runs, you'll have to edit extension/ezodf/scripts/daemon.php inside the eZP installation for ezdeamon user and change the value of the $port variable.

To change the port for Solr server you'll have to edit /extension/ezfind/java/etc/jetty.xml in the eZP instllation of ezdaemon user. It's defined in the line that goes like this:

<Set name="port"><SystemProperty name="jetty.port"
default="8983"/></Set>

Docs

eZFind: http://doc.ez.no/Extensions/eZ-Find/2.1/
eZODF: http://doc22.ez.no/Extensions/ODF-Import-Export/eZODF-extension

eZ debug

Timing: Jan 17 2025 21:05:21
Script start
Timing: Jan 17 2025 21:05:21
Module start 'content'
Timing: Jan 17 2025 21:05:21
Module end 'content'
Timing: Jan 17 2025 21:05:21
Script end

Main resources:

Total runtime0.2950 sec
Peak memory usage6,144.0000 KB
Database Queries186

Timing points:

CheckpointStart (sec)Duration (sec)Memory at start (KB)Memory used (KB)
Script start 0.00000.0083 597.3906180.8203
Module start 'content' 0.00830.1532 778.2109514.2266
Module end 'content' 0.16150.1334 1,292.4375420.8516
Script end 0.2949  1,713.2891 

Time accumulators:

 Accumulator Duration (sec) Duration (%) Count Average (sec)
Ini load
Load cache0.00421.4325210.0002
Check MTime0.00170.5655210.0001
Mysql Total
Database connection0.00140.486810.0014
Mysqli_queries0.164355.69861860.0009
Looping result0.00170.57191840.0000
Template Total0.241481.820.1207
Template load0.00240.821020.0012
Template processing0.239081.011020.1195
Template load and register function0.00010.029510.0001
states
state_id_array0.00150.503510.0015
state_identifier_array0.00080.263720.0004
Override
Cache load0.00210.69601200.0000
Sytem overhead
Fetch class attribute name0.00411.402830.0014
Fetch class attribute can translate value0.00090.302410.0009
class_abstraction
Instantiating content class attribute0.00000.004030.0000
XML
Image XML parsing0.00030.085810.0003
General
dbfile0.00792.6723220.0004
String conversion0.00000.002330.0000
Note: percentages do not add up to 100% because some accumulators overlap

CSS/JS files loaded with "ezjscPacker" during request:

CacheTypePacklevelSourceFiles
CSS0extension/community/design/community/stylesheets/ext/jquery.autocomplete.css
extension/community_design/design/suncana/stylesheets/scrollbars.css
extension/community_design/design/suncana/stylesheets/tabs.css
extension/community_design/design/suncana/stylesheets/roadmap.css
extension/community_design/design/suncana/stylesheets/content.css
extension/community_design/design/suncana/stylesheets/star-rating.css
extension/community_design/design/suncana/stylesheets/syntax_and_custom_tags.css
extension/community_design/design/suncana/stylesheets/buttons.css
extension/community_design/design/suncana/stylesheets/tweetbox.css
extension/community_design/design/suncana/stylesheets/jquery.fancybox-1.3.4.css
extension/bcsmoothgallery/design/standard/stylesheets/magnific-popup.css
extension/sevenx/design/simple/stylesheets/star_rating.css
extension/sevenx/design/simple/stylesheets/libs/fontawesome/css/all.min.css
extension/sevenx/design/simple/stylesheets/main.v02.css
extension/sevenx/design/simple/stylesheets/main.v02.res.css
JS0extension/ezjscore/design/standard/lib/yui/3.17.2/build/yui/yui-min.js
extension/ezjscore/design/standard/javascript/jquery-3.7.0.min.js
extension/community_design/design/suncana/javascript/jquery.ui.core.min.js
extension/community_design/design/suncana/javascript/jquery.ui.widget.min.js
extension/community_design/design/suncana/javascript/jquery.easing.1.3.js
extension/community_design/design/suncana/javascript/jquery.ui.tabs.js
extension/community_design/design/suncana/javascript/jquery.hoverIntent.min.js
extension/community_design/design/suncana/javascript/jquery.popmenu.js
extension/community_design/design/suncana/javascript/jScrollPane.js
extension/community_design/design/suncana/javascript/jquery.mousewheel.js
extension/community_design/design/suncana/javascript/jquery.cycle.all.js
extension/sevenx/design/simple/javascript/jquery.scrollTo.js
extension/community_design/design/suncana/javascript/jquery.cookie.js
extension/community_design/design/suncana/javascript/ezstarrating_jquery.js
extension/community_design/design/suncana/javascript/jquery.initboxes.js
extension/community_design/design/suncana/javascript/app.js
extension/community_design/design/suncana/javascript/twitterwidget.js
extension/community_design/design/suncana/javascript/community.js
extension/community_design/design/suncana/javascript/roadmap.js
extension/community_design/design/suncana/javascript/ez.js
extension/community_design/design/suncana/javascript/ezshareevents.js
extension/sevenx/design/simple/javascript/main.js

Templates used to render the page:

UsageRequested templateTemplateTemplate loadedEditOverride
1node/view/full.tplblog_entry/full.tplextension/community_design/design/suncana/override/templates/blog_entry/full.tplEdit templateOverride template
2content/datatype/view/ezxmltext.tpl<No override>extension/community_design/design/suncana/templates/content/datatype/view/ezxmltext.tplEdit templateOverride template
7content/datatype/view/ezxmltags/header.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/header.tplEdit templateOverride template
7content/datatype/view/ezxmltags/strong.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/strong.tplEdit templateOverride template
20content/datatype/view/ezxmltags/paragraph.tpl<No override>extension/ezwebin/design/ezwebin/templates/content/datatype/view/ezxmltags/paragraph.tplEdit templateOverride template
3content/datatype/view/ezxmltags/li.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/li.tplEdit templateOverride template
3content/datatype/view/ezxmltags/ul.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/ul.tplEdit templateOverride template
9content/datatype/view/ezxmltags/emphasize.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/emphasize.tplEdit templateOverride template
14content/datatype/view/ezxmltags/line.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/line.tplEdit templateOverride template
3content/datatype/view/ezxmltags/link.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/link.tplEdit templateOverride template
6content/datatype/view/ezxmltags/literal.tpl<No override>extension/community/design/standard/templates/content/datatype/view/ezxmltags/literal.tplEdit templateOverride template
1content/datatype/view/ezkeyword.tpl<No override>extension/community_design/design/suncana/templates/content/datatype/view/ezkeyword.tplEdit templateOverride template
1pagelayout.tpl<No override>extension/sevenx/design/simple/templates/pagelayout.tplEdit templateOverride template
 Number of times templates used: 77
 Number of unique templates used: 13

Time used to render debug report: 0.0002 secs