如何在Heroku 上安裝Ghost Blog

近日找遍各大blog

從外太空找到行天宮終於下定決心在Ghost 定了下來
當然如果你想host 一個blog 而不花到任何費用是 絕對不可能的

最主要的花費如下

  1. 主機費用
  2. Domain name 申請

其實你也可以選擇 wordpress,或者 logdown 這些國內外知名的部落格來寫作,如果都選擇最低標準的方案或許不會花到任何錢

但是身為專業的工程師就要全部自己來阿

本篇用到的工具如下

Ghost:
一套免費開源而且非常精美的blog架站軟體,支援Markdown讓你書寫起來更快速

Heroku:
一種支援多種語言的雲端平台服務(PaaS),能編譯、執行及管理各式各樣的語言平台


下載並且安裝 Ghost

首先下載Ghost,可以到這邊下載,在撰寫這篇文章的同時Ghost的版本是0.7.9,照著以下的操作說明還是無法架起來的話,可以檢查Ghost的版本是否相符

下載好之後你可以透過以下指令把檔案解壓縮到網站的目錄下,暫且稱範例網頁為my-blog

1
$ unzip ghost-0.7.9.zip -d my-blog

設定 Heroku 環境

若還沒有Heroku 帳號的話可以到這頁面來註冊,完成後便能在你的作業系統上安裝Heroku,筆者不推薦在Windows 平台上操作,建議使用Ubuntu 來完成

安裝好後至command line 輸入指令登入:

1
$ heroku login

初始化設定

登入後移動到網站目錄下,並且建立一個Git Repository 上傳Ghost 的程式碼,之後再建立一個 Heroku app 就完成了
當你建立好heroku app之後,heroku 便會產生一個remote uri 至你的 .git/config,你可以使用 less .git/config 來檢查檔案內容

1
2
3
$ cd /your/ghost/folder/
$ git init
$ heroku create

heroku create 會出現以下訊息,而網頁便會跑在 https://morning-tor-47399.herokuapp.com/

1
2
Creating app... ⬢ morning-tor-47399
https://morning-tor-47399.herokuapp.com/ | https://git.heroku.com/morning-tor-47399.git

.git/config 內容:

1
2
3
4
5
6
7
8
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "heroku"]
url = https://git.heroku.com/damp-lake-83795.git
fetch = +refs/heads/*:refs/remotes/heroku/*

安裝 Heroku 相關套件

Ghost 預設的SQL Database 是用SQLite3,如果你不希望用這麼陽春版的資料庫也可以換成PostgreSQL:

1
$ heroku addons:create heroku-postgresql:hobby-dev

安裝後可以執行 heroku config 來看剛剛資料庫設定的訊息,你可能會看到類似的輸出:

1
DATABASE_URL: postgres://qqonqkttfshxui:[email protected]com:5432/d24q4651ilbs4n

資料庫的相關訊息如下:

  • Database URL: ec2-54-243-63-195.compute-1.amazonaws.com
  • Database Port: 5432
  • Database Name: d24q4651ilbs4n
  • Database UserName: qqonqkttfshxui
  • Database Password: oGKWpEnyHIKKCgsMIHrHs8aKk

Ghost 參數設定

目前為止,已經完成前置作業了,現在要開始來設定Ghost的服務,首先必須先設置參數檔

1
cp config.example.js config.js

編輯 config.js,在production 的區塊內加入資料庫的設定:

1
2
3
4
5
6
7
8
9
10
11
database: {
client: 'postgres',
connection: {
host: process.env.POSTGRES_HOST,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
database: process.env.POSTGRES_DATABASE,
port: '5432'
},
debug: false
}

你可能會好奇為什麼不改成上面的設定,這點後面會解釋。

由於啟動Node.js app 時必須綁定一個port,而heroku在每次重新啟動的時候都會動態配給一個port 給Node.js app,因此 config.js 必須加入以下設定
找到以下片段:

1
2
host: '127.0.0.1',
port: '2368'

取代成

1
2
host: '0.0.0.0',
port: process.env.PORT

到這一步後基本上所有的設定都完成了,你可以把目前的code 同步到heroku 上:

1
2
3
git add .
git commit -m "Committing all Ghost files"
git push heroku master

但是上傳上去的網頁還不能正常運作,你可能會看到以下的畫面:
![heroku application error]
(https://drive.google.com/uc?export=view&id=1SYp0k6zPbN6rJtOURzocUsAtD9XLdMd7)

這是因為尚未設定database 的參數還沒有設定好,可以透過 heroku logs 查看錯誤訊息:
database connection error

Pool2 是 node.js與資料庫連線的套件,因此還要輸入以下指令:

1
2
3
4
$ heroku config:set POSTGRES_HOST=<value>
$ heroku config:set POSTGRES_USER=<value>
$ heroku config:set POSTGRES_PASSWORD=<value>
$ heroku config:set POSTGRES_DATABASE=<value>

設定好後重新載入網頁就大功告成啦!!

設定圖片上傳

為什麼要特地把這單元拿出來講 ? 如果你不是用Heroku 而是用其他網站空間的話不需要設定這一步,因為 Ghost就有內建圖片上傳的功能,而Heroku 不允許檔案的動態新增,想知道更多詳細資料的話可以參考這篇,所以只能透過其他的外掛服務來上傳圖片。

也因此筆者推薦 Amazon S3 的服務,github上已經有人整理好plugin 了,只要套上即可

在網頁目錄下輸入以下指令:

1
2
3
$ npm install --save ghost-s3-storage
$ mkdir -p content/storage/ghost-s3
$ vi content/storage/ghost-s3/index.js

index.js 輸入以下文字並儲存:

1
2
'use strict';
module.exports = require('ghost-s3-storage');

最後只需要告訴Ghost 該如何儲存圖片即可,回到網頁的根目錄並且新增以下內容到 config.js

1
2
3
4
5
6
7
8
9
10
storage: {
active: 'ghost-s3',
'ghost-s3': {
accessKeyId: process.env.S3_ACCESSKEY,
secretAccessKey: process.env.S3_SECRETKEY,
bucket: 'ghost-blog-bucket',
region: 'us-west-2',
assetHost: 'https://s3-us-west-2.amazonaws.com/ghost-blog-bucket/'
}
}

Amazon s3 的註冊教學可以參考筆者的另一篇文章
最後便可以上傳到github了,不過在上傳前仍有一步需要調整,執行 git status 會看到以下畫面
git status

config.jspackage.json 是因為剛剛加了 ghost-s3-storage 時所產生的,而 node_modules/ 是compile plugin 後產生的資料夾,這個檔案不應該傳到Heroku 上,Heroku只要放Source code 就可以了,因此必須建立 .gitignore 這個檔案,並加入以下內容:

1
2
3
$ echo "node_modules/" > .gitignore
$ git add .gitignore
$ git commit -m "Ignore node_modules directory"

再來便可以真正的上傳目前的程式碼了,在Command line輸入以下指令:

1
2
3
$ git add .
$ git commit -m "add ghost-s3-storage"
$ git push heroku master

儘管更新了程式碼,但是打開網頁後它還是死給你看,檢查 heroku logs 後發現噴了一堆 npm ERR!,節錄部分的內容如下:

1
2
2016-05-02T15:15:47.014552+00:00 app[web.1]: ERROR: Ghost is unable to start due to missing dependencies:
2016-05-02T15:15:47.014564+00:00 app[web.1]: Cannot find module 'ghost-s3-storage'

導致這個問題發生的主因是因為網站根目錄的 npm-shrinkwrap.json 把套件的相依關係鎖住了,因此需要更新 npm-shrinkwrap.json

1
2
$ npm install
$ npm shrinkwrap

想了解 shrinkwrap 的話可以參考這篇文章

更新 npm-shrinkwrap.json 後重新push 到github

1
2
3
$ git add npm-shrinkwrap.json
$ git commit -m "update shrinkwrap.json"
$ git push heroku master

立刻重新整理你的網頁吧。

設定信箱服務

緊接著來介紹Ghost 的mail服務吧

筆者使用mailgun 來當教學範例,在註冊頁面建立帳號後前往後台會看到一個預設的Domain name
mailgun 後台

進入Domain name的設定頁面後只需要取得 Default SMTP Login 以及 Default Password 兩個欄位的結果而已
mailgun Domain information

回到網站目錄下的 config.js,在production 區塊下加入SMTP 的相關設定:

1
2
3
4
5
6
7
8
9
10
mail: {
transport: 'SMTP',
options: {
service: 'Mailgun',
auth: {
user: process.env.MAILGUN_USER,
pass: process.env.MAILGUN_PASS
}
}
},

存檔好之後加入heroku 的變數:

1
2
$ heroku config:set MAILGUN_USER=<value>
$ heroku config:set MAILGUN_PASS=<value>

最後重新push 上heroku 即可大功告成

1
2
3
$ git add .
$ git commit -m "add mail service"
$ git push heroku master

客製化網域

如果想正式營運一個blog,用Heroku 提供的網址並不是一個好方法
因為Heroku 提供的網址太不好記,Domain 給人的感覺就像是見到陌生人的第一印象,你可能會因為這個人的外表去做一些個性上的聯想
雖然兩者的關係並不是絕對的,而Domain Name也一樣,從看到名稱開始你可能就會開始想像這個Blog葫蘆裡賣的是什麼藥。

筆者目前的網域便是在Godaddy 上購買的

購買完網域之後你必須指定一個 cname 到 你的 Heroku app url,例如本篇的教學網址: https://morning-tor-47399.herokuapp.com/,新增的方式大致上如下:

1
2
3
NAME       TYPE   VALUE
--------------------------------------------------
www CNAME https://morning-tor-47399.herokuapp.com/

或者你不希望用www,其他名稱取代也可以,例如blog:

1
2
3
NAME       TYPE   VALUE
--------------------------------------------------
blog CNAME https://morning-tor-47399.herokuapp.com/

供應商這邊設定好之後Heroku 設定也一併需要調整,不然你就會看到 Can't find Heroku app 這個Error了,Heroku 的設定如下:

1
$ heroku domains:add blog.your_customer_domain.com

恭喜你,你的Blog 現在正式上線了。