Installing Ghost on Raspbian Jessie
EDIT 2019-05-22
This post was hosted on a Raspberry Pi at the original time of writing, but now is hosted on Github. See this post.
Every linux flavor has its own path to success
And yes, this blog is running on a Raspberry Pi.
There are issues with the version of Node.js v0.10.29 that comes preinstalled with Raspbian Jessie 2015-11-21 or newer. It’s not possible to install Node.js native add-ons or packages that depend on native add-ons. Therefore, Node must be built from source.
As a note, both building Node and installing Ghost require many things to be run as root, so it’s best to switch to the root user before beginning.
Fetch the latest version of Node
$ wget http://nodejs.org/dist/node-latest.tar.gz
Unpack the compressed tarball
$ tar -xzf node-latest.tar.gz
Change to the unpacked directory, for example
$ cd node-v6.2.2/
where the version number will vary.Configure your makefile
$ ./configure
If you’re on a Raspberry Pi 2 or 3, it’s best to pause at this point and ensure that you’re utilizing all four cores during the make process. By default, make only utilizes one core. In the real world, this means that building Node from source using one core will take several hours to complete. Using all four cores on a Pi 2 reduces the time needed by about 75%, resulting in the build process only taking about an hour to complete.
Using multiple cores during the make process can be as simple as passing the-j
flag with the number of cores you wish to use, or it can be a bit more elegant and flexible by doing something like adding the lines below#Parallel Make
to the end of your.bashrc
file then reloading your profile with$ source ~/.bashrc
.
Here,export NUMCPUS=$()
both defines the environment variable and sets its value togrep -c "^processor" /proc/cpuinfo
where “grep” searches the file “/proc/cpuinfo” for lines that begin with “processor” and passing the “-c” flag to grep counts the number of results.
The last line simply sets an alias called “pmake”, which is simply calling make with the necessary arguments to run multiple jobs in parallel.#Parallel Make export NUMCPUS=$(grep -c "^processor" /proc/cpuinfo) alias pmake='time nice make -j$NUMCPUS --load-average=$NUMCPUS'
Make Node using one of the following
$ make
=> Simply uses one core, or alternately$ make -j4 -l4
=> Manually configure make to use all four cores and ensure that only four jobs are running simultaneously, or alternately$pmake
=> Use the alias created above to have make use all cores and time the process.
Install Node
$ make install
Note: Installation is a quick process, so there’s no need to run things in parallel.Download the latest version of Ghost
$ wget https://ghost.org/zip/ghost-latest.zip
Unzip Ghost
$ unzip -d /path/to/install/ghost ghost-latest.zip
and change to the directory where the files were saved
$ cd /path/to/install/ghost
Install Ghost
$ npm install --production
Create a ghost configuration file by copying the example
$ cp config.example.js config.js
We’re not changing any of the defaults as a part of the installation, so the server will listen on port 2368 by default.
Note: when installing the latest version of Node, the most recent version isn’t currently supported by Ghost. However, the most current version works as intended after disabling Ghost’s version check with an environment variable. This can be passed along with command to start Ghost or set in the bash profile. The necessary variable isGHOST_NODE_VERSION_CHECK=false
.Start the Ghost process to ensure that the installation works
$ npm start --production
(if the environment variable is set in the bash profile) or alternately
$ GHOST_NODE_VERSION_CHECK=false npm start --production
(if the environment variable is to be passed along with the command)Check to see if the Ghost server is accessible by using a second terminal window to run
$ curl -vso /dev/null http://127.0.0.1:2368
where a “HTTP/1.1 200 OK” in the response headers for the curl request indicates a successful configuration and looking at the terminal for the running npm ghost process, there should be an access log line.To avoid the requirement of keeping a terminal window open to keep Ghost running, install Supervisor to run an app as a daemon
$ apt-get update && apt-get install supervisor -y
Create a configuration file for Supervisor to manage Ghost
$ touch /etc/supervisor/conf.d/ghost.conf
that contains the following lines[program:ghost] command = npm start --production directory = /path/ user = root autostart = true autorestart = true stdout_logfile = /var/log/supervisor/ghost.log stderr_logfile = /var/log/supervisor/ghost_err.log environment = NODE_ENV="production",GHOST_NODE_VERSION_CHECK="false"
Check to see if Supervisor is running after installation
$ service supervisord status
if Supervisor is not running
$ service supervisord start
Reload Supervisor with with the new Ghost configuration file
$ supervisorctl reload
and check to see if Ghost is running
$ supervisorctl status
If it isn’t
$ supervisorctl start ghost
Install Nginx to proxy Ghost and make it available externally
$ apt-get update && apt-get install nginx-full -y
Create a new virtual host file to proxy Ghost
$ touch /etc/nginx/sites-available/ghost_website_name
and create a symlink in the sites-enabled directory
$ ln -s /etc/nginx/sites-available/ghost_website_name /etc/nginx/sites-enabled/ghost_website_name
and delete the symlink for the default virtual host$ rm /etc/nginx/sites-enabled/default
Edit the ghost_website_name virtual host file so that it contains the following
server { listen 80; server_name example.com *.example.com; location / { proxy_pass http://127.0.0.1:2368; } }
Restart Nginx
$ service nginx restart
Ghost is now accessible at the external IP address where it was installed on port 80 (the default port for HTTP traffic). Visiting
http://\{IP_address}/
in a browser will now load Ghost. I’ll save configuring Ghost and Nginx for a future post.
Quite a few more steps are needed than would be necessary on a more standard linux distribution (eg, Ubuntu) on more standard architecture (eg, x86) likely due to the technologies used not originally being developed for armhf and the user-base being much smaller so packaged versions of the above are less likely to be available and in some cases, not as thoroughly tested.
As an addendum, The theme I was using relied on Ghost loading jQuery before the one JS file used in the theme was loaded. In older versions of Ghost, this happened as intended. However, in the latest version, jQuery isn’t loaded before main.js, so default.hbs needs to be modified such that <script type="text/javascript" src="https://code.jquery.com/jquery-1.12.0.min.js"></script>
appears on the line immediately preceding <script type="text/javascript" src="/assets/js/main.js?v=e58334d1c1"></script>
which allows main.js to function as intended.
Update: 2017-01-24
The SD card in my Raspberry Pi developed some bad sectors where the MBR was located on the disk, so it was no longer bootable and I’ve replaced it. Fortunately, I had an old export of most of my posts so I was able to recover almost everything. I’ll attempt to recover my most recent post, but for some reason, I don’t see it in the ghost.db, but a fragment is still in the Cloudflare cache, so while slightly confused, I retain a sliver of hope for recovery.
I changed one thing this go around— instead of using upstart, I decided to write a systemd service since the latest stable Debian release and stable derivatives all use systemd. It’s fairly straight-forward.
Create the file
ghost.service
. Note: I realize I should probably not run the service as root, but as another user with adequate permissions.[Unit] Description=Ghost After=network.target [Service] Type=simple User=root WorkingDirectory=/path/to/ghost Environment="GHOST_NODE_VERSION_CHECK=false" ExecStart=/usr/local/bin/npm start --production Restart=on-abort [Install] WantedBy=multi-user.target
Enable the service:
sudo systemctl enable ghost.service
Reload Systemctl:
sudo systemctl daemon-reload
Restart the Ghost service:
sudo systemctl restart ghost.service
Check the status to ensure that it’s running:
sudo systemctl status ghost.service