Running a Node.js app (ghost) with forever and crontab on linux (CentOS)

Pre-requisites

  1. Root access to your server or have access to an account that has sudo powers on your servers – Instructions here to see how to give a linux user sudo powers.
  2. nodejs and npm installed – Instructions here.
  3. ghost installed and a ghost user made to run ghost – Instructions here

What is forever

From the github forever page we learn that forever is,

A simple CLI tool for ensuring that a given script runs continuously (i.e. forever).

CLI means Command Line Interface tool.

Installing forever

Precursor

As detailed in the instructions for installing ghost we want to run ghost with its own ghost user. Furthermore, the ghost user should have a home directory, i.e. /home/ghost/ should exist. If it doesn’t exist please see this post to see the problem that it would cause and how to fix it. Let’s first switch to the ghost user and go to the ghost install directory.

[ahmed@amayem ~]$ sudo su ghost
[ghost@amayem ahmed]$ cd /var/www/ghost/

First try

Installing is easy.

[ghost@amayem ghost]$ npm install -g forever
npm http GET https://registry.npmjs.org/forever
npm http 200 https://registry.npmjs.org/forever
npm http GET https://registry.npmjs.org/forever/-/forever-0.11.0.tgz
npm http 200 https://registry.npmjs.org/forever/-/forever-0.11.0.tgz
npm ERR! Error: EACCES, mkdir '/usr/lib/node_modules/forever'
npm ERR!  { [Error: EACCES, mkdir '/usr/lib/node_modules/forever']
npm ERR!   errno: 3,
npm ERR!   code: 'EACCES',
npm ERR!   path: '/usr/lib/node_modules/forever',
npm ERR!   fstream_type: 'Directory',
npm ERR!   fstream_path: '/usr/lib/node_modules/forever',
npm ERR!   fstream_class: 'DirWriter',
npm ERR!   fstream_stack: 
npm ERR!    [ '/usr/lib/node_modules/fstream/lib/dir-writer.js:36:23',
npm ERR!      '/usr/lib/node_modules/mkdirp/index.js:37:53',
npm ERR!      'Object.oncomplete (fs.js:107:15)' ] }
npm ERR! 
npm ERR! Please try running this command again as root/Administrator.

Argh! I need to sudo. That’s probably because we included the -g flag, which indicates that we want the package to be installed globally for everyone to use. As can be seen in the error, the ghost user does not have pemission to write to /usr/lib/node_modules/. Let’s try installing without the -g flag. We have two solutions:

  1. Installing locally
  2. Switching to an account with sudo powers and using sudo

Installing locally

[ghost@amayem ghost]$ npm install forever

It worked this time. Let’s give forever a try.

[ghost@amayem ghost]$ forever start index.js
bash: forever: command not found

This is the concequence of the local install. We have to actually run the bin that is in the node_modules directory:

[ghost@amayem ghost]$ ./node_modules/forever/bin/forever start index.js 
warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: index.js

It worked, but wouldn’t it be much better if we could use forever without having to find it deep in the directory structure. We will need to switch to the sudo user in that case. Let’s stop the forever process before installing globally.

[ghost@amayem ghost]$ ./node_modules/forever/bin/forever stopall
info:    Forever stopped processes:
data:        uid  command       script   forever pid   logfile                       uptime       
data:    [0] RZRV /usr/bin/node index.js 11940   11942 /home/ghost/.forever/RZRV.log 0:0:5:35.759 

Switching to an account with sudo powers

Ideally we don’t want the ghost account to have sudo powers. Let’s exit the ghost user shell and install globally.

[ghost@amayem ghost]$ exit
exit
[ahmed@amayem ~]$ sudo npm install -g forever

Notice that I was in the home directory of ahmed user, as indicated by ~. It doesn’t matter where I am when I install globally, because it always installs all the packages in the same global directory.

Let’s switch back to the ghost user and run forever again.

[ahmed@amayem ~]$ sudo su ghost
[ghost@amayem ahmed]$ cd /var/www/ghost/
[ghost@amayem ghost]$ NODE_ENV=production forever start index.js 
warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: index.js

That looks much better! We added the NODE_ENV=production to tell ghost that we are in production. If you leave it out it will be in devleopment mode. We discuss configuration in the installation guide.

Surviving a reboot: Crontab setup

Forever will now run ghost in the background, but it won’t start it when the server is rebooted. We can remedy that by setting up the crontab to run cron, whic is a job-scheduler. Basically it allows users to run programs periodically. We would like to run forever periodically on startup. As the ghost user type the following

[ghost@amayem ahmed]$ crontab -e

This will allow you to edit the crontab, probably using vi editor. Enter into insert mode by typing i and add this line.

@reboot NODE_ENV=production /usr/lib/node_modules/forever/bin/forever start /var/www/ghost/index.js

Notice that we put the full path to forever even though we had installed it globally. This is because cron may not be using the bash shell. It’s better to be safe than sorry. Exit insert mode with Esc or ctrl+c then save and exit with :x. You should see the following as the output:

no crontab for ghost - using an empty one
crontab: installing new crontab

Testing cron

Simply reboot your server:

[ghost@amayem ahmed]$ exit
exit
[ahmed@amayem ~]$ sudo reboot

Now simply visit your blog again to see if it’s up. Another way to check is to ssh back in to check the forever process as follows:

[ahmed@amayem ~]$ sudo su ghost
[ghost@amayem ahmed]$ forever list
info:    Forever processes running
data:        uid  command       script                  forever pid logfile                       uptime       
data:    [0] 4MOq /usr/bin/node /var/www/ghost/index.js 537     539 /home/ghost/.forever/4MOq.log 0:0:1:17.237 

Looks good! It’s only been up for 1 minute and a bit so I know it just came on.

References

  1. Ghost deployment docs
  2. Forever github repo

Ahmed Amayem has written 90 articles

A Web Application Developer Entrepreneur.

  • Alimie Zawawi

    Assalamualaikum. Thanks akhi, this tutorial is very helpful! I can vouch that this tutorial also work for my instance of ghost, installed on ubuntu 14.04.

    • http://ahmed.amayem.com ahmedamayem

      W’salaam. Alhamdulillaah, happy it helped.