一、博客的选择

好吧,这是个悲伤的故事,我曾经有很多博客,包括博客园、csdn甚至51CTO、简书等等,这些博客都不算难用,但是都有一个通病--无法定制化博客,想要自己定制化博客,只能自己搭建一个博客了。
一开始我使用的是hexo,使用它的最大好处就是简单,而且外观也还算漂亮,不方便的地方就是它需要一个本地的书写环境,而且要推github,还需要钩子监听程序,如果想要在不同的地方写博客,还挺麻烦的。最终,看到有ghost这么个东西,所以有了新建博客的想法,没想到却接连踩坑。。

二、简易的搭建教程

ghost博客发展了很多年了,到目前为止(2019-05-17)最新版本号为2.20.1,安装方式的话,官网有提供若干种方法(多种方式安装文档),包括二进制文件安装,从源码安装,甚至还有很潮的docker安装方式,这里墙裂建议使用docker的安装方式(ghost在docker),最为简单,定制化也不难,当然这里需要docker的一点知识才行
如果想使用docke安装,必须要拥有docker运行环境才行,安装docker的教程:centos docker安装文档
安装完成docker,只需要直接运行以下命令即可完成一键部署:

docker run -d --name some-ghost ghost

然后在浏览器中输入:http://{ip}:2368 即可看到博客页面,按步骤设置即可看到博客页面了
当然,由于ghost镜像封装了默认的所有配置,所以如果你使用了虚拟机做测试而且并非在虚拟机内打开的博客,你可能不知道如何调整一些东西,因而会有一些疑问:

  • 为啥我一定要用docker不可
  • 为什么菜单项中的url都是http://localhost 的地址,如何修改它
  • 博客是全英文的,如何汉化一部分
  • 为什么管理页面上的view site 无法显示
  • 每篇文章都有tag,我该如何显示所有tag
  • 没有全局搜索
  • 如何开启https
  • 如何代码高亮显示
  • 文章目录
  • 评论模块
  • ......
    好吧,问题太多了,需要一个一个来解决

三、各种疑问解答

1. 为何选用docker

因为使用docker的好处太多了

  1. 安装简单
    如果不使用docker,可以看到要自己安装nodejs,nginx,mysql,ghost等,实际上是个很麻烦的事情
  2. 方便数据迁移
    假如有某些原因导致你想将数据迁移到别的机器上,如果使用常规安装方式,数据的迁移将会非常麻烦,使用docker的安装方式,则非常简单,只需要把数据卷挂载到宿主机的制定文件夹,到时候将数据直接打包带走即可完成无缝迁移,包括mysql的数据、博客图片等等数据
  3. 域名修改简单
    实际上ghost博客对域名的依赖性非常强,无论前端后端都有域名的使用,假如你想换一个域名,常规操作貌似不难,但是使用容器的方式也很简单,这个后续再提
  4. 管理简单
    对于我这种linux不怎么懂,但是对docker相关知识相对来说比较熟的人,使用docker这种跨平台的东西更加友好,比如使用一个命令即可看到所有启动的服务还有占用的端口号等等信息:
docker ps

2. 如何更换域名

$ docker run -d --name some-ghost -e url=http://some-ghost.example.com ghost

使用这个docker命令即可完成域名更换的事情
值得一提的是,如果不想丢失原来的数据更换域名,则要每次创建容器的时候都要指定以下上次使用的数据卷(博主为了找到这个在容器中更换域名的方法,摸索了好久),示例:

docker run -d --name some-ghost -p 3001:2368 -v /path/to/ghost/blog:/var/lib/ghost ghost:0.11-alpine

当然,使用docker命令不仅命令冗长,而且容易出错,这里推荐使用docker-compose的方式管理容器,这个之后细谈

3. 博客是全英文的,如何汉化

实际上,ghost blog提供了所有语言的支持,需要手动做汉化。。
虽然我没用过,嗯,ghost博客中有个非常重要的概念,那就是主题,它定义了一堆的模板和所有的样式,是定制博客的关键,相关文档如下:
https://docs.ghost.org/api/handlebars-themes/
我们可以把相关模板中的文件修改掉,以达到汉化的目的,比如每篇文章的标题前面都有个时间/标签的字段,默认时间是英文的,我们可以通过修改模板post.hbs变成这种样子:
2019年05月16日/博客,修改代码如下:

<time class="post-full-meta-date" datetime="{{date format="YYYY-MM-DD"}}">{{date format="YYYY年MM月DD日"}}</time>

4. view site无法显示

无法显示的问题再指定url之后就会消失

5. 如何显示所有tag

这个是个重头戏,很多人都想做一个标签分类列表,点击标签跳转到相关的列表页显示该标签下所有的文章,这个在ghost blog 2.20.1下是很容易解决的事情。首先需要说下,ghost博客中使用了特殊的模板引擎:
handlebarsjs,https://handlebarsjs.com/expressions.html
使用它可以在不同的上下文中获取很多有用的信息,包括我们现在说的标签信息
首先下载casper默认主题,并新增一个文件page-tags.hbs,内容如下:

{{!< default}}
<header class="site-header outer">
  <div class="inner">
    {{> "site-nav"}}
  </div>
</header>
{{#post}}
<main id="site-main" class="site-main outer" role="main">
  <div class="inner">
    {{#get 'tags' limit='all' include='count.posts' order='count.posts desc'}}
    {{#foreach tags}}
        <a href='{{ url }}' class="page-tag" >
         {{ name }} <small>({{ count.posts }})</small>
        </a>
    {{/foreach}}
    {{/get}}
  </div>
</main>
{{/post}}

然后修改casper文件中的package.json文件,换一个主题名字,并打包上传成为新主题
在admin后端新建page,标题就叫tags,根据路由规则,则默认的url就是http://ip:/port/tags 使用的模板优先级依次是page-tags.hbs->page.hbs->default.hbs,因为我们已经新建了最高优先级的page-tags.hbs,所以会使用它作为展示,这样就可以看到所有的tags了,当然样式可能不怎么好看,我们可以在后端的code injections中添加css代码修饰一下就好看多了

6. 没有全局搜索

ghost博客有一些去全局搜索插件,比如最有名的是jamalneufeld / ghostHunter,可惜的是在2.20.1版本中有存在的bug,导致无法使用,bug追踪:https://github.com/jamalneufeld/ghostHunter/issues/72 当这个bug解决之后ghosthunter应该就能正常使用了

7. 如何开启https

开启https需要申请证书并配置nginx,使用阿里云的域名的话能够轻松搞定,相关问题请自行百度,阿里也有官方文档告诉你怎么做,这里有个坑得注意,那就是,重定向死循环的问题,当一切准备就绪之后你会发现在访问的时候浏览器会提示重定向次数过多,然后就挂了
这个坑,论坛上有解释:https://forum.ghost.org/t/https-site-url-and-redirect-loop/3051
解决方法就是配置

proxy_set_header X-Forwarded-Proto https;

当然还有80端口重定向https的方法,自定百度吧,累了。。

8. 如何代码高亮显示

这个也是有些坑,搞了半天才整明白,其实非常简单的,请参考这个:
https://segmentfault.com/a/1190000016733871

9. 文章目录

文章目录的添加方法参考: https://jingxuetao.com/add-dictionary-to-the-ghost/

10. 评论模块

参考文章:
https://deserts.io/diy-a-comment-system/
https://hans1980775481.github.io/2018/08/27/hexo配置Valine评论系统-邮箱提醒/

四、最终解决方案

最终,我的博客使用nginx+ghost+mysql的解决方案,并使用docker-compose管理容器,编排文件如下:

version: '3.1'

services:

  ghost:
    image: ghost:2.20.1
    restart: always
    ports:
      - 2368
    environment:
      # see https://docs.ghost.org/docs/config#section-running-ghost-with-config-env-variables
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: example
      database__connection__database: ghost
      url: https://blog.kdyzm.cn
    depends_on:
      - db
    volumes:
      - ~/data/ghost:/var/lib/ghost/content
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
    volumes:
      - ~/data/mysql:/var/lib/mysql
  nginx:
    ports:
      - '80:80'
      - '443:443'
    build: ./nginx
    #image: mynginx:3.0
    restart: always
    depends_on:
      - ghost
      - db

其中,mysql不要在宿主机暴露端口号,整个宿主机只暴露80和443端口号,nginx容器由于有定制化的东西,需要新建镜像,在nginx目录下有Dockerfile文件:

FROM nginx:1.16
COPY my.conf /etc/nginx/conf.d/my.conf
COPY myhttps.conf /etc/nginx/conf.d/myhttps.conf
COPY cert /etc/nginx
EXPOSE 80 443

将http配置和https配置文件、证书等都打包进镜像。其中my.conf是80端口的重定向配置:

server {
        listen       80;
        server_name  blog.kdyzm.cn;
        location / {
           return 301 https://$server_name$request_uri;
        }

    }

myhttps.conf文件是443端口的监听配置:

server {
        listen 443 ssl;
        server_name  blog.kdyzm.cn;
                ssl_certificate   cert.pem;
                ssl_certificate_key  cert.key;
                ssl_session_timeout 5m;
                ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
                ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
                ssl_prefer_server_ciphers on;
        location / {
            proxy_pass   http://ghost:2368;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-Proto https;
            client_max_body_size  20m;
        }
    }

使用命令docker-compose up即可将三个容器在命令行模式下全部依次启动起来,访问的时候可以看到日志;
使用命令docker-compose up -d可以将三个容器在后台启动起来;
使用命令docker-compose rm可以删除三个已经停止的容器
注意:每次修改nginx相关的配置都要重新生成镜像,需要手动删除原有的镜像:docker rmi xxx

五、ghost博客没填完的坑

1. 中文输入错误问题

ghost2.20.1版本中,中文输入的时候会出现很诡异的事情
中文输入第一个字符会被识别为单个英文字符
所以使用它这个默认的富文本编辑器是没法好好输入中文的,相关问题链接参考:
Ghost-issues-9801
实际上已经有人解决了该问题,但是正式版本还没搞定,可以像我一样先使用markdown写,等新版本ghost上线之后再升级解决该问题。

2. 没有合适的search组件

之前提到过jamalneufeld / ghostHunter的全局搜索组件,但是它有bug,导致现在还无法兼容新版本的ghost,实属遗憾