When deploying RhodeCode on CentOS systems, one common hurdle is the absence of native init scripts for RedHat-based distributions. Unlike Debian or Gentoo, CentOS requires custom daemon management solutions. The core problem involves:
- Persistent process execution
- Proper user permissions
- Log management
- PID file handling
For a robust daemon implementation, we need these key elements:
# Directory structure essentials
/var/run/rhodecode/ # For PID files
/var/www/rhodecode/ # Configuration and logs
/srv/rhodecode/ # Execution scripts
Here's an improved version of start.sh with better error handling:
#!/bin/bash
# RhodeCode execution wrapper
WDIR=/var/www/rhodecode
VIRTUALENV_DIR=/opt/python_virtualenvironments/rhodecode-venv
export PYTHON_EGG_CACHE=/tmp/.python-eggs
# Environment validation
[ ! -d "$VIRTUALENV_DIR" ] && { echo "Virtualenv missing"; exit 1; }
source $VIRTUALENV_DIR/bin/activate || exit 1
cd $WDIR || exit 1
exec paster serve production.ini >> debug.log 2>&1
A more resilient init.d script with proper status checks:
#!/bin/sh
# RhodeCode System V init script
NAME=rhodecode-server
DESC="RhodeCode Version Control"
USER=rhodecode
PID_FILE=/var/run/rhodecode/pid
CMD="/srv/rhodecode/start.sh"
LOCK_FILE=/var/lock/subsys/$NAME
. /etc/init.d/functions
validate_environment() {
[ -f "$CMD" ] || return 1
[ -d "$(dirname $PID_FILE)" ] || return 1
id $USER >/dev/null 2>&1 || return 1
return 0
}
start() {
validate_environment || {
echo "Environment validation failed"
return 1
}
echo -n $"Starting $DESC: "
daemon --user=$USER --pidfile=$PID_FILE "$CMD &"
RETVAL=$?
[ $RETVAL -eq 0 ] && touch $LOCK_FILE
echo
return $RETVAL
}
stop() {
echo -n $"Stopping $DESC: "
killproc -p $PID_FILE
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f $LOCK_FILE $PID_FILE
echo
return $RETVAL
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
sleep 2
start
;;
*)
echo $"Usage: $0 {start|stop|restart}"
exit 1
esac
exit $?
When encountering hangs during startup:
- Verify the process isn't already running:
ps aux | grep paster
- Check SELinux context:
ls -Z /srv/rhodecode/start.sh
- Test direct execution:
sudo -u rhodecode /srv/rhodecode/start.sh
For modern CentOS versions (7+), consider this systemd unit file:
[Unit]
Description=RhodeCode Version Control
After=network.target
[Service]
User=rhodecode
Group=rhodecode
WorkingDirectory=/var/www/rhodecode
Environment=PYTHON_EGG_CACHE=/tmp/.python-eggs
ExecStart=/opt/python_virtualenvironments/rhodecode-venv/bin/paster serve production.ini
Restart=always
PIDFile=/var/run/rhodecode/pid
[Install]
WantedBy=multi-user.target
After implementing either solution:
# Set proper permissions
chmod 755 /srv/rhodecode/start.sh
chmod 755 /etc/init.d/rhodecode-server
# Enable auto-start
chkconfig --add rhodecode-server
chkconfig rhodecode-server on
When converting a shell script into a proper daemon on CentOS, several critical components must be addressed:
# Essential daemon characteristics:
1. Background execution (detaching from terminal)
2. PID file management
3. Proper user context
4. Logging infrastructure
5. System V init script compliance
The current setup shows several common pitfalls in daemon implementation:
# Problem areas in the original script:
1. Missing proper daemonization in start.sh
2. Incomplete PID file handling
3. No proper process detachment
4. Log rotation not configured
Here's the corrected version of the start.sh script with proper daemonization:
#!/bin/bash
WDIR=/var/www/rhodecode
VIRTUALENV_DIR=/opt/python_virtualenvironments/rhodecode-venv
PID_FILE=/var/run/rhodecode/pid
LOG_DIR=/var/log/rhodecode
# Ensure proper environment
export PYTHON_EGG_CACHE=/tmp/.python-eggs
source $VIRTUALENV_DIR/bin/activate
# Daemonization function
daemonize() {
# Double-fork to properly daemonize
(
cd $WDIR
exec /usr/bin/paster serve production.ini \
>> $LOG_DIR/debug.log \
2>> $LOG_DIR/error.log
) & echo $! > $PID_FILE
}
case "$1" in
start)
daemonize
;;
stop)
[ -f $PID_FILE ] && kill $(cat $PID_FILE)
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
;;
esac
The improved /etc/init.d/rhodecode-server should handle process management more robustly:
#!/bin/sh
#
# chkconfig: 345 90 10
# description: RhodeCode version control server
### BEGIN INIT INFO
# Provides: rhodecode-server
# Required-Start: $network $local_fs $remote_fs
# Required-Stop: $network $local_fs $remote_fs
# Default-Start: 3 4 5
# Default-Stop: 0 1 2 6
# Short-Description: RhodeCode server
### END INIT INFO
NAME=rhodecode-server
USER=rhodecode
SCRIPT=/srv/rhodecode/start.sh
PID_FILE=/var/run/rhodecode/pid
LOCK_FILE=/var/lock/subsys/$NAME
. /etc/init.d/functions
start() {
echo -n $"Starting $NAME: "
daemon --user=$USER --pidfile=$PID_FILE $SCRIPT start
RETVAL=$?
[ $RETVAL -eq 0 ] && touch $LOCK_FILE
echo
return $RETVAL
}
stop() {
echo -n $"Stopping $NAME: "
killproc -p $PID_FILE $SCRIPT
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f $LOCK_FILE
echo
return $RETVAL
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status -p $PID_FILE $NAME
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
RETVAL=2
;;
esac
exit $RETVAL
Create /etc/logrotate.d/rhodecode for proper log management:
/var/log/rhodecode/*.log {
weekly
missingok
rotate 12
compress
delaycompress
notifempty
create 640 rhodecode rhodecode
sharedscripts
postrotate
/etc/init.d/rhodecode-server restart > /dev/null
endscript
}
Complete the setup with these commands:
# Create necessary directories
sudo mkdir -p /var/log/rhodecode
sudo chown rhodecode:rhodecode /var/log/rhodecode
# Set up init script
sudo chmod 755 /etc/init.d/rhodecode-server
sudo chkconfig --add rhodecode-server
sudo chkconfig rhodecode-server on
# First start
sudo service rhodecode-server start