Tags: Node.js
Ghost is a very popular blogging platform which, because it's written in Node.js, is not what you'd expect to install on a traditional web hosting provider who supports PHP. Dreamhost is one of the many dozens or hundreds of web hosting providers whose bread-and-butter is PHP application hosting. Dreamhost, for example, has a specially configured Wordpress hosting service, Dreampress, that looks very useful. However, Dreamhost also allows hosting of Node.js applications. Let's see how to get Ghost running on a Dreamhost Virtual Private Server.
For general directions on running Node.js apps on Dreamhost: Deploy Node.js application using Passenger on Dreamhost or other hosting providers
Bottom line is these observations:
- Dreamhost uses a thingymajob called Passenger that was meant for Ruby and Python, but also supports Node.js apps -- getting that to support Ghost has a little trick to it, but is not hard
- Dreamhost prohibits Node.js installation on a shared hosting account, it can only be done on a VPS
- The Ghost installer expects it's being run as
root
in a VPS and that it must do some things to set upnginx
for proxying, and to create a low-privilege user to run Ghost -- but Dreamhost VPS's don't support the necessary access -- so we have to run this a little differently - While the Ghost team warns against using Node.js installed by
nvm
that's what we must do
Installing nvm
We need a fairly up-to-date version of Node.js, and the crufty old version Dreamhost supplies in the crufty old Ubuntu 14.04 we're provided on VPS's just doesn't cut it. Fortunately nvm makes it easy to install any Node.js version you wish. Getting Ghost to use it is just a matter of a little configuration.
Instructions: https://github.com/creationix/nvm
In a terminal session on your Dreamhost VPS, type this command:
$ wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
Ghost supports Node.js 4.5, 6.9 and 8.9, so type this:
$ nvm install 8
v8.9.4 is already installed.
Now using node v8.9.4 (npm v5.6.0)
Installing Ghost-CLI
With Node.js installed type:
$ npm install -g ghost-cli
This installs the Ghost command-line tool, documentation: https://docs.ghost.org/v1.0.0/docs/ghost-cli
Setup subdomain w/ Passenger/Node.js support
There's more instructions on this at: Deploy Node.js application using Passenger on Dreamhost or other hosting providers
In the Dreamhost control panel, set up a new domain (or subdomain), with these entries in the form:
- Type a domain to use - like
example.com
- Click either Add WWW or Remove WWW depending on your preference
- For the user account to run this under, choose one you have on your VPS -- I have one VPS with one user ID installed, and chose that user
- For Web Directory, you'll be presented with
/home/username
and in the text entry box the domain (e.g.example.com
) you'll use. You MUST extend the text in the box to readDOMAIN.TLD/public
or e.g.exmple.com/public
- Click the button for Passenger
- In the buttons that show themselves, select Node.js
Then click the button at the bottom to setup the domain.
When the Dreamhost installation software sets up the DOMAIN.TLD
directory, delete all contents. The Ghost installer will complain about being run in a non-empty directory and refuse to do anything.
Install and setup Ghost
The Ghost team has setup instructions which we'll use parts of: https://docs.ghost.org/v1.0.0/docs/install
The steps taken so far are preparatory so we can do the following.
Ideally you just run this and it would install:
$ ghost install --db=sqlite3
Ghost can also run against MySQL, and Dreamhost offers a MySQL service. I wanted to instead use SQLite for now, and setup the MySQL service later.
Unfortunately that produces this error message:
1) SystemError
Message: The path /home/USERNAME/ is not readable by other users on the system.
This can cause issues with the CLI, please either make this directory readable by others or install node and Ghost-CLI in another location.
The fix is this:
$ chmod 755 $HOME
Dreamhost probably set this up with a 700 permissions which is a useful permission setting for shared hosting. However, we're on a VPS and there's noone else on that VPS and therefore making the directory readable by others is perfectly fine.
Rerunning the above command still fails because Ghost wants to do this:
Running sudo command: useradd --system --user-group ghost
? Password [hidden]
? Password [hidden]
? Password [hidden]
✖ Setting up "ghost" system user
Remember when I said at the top the Ghost installer is assuming it's run by root
on an empty VPS and it must set up a whole bunch of things including a low-privelege user. There's certain things we must instruct the Ghost installer to skip over.
See: https://docs.ghost.org/v1.0.0/docs/cli-setup
That page covers the ghost setup
subcommand, which says there are several stages to the ghost install
command. For each stage it calls ghost setup
to perform the stage. If we want the installer to skip a stage, we use --no-setup-STAGE-NAME
. In this case:
$ ghost install --db=sqlite3 --no-setup-linux-user --no-setup-nginx --no-setup-ssl --no-setup-systemd
For the last three of those you can simply answer No when it asks, like so:
? Do you wish to set up Nginx? No
ℹ Setting up Nginx [skipped]
Task ssl depends on the 'nginx' stage, which was skipped.
ℹ Setting up SSL [skipped]
? Do you wish to set up Systemd? No
ℹ Setting up Systemd [skipped]
✔ Running database migrations
? Do you want to start Ghost? No
We end up with a directory containing:
$ ls
config.production.json content current versions
We're not ready to run anything yet, and have three things to do.
First, we need to setup the public
directory we deleted a ways back. We needed the directory to be empty for the Ghost installer to even run, but the Dreamhost Passenger setup requires the public
directory and more specifically a .htaccess
in that file.
$ mkdir public
$ touch public/.htaccess
Then in .htaccess
add this line:
PassengerNodejs /home/USERNAME/.nvm/versions/node/v8.9.4/bin/node
Adjust this for the Node.js version you have installed.
Finally we need a file named app.js
to start the application. Passenger looks for this file, and while the Passenger documentation seems to support a way to change which file it looks for I couldn't figure it out. Instead I added a file, app.js
, containing this:
const app = require('./current/index.js');
The file current/index.js
is the module used to launch Ghost. This takes care of loading that module and executing its code.
A configuration file is in the directory as well, and you can use something like this:
{
"url": "http://example.com",
"server": {
"port": 80,
"host": "0.0.0.0"
},
"database": {
"client": "sqlite3",
"connection": {
"filename": "./content/data/ghost.db"
}
},
"mail": {
"transport": "Direct"
},
"logging": {
"transports": [
"file",
"stdout"
]
},
"process": "systemd",
"paths": {
"contentPath": "/home/USERNAME/gh.7gen.com/content"
}
}
Running and troubleshooting
Once all that is running, just visiting http://DOMAIN
should bring up Ghost, and you'll be good to go.
If something goes wrong, the error log may have clues in $HOME/logs/DOMAIN/error.log