Create a blog on Ghost with Traefik

看了一下自从上一次更新之后这又过去一个季度了。要不是这次短期旅行没有带上平时工作的电脑估计我还不知道什么时候可以抽出时间写下这篇文章。说起来让人感慨,读书的时候我对于写代码非常不感兴趣,当年还是靠我一哥们给我讲题,帮我做作业勉强毕的业。那曾想到30岁之后因为工作的原因重新接触代码之后反而被迷住了,现在仅存的一点个人时间都放在各种有的没得project上面。

言归正传,我们下面分几个方面来说说Ghost以及如何用Docker和Traefik来快速搭建一个Ghost Blog。

什么是Ghost

我在之前的文章中也介绍过如何安装Wordpress。根据W3Techs的这篇CMS占比的文章,Wordpress 超过60%的市场占有率让它毫无疑问地成为了很多人建站的第一选择。大部分的share hosting肯定都有一键安装Wordpress的功能,而且多年的深耕也让WP拥有了及其庞大的皮肤和插件库。但是也正因为使用的人太多,让很多网站看起来都以一种同质化的感觉,而且强大的功能对于普通的博客用户根本就是累赘,反而影响了网站的加载速度以及安全性。

Ghost在这种情况下与2012年应运而生,目标是为了纯粹的博客基于Node.js诞生的一个平台。之前看过某个奥地利博主的这篇文章很好的说明了我对于Ghost的初始印象。

A blogging platform which is just for blogging? Having a neat markdown editor? This amazing dashboard? SEO right out of the box? Ways to extend via plugins and themes? Oh boy, John, you got me sold.

准备配置文件

自从我用上了Docker和Traefik之后,除了有特别需求的网站之外(例如需要Client Authentication的Apache)我建所有的网站都是用他们来做。在自由度上来说可能比传统的用命令行来的少,但是搭建起来实在太方便了,废话不多说,开始讲解。

首先是docker-compose.yml这个文件。废话不多说,先放一张最后的成品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
version: '3.3'

services:
traefik:
image: traefik:1.7-alpine
command: --api --docker
ports:
- 80:80
- 443:443
labels:
- "traefik.enable=true"
- "traefik.backend=traefik"
- "traefik.frontend.rule=Host:monitor.your.domain"
- "traefik.port=8080"
networks:
- traefiknet
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.toml:/traefik.toml
- ./acme.json:/acme.json
container_name: traefik
restart: always

ghost:
image: ghost:alpine
restart: always
ports:
- 2368
volumes:
- ./ghost/content:/var/lib/ghost/content
- ./ghost/config.production.json:/var/lib/ghost/config.production.json
environment:
- NODE_ENV=production
- url=https://ghost.your.domain
labels:
- "traefik.enabled=true"
- "traefik.backend=ghost"
- "traefik.frontend.rule=Host:ghost.your.domain"
- "traefik.docker.network=traefiknet"
- "traefik.port=2368"
networks:
- traefiknet
container_name: ghost
depends_on:
- traefik

networks:
traefiknet:

接下来让我分开讲解一下两个container的配置重点。

Traefik Configuration
  • image :使用的是1.7-alpine,我之前一直用latest这个tag,但是在Traefik升级到2.0之后语法都不一样了,因此我之前的网站挂了一天我都没发现……(这也是用WatchTower自动升级image的坏处)
  • command
    • --docker Enable Docker backend with default settings (default “false”)
    • --api Enable api/dashboard (default “false”)
  • ports :打开80和443的端口
  • labels
    • 需要改的只有"traefik.frontend.rule=Host:monitor.your.domain",把host name改成你喜欢的Dashboard的URL,其他copy
  • networks:自定义一个网络让Ghost和Traefik可以沟通(也可以不加)
  • volumes
    • traefik.toml加载自定义traefik连接的config文件
    • acme.json保存自动获取的Let'sEncrypt证书的文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
traefik:
image: traefik:1.7-alpine
command: --api --docker
ports:
- 80:80
- 443:443
labels:
- "traefik.enable=true"
- "traefik.backend=traefik"
- "traefik.frontend.rule=Host:monitor.your.domain"
- "traefik.port=8080"
networks:
- traefiknet
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.toml:/traefik.toml
- ./acme.json:/acme.json
container_name: traefik
restart: always
traefik.toml 文件讲解
  • logLevel:用来检查docker运行情况的,一旦运行不起来,这些信息可以有效的帮助我debug,这里可以用INFO或者DEBUG
  • defaultEntryPoints:默认打开http 和 http
  • [entryPoints.https.tls]
    • minVersion:只支持TLS1.2或以上的protocol来连接
    • cipherSuites :只支持这几个cipher suite来连接。这个部分我是使用Mozilla SSL Config来帮我完成
  • **[acme]**:这里定义如何通过ACME来获取证书,我也只挑我认为重要的讲讲
    • KeyType:定义获取的证书使用的私钥类型和大小,我喜欢ECC,所以选的ECC384。更多的选择可以参考Traefik官方文档
    • **[[acme.domains]]**:这里定义了证书包含的域名。我只想用一张证书来保护我所有的域名,因此我在这里定义了主域名和sans。也可以完全不加这个部分,那么Traefik会为不同的FQDN获取不同的证书保存在acme.json里面来使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
logLevel = "INFO"

defaultEntryPoints = ["http", "https"]

[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
minVersion = "VersionTLS12"
cipherSuites = [
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
]

[acme]
email = "[email protected]"
storage = "acme.json"
onHostRule = true
KeyType = "EC384"
entryPoint = "https"
[acme.httpChallenge]
entryPoint = "http"

[[acme.domains]]
main = "monitor.your.domain"
sans = ["ghost.your.domain"]
生成acme.json文件
1
2
touch acme.json
sudo chmod 600 acme.json
Ghost Configuration

网上大部分的Ghost教程都用的MySQL的数据库。我认为普通人使用Ghost自带的SQLite已经完全足够,我们也不需要再配置以及连接MySQL和Ghost(虽说不难吧……还是能省则省)

  • image:这里我们选择用最新的Ghost Alpine Image (Alpine的好处是体积小,所以任何可以用alpine的image我都用alpine)
  • volumes
    • ./ghost/content是把Ghost的文件映射到服务器本地方便修改
    • ./ghost/config.production.json是把Ghostd的config文件映射出来方便修改,这一步挺重要的,不然你就需要使用docker exec进入到container去修改这个文件了
  • 其他的照抄,需要注意的就是把下面的URL改成你blog的地址
    • "traefik.frontend.rule=Host:ghost.your.domain"
    • - url=https://ghost.your.domain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ghost:
image: ghost:alpine
restart: always
ports:
- 2368
volumes:
- ./ghost/content:/var/lib/ghost/content
- ./ghost/config.production.json:/var/lib/ghost/config.production.json
environment:
- NODE_ENV=production
- url=https://ghost.your.domain
labels:
- "traefik.enabled=true"
- "traefik.backend=ghost"
- "traefik.frontend.rule=Host:ghost.your.domain"
- "traefik.docker.network=traefiknet"
- "traefik.port=2368"
networks:
- traefiknet
container_name: ghost
depends_on:
- traefik
配置config.production.json

这个文件其实是Ghost自动生成的,唯一需要修改的地方就是网站的URL了。你可以也注意到了这里可以配置Mail。ghost支持自动发送邮件给用户。想用的朋友可以根据自己邮箱的服务商来配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"url": "http://ghost.your.domain",
"server": {
"port": 2368,
"host": "0.0.0.0"
},
"database": {
"client": "sqlite3",
"connection": {
"filename": "/var/lib/ghost/content/data/ghost.db"
}
},
"mail": {
"transport": "Direct"
},
"logging": {
"transports": [
"file",
"stdout"
]
},
"process": "systemd",
"paths": {
"contentPath": "/var/lib/ghost/content"
}
}

下面以我用的腾讯企业邮为例,大家可以参考应该怎么配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
,
"mail": {
"from": "[email protected]",
"transport": "SMTP",
"options": {
"host": "smtp.exmail.qq.com",
"secureConnection": true,
"requiresAuth": true,
"port": 465,
"auth": {
"user": "[email protected]",
"pass": "YourPassword"
}
}
},
...

开始安装

这里我假设各位已经安装好了docker和docker-compose

  1. ssh到vps,默认进入home folder
  2. touch docker-compose.yml && touch traefik.toml 创建docker-composetraefik的配置文件,之后可以用vim或者nano打开文件把上文的内容粘贴进去
  3. touch acme.json && chmod 600 acme.json创建acme.json文件并修改access权限
  4. mkdir ghost && cd ghost && touch config.production.json创建ghost目录,生成config.production.json文件。把上文这个config的文件修改好域名之后copy进去即可
  5. cd ..回到home folder
  6. docker-compose up运行docker-compose,系统会自动把image抓下来安装并且ssl证书也会一并安装好

理论来说如果各位按照我上面的做法来做肯定可以成功。