平台/工具折腾血泪史
博客陆陆续续也写了有七八年了,早年在51空间、QQ 空间、人人网、点点网上写过一些矫情的文字,后来接触了比较 geek 的 GitHub Pages 方式,折腾过 Jekyll,也不断升级了好几年的 Hexo, 还试着使用了一段时间的 GitBook 作为博客使用, 该有的基本都有了,插件极其丰富,借助一些自制的脚本还算比较顺手。『现在已经不想再折腾这些工具了,专注文字本身即可。』——这句话还是上次折腾 GitBook 后写的,现在又被打脸了… 这次我纠结了良久还是彻底换为了 Hugo.
我需要/使用什么样的博客平台/工具
在回答『我需要什么样的博客平台/工具』之前先问问我们为什么要写博客,对于我个人而言,我对博客的定位有如下几点:
- 发表一些有见地的观点,如果不是原创则需要是一篇能对其他人有帮助的综述总结
- 锻炼自己的表达能力,尤其是技术方面的积累
- 分享自己一部分有趣的生活,旅行等非技术活动
- 数字世界中的个人品牌,能独立于任何平台,不用担心其它公司倒闭
能满足以上几点的可以自建诸如 Wordpress 之类的 CMS, 写作起来是非常容易的,但需要维护数据库什么的,而且在如今也显得不够 geek :) 基于 GitBook 的博客方案自己虽然也用过一阵子,自己也给 GitBook 造过几个轮子,但用下来发现和博客的风格还是有点不合,用作专题类的书籍/主题写作更为合适一些,然鹅,Gitbook 生成 PDF 的速度是真的慢,几百个文件能搞一个小时,直接被 travis 干掉了。
基于 git + markdown 几乎是最近几年程序员写博客的标配,GitHub Pages/Netlify 之类的静态页面服务器更是为部署提供了方便。目前自己的博客写作工具有如下组合拳:
- git 版本控制,记录博客历史上的任何一个时间点
- markdown 源文本,轻量级标记语言,完美适应博客写作,不需要复杂的富文本编辑器
- Hugo 静态页面引擎,性能秒杀 GitBook. 静态编译的二进制包,不用再和 node 搏斗了
- GitHub issue 作为评论系统,内容生产和反馈形成闭环
- travis/netlify 持续集成,本地专注内容创作即可,编译和部署交给 travis/netlify
- 为了大陆用户方便,使用了 DNS 分流,大陆用户路由到针对国内加速一处付费的线路
博客源文档管理
使用 markdown + git 的方案管理源文件,编辑器可以选择任意你最爱的文本编辑器,比如 Vim :) 除了使用 git 控制版本外,你也可以选择将整个博客目录置于如 Dropbox 这种同步盘中,这样就不用纠结未 commit 的草稿了,任意切换设备都可以无缝继续写作啦~ 为了保持和之前 GitBook 的目录结构一致,我写了一个脚本 blog/hugo_helper.sh 这种简单粗暴基于时间的命名方式避免了中文 URL 和拼音 URL.
静态页面引擎
在使用过诸多不同的静态页面引擎后,使用 Hugo 的感觉就一个字——爽!简直不要太快。Golang 大法好,我现在也越来越喜欢尝试使用 Golang 构建的工具了。Hugo 相对于其他静态页面引擎来说其功能还是有点丰富的,建议读读官方文档快速了解下。相比于 Hugo 刚诞生时主题的稀缺,现在的主题已经多如牛毛了,很大一部分都是从 hexo 的主题移植过来的。我选择的是一款相对较为简洁的主题 olOwOlo/hugo-theme-even, 评论方面我移植了 wzpan/comment.js
评论系统
在这之前我的博客几乎一直使用 disqus 评论系统,除了在国内响应慢一点外还算能接受,毕竟接受的账号体系多,受众更广一些。disqus 这种通用型评论系统牺牲了一部分特性,比如支持 markdown 评论,在之前迁移到 GitBook 时偶然发现原来还有基于 GitHub issue 的评论系统如 gittalk/gitment, 但这两种工具都有一个致命缺陷——侵入性太强,这都源于 GitHub 之前的鉴权粒度太粗导致,新的基于 GitHub App 的方式权限控制更细一些,但仍然会要求你授权第三方,比如 utterances 1.0 在绝望之际我偶然发现了 wzpan 的 comment.js, 花了点时间便移植到了 even 这个主题上,有兴趣使用的可以前往 billryan/hugo-theme-even 配置文件参考我的 blog/config.toml
对我移植过的 comment.js 有兴趣的可以关注新的博文,我会详细介绍配置细节。
部署
静态页面部署这一块,可复杂可简单。最简单的莫过于使用 Netlify, 可以做到比 GitHub Pages 功能更强大更方便。如果使用的是 Hugo 引擎,Netlify 是直接支持的,不确定是不是 Netlify 做了一定的识别导致我产生的这种错觉? 相较于 GitHub 往往需要自己编写 .travis.yml
文件来定制编译细节,Netlify 提供了在其网页上配置编译选项,大大简化了部署这件小事。Netlify 其他的优点可以去看官方文档,东岳的一篇博文写的也不错 Case Study: 使用 Netlify 持续集成你的静态网站 不过讽刺的是,他们现在使用的是 GitHub Pages 服务… 2333
Netlify 除了支持基本的静态页面部署外,还支持很多细节优化,如减少 js/css/图片 等体积,自定义跳转。另外实测发现现在的 Netlify 在大陆地区的访问速度要优于 GitHub Pages.
值得注意的是,GitHub Pages 和 Netlify 现在都支持自定义域名获取 let's encrypt 的免费证书了。
国内访问优化 —— 不追求极致优化的略过
众所周知的原因,国内访问很多国外资源是存在很多问题的,如果你博客的内容主要针对国内读者,如果能定向优化下就更好了。这里我采取的方案是结合 DNSPod 的 DNS 分线路路由配置国外指向 GitHub Pages, 国内其他线路则指向我最快的 VPS, 这样我的博客网站对全球不同网络都有很好的访问速度了。在这个过程中有几个问题需要解决:
- 国内外 DNS 记录分流 - DNSPod
- 分流后 VPS 也要做到持续部署 - webhook + caddy
- 分流后也要保障 HTTPS 正常访问 - let's encrypt DNS challenge
第一个问题已经说过了,DNSPod 上免费版也可以设置国内国外分流。
对于第二个问题,我们可以基于 GitHub webhook, 待 travis 编译好静态页面后推送到 gh-pages
分支,VPS 接收 webhook 事件后拉取最新静态文件更新。VPS 上我使用了 caddy 作为 web server, 它的 plugin 机制扩展起来非常方便,日常使用性能绰绰有余,又一个用 Go 写的平台工具。caddy 虽然有 http.git 插件可以配置 GitHub webhook, 但实测在文件变动时可能会出现拉取失败,所以可以自己写一个。
webhook 在 VPS 上更新网站原理也很简单,先克隆 gh-pages
分支的静态文件,然后覆盖原静态文件,网站就更新了。这里我的做法具体分为以下几步:
- 在临时目录下新建随机目录
- git clone 指定 URL 和分支到步骤 1 得到的临时目录,最大深度可以指定为 1,加快克隆速度
- 使用 rsync 镜像临时目录到原静态目录
- 删除临时目录
Go 代码及对应 systemd service:
go build webhook.go
sudo cp webhook /usr/local/bin/webhook
Caddyfile 配置可参考
yoursite.com {
proxy / http://127.0.0.1:8001 {
transparent
}
}
在配置 GitHub 上的 webhook 也是有讲究的,我们不能直接用 blog.yuanbin.me
这种域名,因为 blog.yuanbin.me
在分流时路由到了 GitHub Pages, 不在 VPS 上,所以我们需要使用单独的域名作为 VPS 对接 GitHub webhook 服务并将静态页面文件写入到指定的目录中,便于 VPS 上的 blog.yuanbin.me
使用。
第三个问题由于一般不是自购 HTTPS 证书,依赖的是 let's encrypt, 所以多了一个获取证书的步骤,好在 caddy 可以自动获取和更新 let's encrypt 证书。但实际上在 VPS 上自动更新证书时不能使用普通的 https challenge, 因为我们的域名被分流了… 国外的 VPS 拿到的域名指向是 GitHub Pages, 所以 https challenge 的请求过不来。这里我们可以选择使用 DNS challenge 模式,在使用 DNS challenge 时,需要注意自己 VPS 上的 resolv 配置,有可能需要加一个 8.8.8.8
, 否则可能会产生超时的现象导致 caddy 启动失败。考虑到开机启动 /etc/resolv.conf
中的记录可能会更新,我么可以在 /etc/resolvconf/xxx/head
中加入 nameserver 8.8.8.8
总结
基于这套工作流,我们就可以做到关注博客内容创作了,部署等尽量由自动化工具处理掉。对于之前未建过站的朋友来说,这套流程还是有些复杂的,尤其是最后的优化,建议开始玩的时候一切从简,怎么方便怎么来。