SilverLining's Blog

从 Hexo 重回 Wordpress 的采坑经历

四年前,当时还年轻气盛(头发茂密)的我打算开始写博客的时候,研究了一些独立博客的方案。总的来说,写博客的选择大致也就三类:

托管博客平台

托管博客平台最大的优势,在于商家已经为你构建好了一个足够成熟、稳定、开箱即用的便捷的平台。不论何时何地,用 PC 或是手机登录上去,就可以开始写作了。对于博主来说,唯一需要关注的就是博客内容了。

除了这点显而易见的优势外,成熟的商业博客网站还有一些隐形的优势:

而劣势也很明显。所谓寄人篱下,有苦难言,在托管平台写作的主要问题有:

静态博客系统

什么是静态博客

静态博客区别于动态框架,全部或绝大部分页面展示和功能的实现仅依赖前端技术,即博客的最终形式只是一些静态页面。一般说起静态博客,大家想到的首要好处就是加载速度快,阅读体验好。而相对的,对于作者来说,想要发布一篇博客就麻烦了不少。

静态博客的写作与博客平台的所见即所得的编辑方式不同,通常要遵循一些排版格式(最常见通用的就是 Markdown)。脱离了功能全面的编辑框,在插入图片,表格等操作时明显麻烦了不少。

写作完成之后,还需要使用特定的渲染引擎将文本、图片、页面模板和一些页面的功能插件,渲染生成静态页面,再发布到特定的位置。原本一气呵成的写作体验,大致被拆分成了以下几步:

  1. 找一个(或者魔改一个)自己喜欢的主题模板
  2. 找一些可靠的图床,挨个试试哪个好用
  3. 用 Markdown 进行写作(这一步还是挺爽的)
  4. 为渲染引擎搭建一个运行环境
  5. 渲染文章,文章多的话渲染可能比较慢
  6. 发布渲染后的静态资源
  7. 处理可能出现的图片加载失败,链接错误等一系列问题
  8. 修改以前的文章或发布新的文章,重复上述流程

以前年轻爱折腾(轻信了安利),觉得这样很 geek 很酷,遂入了静态博客的坑。即使加上这几年静态博客的发展,其实主流的选择也并不多。

Jekyll

Jekyll 可以算作是 Github 的亲儿子了,其渲染引擎直接由 Github 托管,文章上传后可以自动的被渲染部署发布到 Github Pages,一气呵成,非常适合对于独立域名没有执念的博主。

Jekyll 是一种轻折腾的解决方案,上手的门槛只要注册一个 Github 账号,其余的 99 步网上都有大把大把的教程。其缺点也很明显,体验与 Github 强绑定了(Github 本身的访问速度和稳定性也不太加分)。

如果你稍稍还有点别的需求,你可能还需要自己搞定:

我不确定 Github Pages 加 Jekyll 的组合能否满足以上需求,因为我执着于独立域名,因此从一开始我就放弃了这种方案。

Hexo

既然决定了自己搭建博客系统,那么渲染引擎本身使用的门槛就显得比较重要了。相比基于 Ruby 的 Jekyll,我还是对基于 NodeJS 稍稍更乐观一些(除非你是一个 Rubyer)。

这里有一篇我曾经折腾 Hexo 的文章,大致流程可以参考,但细节可能已不具备时效性了。

刚开始,我的解决方案是用 Atom(当时 VSCode 都还没出生)写文章和 Markdown 预览,图片链接是网站目录的绝对路径,然后在自己电脑上跑:

$ hexo g && hexo d

来渲染和部署静态页面。然后把页面上传到服务器,再把图片放到服务器的固定目录。然后测试一下图片和链接。

这个过程写起来感觉轻描淡写,但其中也踩过不少坑。

Markdown 渲染引擎

如果只是标准的 Markdown 格式的文章,估计大部分引擎都能够正常工作,不用太担心。但如果不巧,你也是重度 Markdown 用户,严重依赖 Markdown 来帮你渲染各种 Mermaid Chart 、 Mathjax 数学公式等复杂的内容,那么最大的坑可能就是 Markdown 的渲染引擎本身了。

在我不断试图扩展 Markdown 的用法时,更大的能力带来了更多的 Bug 。不同的 Markdown 渲染引擎对于复杂内容的渲染行为都是不可预料的,我最后也是折腾了很久才搞定了这些奇怪的需求。

主题更新

之前的静态博客,我使用的是一个非常主流也很精致的主题:Hexo Next 。这个主题用起来很不错,我经历了两次大版本的更新,其中一次就是因为作者修改了主题的配置方式,但是有些细节没有在文档中呈现(也确实不可能所有的改动都能完全进文档),导致一些静态资源、页面模板加载失败了。

去 Github issue 逛了一圈也没有类似的反馈,只好假装自己会写前端,靠扒代码解决了。但这样的结果只能说是运气不错。如果碰到一个隐藏很深/逻辑复杂的 Bug,估计就不会这么幸运了。

评论插件

虽然博客没什么人看,但是万一真有人看了,甚至还想提问,我总得搞个评论系统吧。

Hexo Next 主题本身提供了很多评论系统插件的集成。但是悲剧在于,一开始用的多说,后来国内加强了评论系统的管理,多说宣布停止服务了。

坑的我去换了个韩国的来必利,然后发现这个网站访问不稳定。最后绕了一圈还是回到了最知名的 Discuq,稳定是稳定了,也算彻底牺牲了做评论插件的意义(国内没法访问)。

搜索插件

第二个坑是搜索插件。搜索是一个博客的最核心的功能,却也是静态博客最大的痛点。搜索插件的核心思路一般都是一样的,即发布的时候做索引,然后把索引存储到一个云数据库服务以供查询。

于是同样的悲剧发生了。我用的第一家搜索服务(不太记得名字了),免费的套餐跑路了,于是我又换到了 Algolia,又重新集成 API 加重新索引搞了一遍。

后来我想,搜索功能是博客的核心功能,然而搜索必然需要依赖数据库(不论是以何种方式提供)。既然这样,算上部署成本,运维成本和性能问题,静态博客本身是否也没有很轻量。

Hexo 性能

后来我觉得每次在本地渲染再上传有点麻烦,再加上文章数量多了些(其实也就一百来篇),稍微做点修改或者写一篇新的,渲染时间竟然高达 2 分钟,有点接受不了。因为当时的 Hexo 是全量更新机制,不知道现在有没有实现增量更新了。

因此我想,把渲染放在 Server 上完成也挺好,然后我的 512M 内存的小鸡就罢工了。我研究了半天才发现渲染失败竟然是 OOM 然后进程被杀掉了,惊讶于 NodeJS 竟然如此吃配置。

再然后我就想,这样显然不够优雅。我要优雅的发布流程,我要搞 CI/CD 。于是绕了一圈,我又回到了 Github 的主场,把文章 push 到 master 分支,然后触发 Travis CI,来自动完成渲染,最后再打包上传到我自己的 Server 的指定位置,然后触发 Server 的钩子进行部署。

当然最后一步部署没有完成,我就弃坑了。静态博客这玩意,看起来各种高大上很 Geek,但是其中的痛,谁用谁知道。

最大的坑就在于折腾浪费生命。你打开电脑准备花一个小时写一篇博客,结果发现代码高亮不好看,流程图渲染不 work,跑去改改主题配置,研究研究渲染引擎,等这篇文章发布了,可能三个小时都已经过去了。

动态博客系统

年轻大了以后,深感这样折腾太浪费生产力了。我认真思考了一番,回归到自己对于博客系统的核心需求,是能有个稳定的平台,能让我随时登陆上去就可以写作。即使偶尔想修改修改样式,也能很低成本的实现(改起来简单)。

跨平台也非常重要。对于静态博客,你至少也需要有个 Markdown 编辑器。如果你换了台电脑,还得装一下 VSCode(可能又花点时间折腾一下插件)。如果是用手机可能就更麻烦了。虽然记事本和便笺也可以用来创作,但是毕竟不是很完美的体验。这种场景下,自适应的 Web 平台就非常香了。

因此我又将目光重新投向了动态博客。

框架选择

主流的动态博客框架分为两大类:基于 PHP 的和基于其他语言的。我这么说不是为了强调 PHP 的梗,而是 PHP 的框架有着天生的优势:运行环境部署相对简单,以及语言本身门槛不高,易于维护。

我本身是用 Java 的,在调研过程中也看到了一些优秀的 Java 博客程序。但我没有选择 Java 程序的理由有:

当然现在有了 Spring Boot 这样优秀的框架,不管是开发成本还是部署成本都极大地降低了。因此我建议如果你本身是个 Javaer,又想借机深入学习一下博客系统本身的 Java 项目,这是个不错的选择,否则我不太建议这套方案(维护成本偏高)。

说回 PHP 的方案。在部署方面,LNMP(Linux + Nginx + MySQL + PHP) 的运行环境已经有了非常成熟的一键脚本,极大地降低了部署的门槛。但对于有能力独立部署的同学,我不太建议使用一键脚本,主要原因有两点:

而相对的,使用系统自带的源分别安装 Nginx,PHP 和 MySQL,后续的配置也不算太复杂,即可正确运行,带来的好处有:

可能有用的参考教程:https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-ubuntu-18-04

Wordpress VS Typecho

在 PHP 阵营中,我主要考察的是 WordpressTypecho

Typecho 最大的宣传点是:轻量,简单,纯粹。但是网站的稳定版本好像还停留在两年前,已经很久不更新了。

去 Github 上看了一下开发分支,还算活跃,但是把开发版拉下来以后还是跑不起来,算是开箱即废。目前(2019 年底)看来主要问题有:

我花了半个小时淌了淌水,结论是:人生苦短,我用 Wordpress 。仔细想想,在 PHP 7 的加持下,原本的性能优势也被缩短了。而且虽然 Wordpress 常常被贴上复杂笨重的标签,但反过来说就是扩展性好,如果需要做点小改动的需求,往往都有现成的插件或只需要几行 PHP 代码,简单高效。

个人认为,在计算机硬件飞速发展的今天,除非底层程序,否则性能都不再是决定性优势了。我现在的环境是一台 1GB 内存的机器,Wordpress 装了十个左右的插件吧,加上 Nginx 和 MySQL,实测整机常态内存也就稳定在 240MB,表现还是超出预期的(如果是 Java 可能就不止了)。

当然在迁回 Wordpress 的过程中,也踩了不少坑,下面稍稍总结一些经验。

Wordpress 安装踩坑

MySQL 设置密码

刚装完 MySQL,可能会出现 Access denied for root@localhost 之类的错误。在之前这么做是可以的:

$ sudo mysqld_safe --skip-grant-tables --skip-networking
$ mysql -u root
mysql > SET PASSWORD FOR 'root'@'local' = PASSWORD('newpass');

但是很不幸,如果你装了 MySQL 5.7 或者 MariaDB 10.4 以上的版本的时候,这个方法就没用了。

原因是对 root 用户默认启用了基于 unix_socket 的验证方式,对于这样的方式是不能直接设置密码的:https://mariadb.com/kb/en/set-password/#authentication-plugin-support

SET PASSWORD is ignored for users authenticating via unix_socket plugin

那么怎么解决呢,在官方另一篇文档中就有答案:https://mariadb.com/kb/en/authentication-from-mariadb-104/

ALTER USER root@localhost IDENTIFIED VIA mysql_native_password USING PASSWORD("verysecret");

PHP 流量转发错误,站点 Error 502

这个问题是由于从 PHP 7 开始,默认不再监听 127.0.0.1:9000 而是监听 Socket 文件了,在 PHP 自己的配置文件中可以看到:

# vi /etc/php/7.4/fpm/pool.d/www.conf
listen = /run/php/php7.4-fpm.sock

因此只需要修改 Nginx 中的代理设置即可:

location ~ \.php(\/.*)*{
    try_filesuri =404;
    fastcgi_pass   unix:/var/run/php/php-fpm.sock;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  document_rootfastcgi_script_name;
    include        fastcgi_params;
}

Nginx 伪静态设置

如果在 Wordpress 中启用了文章固定链接,可能会因为 Nginx 的伪静态设置不正确导致 404 错误。在目录下加入伪静态的 rewrite 规则即可:

location /blog/ {
    index index.php index.html;
    try_files uriuri/ /blog/index.php?$args;
}

文件上传大小限制

修改 PHP 中文件上传大小的限制,之前改了几个地方都没生效,后来发现是因为漏掉了 post_max_size 参数:

memory_limit=128M           //相当于单个脚本可调用内存大小
post_max_size=8M            //上传文件大小上限
upload_max_filesize=2M      //默认上传文件大小,这个就是 2M 的限制!
max_execution_time=30       //最大执行时间,页面等待时间
max_input_time=60           //最大上传时间?

Wordpress 设置错误的补救

如果你也和我一样悲剧的再点完提交才发现 Wordpress 中的 Site URL 和 Home 两个参数填错了,这时你就会面临一个 404 的后台页面。

好在,这可以在数据库中修正这两个参数:

SELECT * FROM wp_options WHERE option_name = 'siteurl';
SELECT * FROM wp_options WHERE option_name = 'home';

完美迁站方案

如果你也需要迁站,我的建议是不要安装 Wordpress,直接无脑导入数据库,然后把目录全部复制进来,大概率是 OK 的。

而我这次走了另一条比较曲折的路,先在新机器上安装了 Wordpress,测试了数据库和后台都正常之后,通过 Wordpress 自带的导入/导出功能导入了文章。

至此看起来都还算成功。然而当我把这些 wp-content/uploads,wp-content/themes 和 wp-content/plugins 复制过去之后,媒体库的显示一直不太正常。虽然文件已经存在了,但是好像和 wp_postmeta 这张表里的数据有关。

只能说 Wordpress 自带的导入/导出的备份方案还是太弱了。后来通过一个 Wordpress 备份插件成功解决了这个问题(插件的好处,你想要的基本都有,最多就是再加钱)。