Running Unicorn as a Service on Debian Linux

Unicorn is a very fast app server for Ruby on Rails. You just have to go to the APP_ROOT and type in “unicorn_rails”. And your app is running.

The problem with that is, if your server reboots your app is down. And you have to start it again by hand. That is not so cool!

Wouldn’t it be cool if you could start your Ruby on Rails like that:

/etc/init.d/unicorn start

and stop it like that:

/etc/init.d/unicorn stop

like all other services on Linux? And after a reboot unicorn starts automatically.

That is possible. Just use this script here for starting and stopping unicorn.

#!/bin/bash

### BEGIN INIT INFO
# Provides: unicorn
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start daemon at boot time
# Description: Enable service provided by daemon.
### END INIT INFO

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
BUNDLE=/usr/local/bin/bundle
UNICORN=/usr/local/bin/unicorn_rails
KILL=/bin/kill
APP_ROOT=/var/www/my_app/current
PID=$APP_ROOT/pids/unicorn.pid
OLD_PID=$APP_ROOT/pids/unicorn.pid.oldbin
CONF=$APP_ROOT/unicorn.conf.rb
GEM_HOME=/var/www/my_app/shared/bundle/ruby/2.1.0/gems/

sig () {
  test -s "$PID" && kill -$1 `cat $PID`
}

case "$1" in
  start)
    echo "Starting unicorn rails app ..."
    cd $APP_ROOT
    if [ $USER == "ubuntu" ]
    then
      $BUNDLE exec unicorn_rails -D -c $CONF
    else
      su ubuntu -c "$BUNDLE exec unicorn_rails -D -c $CONF"
    fi
    echo "Unicorn rails app started!"
    ;;
  stop)
    echo "Stoping unicorn rails app ..."
    sig QUIT && exit 0
    echo "Not running"
    ;;
  restart)
    if [ -f $PID ];
    then
      echo "Unicorn PID $PID exists"
      /bin/kill -s USR2 `/bin/cat $PID`
      sleep 30
      echo "Old PID $OLD_PID"
      /bin/kill -9 `/bin/cat $OLD_PID`
    else
      echo "Unicorn rails app is not running. Lets start it up!"
      $0 start
    fi
    ;;
  status)
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|status}"
    ;;
esac

Just customize the paths to your server and place the script in “/etc/init.d”. And ensure that the script is executable.

chmod ugo+x <YOUR_SCRIPT>

Than navigate to the direcotry “/etc/init.d” and execute this here:

update-rc.d <YOUR_SCRIPT> defaults

That will add your script to the default runlevels. So that your script will be executed by every reboot.

15 thoughts on “Running Unicorn as a Service on Debian Linux

  1. not really good way to run unicorn as root..

    it’s a huge huge security risk..

    here is what I’m using for starting redmine:

    #!/bin/bash

    ### BEGIN INIT INFO
    # Provides: unicorn
    # Required-Start: $remote_fs $syslog
    # Required-Stop: $remote_fs $syslog
    # Default-Start: 2 3 4 5
    # Default-Stop: 0 1 6
    # Short-Description: Start daemon at boot time
    # Description: Enable service provided by daemon.
    ### END INIT INFO

    UNICORN=/var/lib/gems/1.8/bin/unicorn_rails
    KILL=/bin/kill
    APP_ROOT=/var/www/redmine
    PID=$APP_ROOT/tmp/pids/unicorn.pid
    CONFIG=$APP_ROOT/config/unicorn.rb
    GEM_HOME=/var/lib/gems/1.8/gems/
    RUNUSER=www-data

    sig () {
    test -s “$PID” && kill -$1 `cat $PID`
    }

    case “$1″ in
    start)
    echo -ne “Starting unicorn…”
    cd $APP_ROOT
    su -c “${UNICORN} -E production -c ${CONFIG} -D” www-data
    if [ “$?” != 0 ]; then
    echo -ne “[FAILED]\n”
    else
    echo -ne “[OK]\n”
    fi
    ;;
    stop)
    sig QUIT && exit 0
    echo >&2 “Not running”
    ;;
    restart)
    $0 stop
    $0 start
    ;;
    status)
    ;;
    *)
    echo “Usage: $0 {start|stop|restart|status}”
    ;;
    esac

  2. Hi, Im trying to implement your script, but its not working for me. I get:

    Starting unicorn…
    master failed to start, check stderr log for details

    • That can have multiple reasons. For example if you start the script as non-root user but some directories need root access. You can turn on the logging for unicorn in unicorn.conf.rb. You should have there this 2 lines:

      stderr_path “/var/www/yourapp/shared/log/unicorn.stderr.log”
      stdout_path “/var/www/yourapp/shared/log/unicorn.stdout.log”

      That will give you more info on the error.

  3. I just updated the script. It is more sophisticated now! The current version starts the unicorn daemon as non privileged user ubuntu. That’s more secure!

  4. When I run the command without using su -c, it works just fine, but for some reason when I run it with that as my app’s user I get this:
    /usr/bin/env: ruby_executable_hooks: No such file or directory

    Any ideas?

  5. Instead of ubuntu I am using a user with access to the directory and paths setup correctly. When I login as this user and run the command it works fine, but for some reason when I use su it doesn’t, which seems very strange. When I ran su ubuntu I get this:
    No passwd entry for user ‘ubuntu’
    I ran this to check if there was an ubuntu user:
    cut -d: -f1 /etc/passwd
    and saw no entry for the user ubuntu

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s