While I'm looking at Ghost related-things, let's take a quick look at using Ghost on Heroku. One of the organizations I volunteer at recently spun up a website and decided they wanted a blog. I figured integrating a Ghost blog in there would be a great, lightweight solution. Best part is that someone else would be maintaining the software updates for the platform itself.
Personally, this is my first foray with Heroku but luckily it looks I was able to find someone who has this process started for 0.11.3, cobyism/ghost-on-heroku. I forked the repo and made a couple of changes, one was to remove the "click to deploy" feature. My main reason for doing this is that Heroku prompted me for a payment method even though the app was only using free resources when I went to deploy. So instead I just linked Heroku to the private Github repo and deployed that way.
One thing I did learn is that
app.json, the handy Heroku app manifest, is only read on the initial deploy. So if you, like me, did a bare deploy and then added the info for an S3 bucket or an actual URL instead of just the Heroku app URL, the updated information isn't picked up from
I discovered this when the app crashed fabulously like so:
2017-02-04T17:53:42.152191+00:00 heroku[web.1]: Starting process with command `npm start --production` 2017-02-04T17:53:45.872184+00:00 app[web.1]: 2017-02-04T17:53:45.872201+00:00 app[web.1]: > node server.js 2017-02-04T17:53:45.872200+00:00 app[web.1]: > firstname.lastname@example.org start /app 2017-02-04T17:53:45.872202+00:00 app[web.1]: 2017-02-04T17:53:49.636003+00:00 heroku[web.1]: Process exited with status 0 2017-02-04T17:53:49.512391+00:00 app[web.1]: Unhandled rejection TypeError: This library (validator.js) validates strings only 2017-02-04T17:53:49.512403+00:00 app[web.1]: at assertString (/app/node_modules/ghost/node_modules/validator/lib/util/assertString.js:9:11) 2017-02-04T17:53:49.512404+00:00 app[web.1]: at Object.isURL (/app/node_modules/ghost/node_modules/validator/lib/isURL.js:54:30) 2017-02-04T17:53:49.512405+00:00 app[web.1]: at ConfigManager.validate (/app/node_modules/ghost/core/server/config/index.js:420:20) 2017-02-04T17:53:49.512406+00:00 app[web.1]: at /app/node_modules/ghost/core/server/config/index.js:334:29 2017-02-04T17:53:49.512407+00:00 app[web.1]: at tryCatcher (/app/node_modules/ghost/node_modules/bluebird/js/release/util.js:16:23) 2017-02-04T17:53:49.512409+00:00 app[web.1]: at Promise._settlePromiseFromHandler (/app/node_modules/ghost/node_modules/bluebird/js/release/promise.js:510:31) 2017-02-04T17:53:49.512410+00:00 app[web.1]: at Promise._settlePromise (/app/node_modules/ghost/node_modules/bluebird/js/release/promise.js:567:18) 2017-02-04T17:53:49.512410+00:00 app[web.1]: at Promise._settlePromiseCtx (/app/node_modules/ghost/node_modules/bluebird/js/release/promise.js:604:10) 2017-02-04T17:53:49.512411+00:00 app[web.1]: at Async._drainQueue (/app/node_modules/ghost/node_modules/bluebird/js/release/async.js:143:12) 2017-02-04T17:53:49.512412+00:00 app[web.1]: at Async._drainQueues (/app/node_modules/ghost/node_modules/bluebird/js/release/async.js:148:10) 2017-02-04T17:53:49.512413+00:00 app[web.1]: at Immediate.Async.drainQueues [as _onImmediate] (/app/node_modules/ghost/node_modules/bluebird/js/release/async.js:17:14) 2017-02-04T17:53:49.512413+00:00 app[web.1]: at processImmediate [as _immediateCallback] (timers.js:367:17) 2017-02-04T17:53:49.652290+00:00 heroku[web.1]: State changed from starting to crashed 2017-02-04T17:53:50.746150+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=yagb.herokuapp.com request_id=24929605-de9c-4504-9326-a3f2d766c9b4 fwd="184.108.40.206" dyno= connect= service= status=503 bytes= 2017-02-04T17:53:51.086501+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=yagb.herokuapp.com request_id=104cb0c8-fcd1-4173-aae6-b40861ce4e9e fwd="220.127.116.11" dyno= connect= service= status=503 bytes=
Since it was failing validation, I checked out the environment variables for the app:
$ heroku run printenv --app yagb Running printenv on ⬢ yagb... up, run.8203 (Free) TERM=xterm-256color WEB_MEMORY=512 MEMORY_AVAILABLE=512 COLUMNS=202 DYNO=run.8203 PATH=/app/.heroku/node/bin:/app/.heroku/yarn/bin:/usr/local/bin:/usr/bin:/bin:/app/bin:/app/node_modules/.bin WEB_CONCURRENCY=1 PWD=/app NODE_ENV=production PS1=\[\033[01;34m\]\w\[\033[00m\] \[\033[01;32m\]$ \[\033[00m\] LINES=47 SHLVL=1 HOME=/app PORT=21806 DATABASE_URL=postgres://██████████:████████████████████@ec2-██-██-██-██.compute-1.amazonaws.com:5432/████████ NODE_HOME=/app/.heroku/node _=/usr/bin/printenv
Lo! No updated
HEROKU_URL or anything else. So these needed to be updated/added in the Heroku UI under Settings -> Config Variables - no big deal. I also created and linked to a named Ghost database instead of just the default using the Heroku CLI:
$ heroku addons:create heroku-postgresql:hobby-dev --as ghostdb --app yagb
Looking at cobyism's
package.json file, currently s/he's set up for 0.11.3. Since the latest version of Ghost is 0.11.4, now that I have 0.11.3 working I'm going to update to 0.11.4. Hopefully this'll go easier than last time. ¯\_(ツ)_/¯
Anywho, in order to update to 0.11.4 aside from changing 0.11.3 to 0.11.4 I also update Casper to 1.3.5 (as that ships with 0.11.4), the version of
~4.7 as the recommended versions of
node to use with Ghost are the 4.x Argon LTS releases.
ghost-s3-storage-adapter were still at their latest releases.
The deploy was successful and now the org has v0.11.4 of Ghost on Heroku. Happy endings ^.^
Fun facts: How to Semver with npm
So you may be wondering what the difference between
^x.y.z is, since both versions (see what I did thar) appear in
package.json. In the first case,
~x.y.z, matches the most recent minor version (the
y). The second case,
^x.y.z, matches the most recent major version. With some relevant numbers, that means
~4.7.3 pick up the latest
4.7.x release. Right now, it happens to be
4.7.3 but if there was a update to
4.7.4 that version would be applied on the next deploy. That said, a
4.8.x release would not be applied - unless I used
^4.7.3, then the latest release through (but not including)
5.x.x would be used during a deploy.
For more information, see tilde and caret releases on the NPM docs.