使用Docker搭建Ghost博客

对于想搭建自己博客的人来说,可选择的平台有很多,比如功能强大的WordPress、可运行在GitHub Pages上的静态博客平台Hexojekyll,以及本文介绍的博客平台Ghost。各平台各有优劣,本文不作赘述,重点介绍如何自己搭建一个可用的Ghost博客。

总体来说可通过两个docker run命令,分别运行Ghost博客和Nginx服务器即可,但运行前需要进行相关的配置。

1. 前期准备

搭建该平台需要准备如下的内容:

  • 一个公网可访问的服务器,如可使用阿里云服务器。服务器建议安装64位的Linux系统,并安装docker。
  • 一个域名,也可不使用域名,直接通过IP地址访问。本文以本博客使用的域名blog.datarepo.cn为例。

2. 配置并运行Ghost博客

使用Docker安装Ghost可以省掉配置环境的繁琐过程。但需要将配置信息、主题及博客内容存储在本地,以防止Docker运行停止造成的数据丢失。

下面是Ghost中存放这些信息的路径:

  • 配置文件:/var/lib/ghost/config.production.json和/var/lib/ghost/config.development.json
  • 主题:/var/lib/ghost/content/themes/
  • 博客内容:/var/lib/ghost/content/

配置修改

Ghost的官方容器镜像中有默认的配置文件,需要对其进行修改,主要是“url”和“mail”两个字段。配置修改方式为两种,一种是在容器中修改,然后重新打包为新的镜像;另一种为在本地创建文件,然后挂载到容器中,以替换容器中的文件。本文选用第二种方法。

本地创建配置文件:config.production.json和config.development.json

# touch config.production.json 

在config.production.json文件中添加如下内容,其中邮箱以163邮箱为例。也可直接下载config.production.json,并对相应的字段进行修改:

{
  "url": "yoururl",
  "server": {
    "port": 2368,
    "host": "0.0.0.0"
  },
  "database": {
    "client": "sqlite3",
    "connection": {
      "filename": "/var/lib/ghost/content/data/ghost.db"
    }
  },
  "mail": {
    "transport": "SMTP",
    "from": "youremail",
    "options": {
       "host": "smtp.163.com",
       "secureConnection": true,
       "port": 465,
       "auth": {
         "user": "youremail",
         "pass": "yourpassword"
       }
    }
  },
  "logging": {
    "transports": [
      "file",
      "stdout"
    ]
  },
  "process": "systemd",
  "paths": {
    "contentPath": "/var/lib/ghost/content"
  }
}

然后复制config.production.json文件:

# cp config.production.json config.development.json

在Ghost容器中,config.development.json为指向config.production.json的链接文件,理论上只需要修改config.production.json文件,但如果本地挂载该文件后,config.development.json文件的链接会发生错误,造成无法启动。

使用Gitalk作为评论组件

由于国内的多说已经关闭,国外Disqus访问不稳定,本文选用Gitalk作为评论组件。Gitalk是基于Github issue和Preact实现的开源评论组件。实现效果见本博客最下方,或Gitalk的Demo

为了添加评论组件,首先下载Ghost博客的默认主题Casper

# mkdir content/themes/
# cd content/themes/
# git clone https://github.com/TryGhost/Casper.git

添加评论组件需要创建Github Application,并修改casper/post.hbs文件,配置方法详见Gitalk项目主页教程

修改后的post.hbs可参考文件post.hbs中的Gitalk comment component一段,并根据官方教程修改其中的字段。

使用Gitalk需要有github账号,并且在一篇文章发表之后,需要点开文章并初始化评论,其他人才可以使用。

解决Gitalk出现validation error错误问题

需要注意的是,在Gitalk的配置中,id 字段需要格外注意,官方推荐的写法为location.pathname ,确保每一个文章都有不同的id 值。该字段用于在github中创建当前文章对应的issue,作为label添加到issue中,如果该字段设置为固定值,则只能创建一个issue,即所有文章共享相同的评论,显然这样是不可接受的。

同时,还需要注意的是,github在2018年2月份对issue中label的字符长度进行限制,如果id 字段过长(超过50个字符),则会创建issue失败,打开文章后会显示validation error,详见官方issue

为了解决该问题,可以在创建文章时修改URL,使其总长度小于50字符。或者采用官方issue中DOUBIGROUP给出的方法,将id字段设置为location.pathname的md5值,具体方法为,在casper/post.hbs添加:

<script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.min.js"></script>

并将id字段设置为:md5(location.pathname)

中文摘要截取问题

当前Ghost博客对中文的支持较差,Casper主题在主页中使用post-card作为单个文章的展示,图片后的文字默认截取33个单词,但是不支持对中文字数的截取,通常会在图片后放大段的文字,展现效果不够美观。

本文参考Ghost 调教日志 - 解决中文摘要的截取问题对Ghost和Casper主题代码进行了修改。包括excerpt.js文件和post-card.hbs文件,修改后的文件见excerpt.jspost-card.hbs

其中excerpt.js文件为Ghost博客中的代码文件,通过本地文件挂载的形式对原文件进行覆盖,post-card.hbs为Casper博客中的文件,可直接替换掉本地文件casper/partials/post-card.hbs。

图片超出文档范围问题

默认情况下由于Ghost CSS样式文件问题,博客中引入的图片会超出文章的总宽度,本文参考Ghost 调教日志 - 解决图片超过文章宽度方法,在Ghost后台中插入代码解决。

在后台Settings/Code injection的Blog Header中加上如下内容:

<style type="text/css">
.post-full-content img {
    max-width: none !important;
    width: 100% !important;
}
</style>

文章第一段显示字体过大的问题

Casper主题中文章的第一段字体和正文相比较大,这样浏览起来不够美观,尤其是在手机端浏览时。参考上面的做法,使用代码注入的方式,覆盖原来的CSS文件中的代码片段。

在后台Settings/Code injection的Blog Header中的</style>前插入如下内容:

.post-template .kg-card-markdown > p:first-child {
    font-size: 1em !important;
    line-height: 1.5em;

运行Ghost镜像

切换到config.production.json文件所在的目录,执行docker run命令运行Ghost镜像,并挂载本地文件:

# docker run -d --name blog -p 2368:2368 \
   -v `pwd`/content/:/var/lib/ghost/content/ \
   -v `pwd`/content/themes/:/var/lib/ghost/content/themes/ \
   -v `pwd`/config.production.json:/var/lib/ghost/config.production.json \
   -v `pwd`/config.development.json:/var/lib/ghost/config.development.json \
   -v `pwd`/excerpt.js:/var/lib/ghost/current/core/server/helpers/excerpt.js \
   ghost:alpine

上述命令指定容器名为blog ,监听端口为默认的2368 ,并分别挂载了博客内容、主题、配置文件和更改的代码文件。

运行上述命令之后,即可通过http://yoururl:2368端口访问博客了。

如果使用阿里云服务器,还需要设置安全组策略,打开2368端口的访问。

3. 配置并运行Nginx服务器

常见的网站一般通过端口80来进行访问,实际上在上述命令中,可直接将端口映射改为-p 80:2368 。但是为了使服务器能够提供尽量多的Web服务,本文没有改变端口映射,而是使用Nginx进行反向代理,将访问二级域名blog.datarepo.cn 80端口的流量转发到Ghost服务端口。

本地创建Nginx配置文件default.conf :

# mkdir conf.d
# cd conf.d
# touch default.conf

添加如下内容:

server {
    listen       80;
    server_name  yoururl;
   
    location / {
        proxy_pass  http://yoururl:2368;
        proxy_set_header           Host $host;
        proxy_set_header  X-Real-IP  $remote_addr;
        proxy_set_header           X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size  100m;
    }
}

切换到包含conf.d的文件夹下,运行Nginx服务:

# docker run -d —name webserver -p 80:80 \
   -v `pwd`/conf.d/:/etc/nginx/conf.d/ \
   nginx:alpine

运行后,即可通过http://yoururl访问博客了。

4. 博客使用

博客的管理页面为http://yoururl/ghost。

登录后可创建用户、通过前文配置的邮箱邀请用户、撰写并发布文章、对博客进行定制等。

需要注意的是,当前Ghost博客的编辑器在iPhone和iPad中无法输入中文,只能在其他地方输入中文后,粘贴到编辑器中,在电脑端不受影响。该问题是Ghost使用的开源markdown编辑器CodeMirror中的bug,详见issue。遗憾的是,这个问题在2015年就发现了,到现在依然没有解决。

Enjoy the fun of writing.