Deploy Ghost blogging system using Passenger on Dreamhost or other hosting providers

By: ( +David Herron; Date: Mon Mar 05 2018 16:00:00 GMT-0800 (Pacific Standard Time)

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 up nginx 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: (

In a terminal session on your Dreamhost VPS, type this command:

$ wget -qO- | 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: (

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
  • 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. you'll use. You MUST extend the text in the box to read DOMAIN.TLD/public or e.g.
  • 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: (

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: (

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": "",
  "server": {
    "port": 80,
    "host": ""
  "database": {
    "client": "sqlite3",
    "connection": {
      "filename": "./content/data/ghost.db"
  "mail": {
    "transport": "Direct"
  "logging": {
    "transports": [
  "process": "systemd",
  "paths": {
    "contentPath": "/home/USERNAME/"

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

« Using SSL to connect to MySQL database in Node.js Dynamic import lands in Node.js, we can import ES6 modules in CommonJS code »
2016 Election 2018 Elections Acer C720 Ad block Affiliate marketing Air Filters Air Quality Air Quality Monitoring AkashaCMS Amazon Amazon Kindle Amazon Web Services America Amiga and Jon Pertwee Android Anti-Fascism AntiVirus Software Apple Apple Flexgate Apple Hardware History Apple Hardware Mistakes Apple iPhone Apple iPhone Hardware April 1st Arduino ARM Compilation Artificial Intelligence Astronomy Astrophotography Asynchronous Programming Authoritarianism Automated Social Posting AWS DynamoDB AWS Lambda Ayo.JS Bells Law Big Brother Big Data Big Finish Big Science Bitcoin Mining Black Holes Blade Runner Blockchain Blogger Blogging Books Botnets Cassette Tapes Cellphones China China Manufacturing Christopher Eccleston Chrome Chrome Apps Chromebook Chromebox ChromeOS CIA CitiCards Citizen Journalism Civil Liberties Climate Change Clinton Cluster Computing Command Line Tools Comment Systems Computer Accessories Computer Hardware Computer Repair Computers Conservatives Cross Compilation Crouton Cryptocurrency Curiosity Rover Currencies Cyber Security Cybermen Cybersecurity Daleks Darth Vader Data backup Data Formats Data Storage Database Database Backup Databases David Tenant DDoS Botnet Department of Defense Department of Justice Detect Adblocker Developers Editors Digital audio Digital Nomad Digital Photography Direct Attach Storage Diskless Booting Disqus DIY DIY Repair DNP3 Do it yourself Docker Docker MAMP Docker Swarm Doctor Who Doctor Who Paradox Doctor Who Review Drobo Drupal Drupal Themes DuckDuckGo DVD E-Books E-Readers Early Computers eGPU Election Hacks Electric Bicycles Electric Vehicles Electron Eliminating Jobs for Human Emdebian Encabulators Energy Efficiency Enterprise Node EPUB ESP8266 Ethical Curation Eurovision Event Driven Asynchronous Express Face Recognition Facebook Fake Advertising Fake News Fedora VirtualBox Fifth Doctor File transfer without iTunes FireFly Flash Flickr Fraud Freedom of Speech Front-end Development G Suite Gallifrey Gig Economy git Github GitKraken Gitlab GMAIL Google Google Adsense Google Chrome Google Gnome Google+ Government Spying Great Britain Green Transportation Hate Speech Heat Loss Hibernate High Technology Hoax Science Home Automation HTTP Security HTTPS Human ID I2C Protocol Image Analysis Image Conversion Image Processing ImageMagick In-memory Computing Incognito Mode InfluxDB Infrared Thermometers Insulation Internet Internet Advertising Internet Law Internet of Things Internet Policy Internet Privacy iOS iOS Devices iPad iPhone iPhone hacking Iron Man iShowU Audio Capture iTunes Janet Fielding Java JavaFX JavaScript JavaScript Injection JDBC John Simms Journalism Joyent jQuery Kaspersky Labs Kext Kindle Kindle Marketplace Large Hadron Collider Lets Encrypt LibreOffice Linux Linux Hints Linux Single Board Computers Logging Mac Mini Mac OS Mac OS X Mac Pro MacBook Pro Machine Learning Machine Readable ID Macintosh macOS macOS High Sierra macOS Kext MacOS X setup Make Money Online Make Money with Gigs March For Our Lives MariaDB Mars Mass Violence Matt Lucas MEADS Anti-Missile Mercurial MERN Stack Michele Gomez Micro Apartments Microsoft Military AI Military Hardware Minification Minimized CSS Minimized HTML Minimized JavaScript Missy Mobile Applications Mobile Computers MODBUS Mondas Monetary System MongoDB Mongoose Monty Python MQTT Music Player Music Streaming MySQL NanoPi Nardole NASA Net Neutrality Network Attached Storage Node Web Development Node.js Node.js Database Node.js Performance Node.js Testing Node.JS Web Development Node.x North Korea npm NSA NVIDIA NY Times Online advertising Online Community Online Fraud Online Journalism Online News Online Photography Online Video Open Media Vault Open Source Open Source and Patents Open Source Governance Open Source Licenses Open Source Software OpenAPI OpenJDK OpenVPN Palmtop PDA Patrick Troughton PayPal Paywalls Personal Flight Peter Capaldi Peter Davison Phishing Photography PHP Plex Plex Media Server Political Protest Politics Postal Service Power Control President Trump Privacy Private E-mail server Production use Public Violence Raspberry Pi Raspberry Pi 3 Raspberry Pi Zero ReactJS Recaptcha Recycling Refurbished Computers Remote Desktop Removable Storage Renewable Energy Republicans Retro Computing Retro-Technology Reviews RFID Rich Internet Applications Right to Repair River Song Robotics Robots Rocket Ships RSS News Readers rsync Russia Russia Troll Factory Russian Hacking Rust SCADA Scheme Science Fiction SD Cards Search Engine Ranking Search Engines Season 1 Season 10 Season 11 Security Security Cameras Server-side JavaScript Serverless Framework Servers Shell Scripts Silence Simsimi Skype SmugMug Social Media Social Media Networks Social Media Warfare Social Network Management Social Networks Software Development Software Patents Space Flight Space Ship Reuse Space Ships SpaceX Spear Phishing Spring Spring Boot Spy Satellites SQLite3 SSD Drives SSD upgrade SSH SSH Key SSL Stand For Truth Strange Parts Swagger Synchronizing Files Tegan Jovanka Telescopes Terrorism The Cybermen The Daleks The Master Time-Series Database Tom Baker Torchwood Total Information Awareness Trump Trump Administration Trump Campaign Twitter Ubuntu Udemy UDOO US Department of Defense Video editing Virtual Private Networks VirtualBox VLC VNC VOIP Vue.js Walmart Weapons Systems Web Applications Web Developer Resources Web Development Web Development Tools Web Marketing Webpack Website Advertising Website Business Models Weeping Angels WhatsApp William Hartnell Window Insulation Windows Windows Alternatives Wordpress World Wide Web Yahoo YouTube YouTube Adpocalypse YouTube Monetization