四年前,当时还年轻气盛(头发茂密)的我打算开始写博客的时候,研究了一些独立博客的方案。总的来说,写博客的选择大致也就三类:
- 托管博客平台:如 CSDN,SegmentFault 和近几年比较火的 Medium;
- 静态博客系统:如 Jekyll,Hexo 和 Ghost 等;
- 动态博客系统:如 Wordpress,Typecho 和国内较火的 ZBlog 等。
托管博客平台
托管博客平台最大的优势,在于商家已经为你构建好了一个足够成熟、稳定、开箱即用的便捷的平台。不论何时何地,用 PC 或是手机登录上去,就可以开始写作了。对于博主来说,唯一需要关注的就是博客内容了。
除了这点显而易见的优势外,成熟的商业博客网站还有一些隐形的优势:
- 平台自身的权重带来的天然的 SEO 流量;
- 成熟的运营增加了文章曝光率;
- 省去了运维和折腾的工作量
而劣势也很明显。所谓寄人篱下,有苦难言,在托管平台写作的主要问题有:
- 无法满足定制化需求。不管是想定制一个代码高亮的 CSS,还是调整一下布局,都是做不到的。我有什么你就用什么,对于我这样手贱的强迫症来说实在是无法忍受的,因为我可能每次看到自己的博客都想顺手改点样式。
- 内容和平台绑定。当你不满意想换一个平台时,当初上手时候的简单就变成了导出时的痛苦,增加了迁移成本和难度。
- 平台不够稳定。小平台跑路就不说了,国内的平台普遍存在着审核问题,有时辛辛苦苦码的字被直接删掉,连回收站都找不回来,就欲哭无泪了。而国外的平台也存在着访问速度慢,甚至某天突然就连不上的悲剧。
静态博客系统
什么是静态博客
静态博客区别于动态框架,全部或绝大部分页面展示和功能的实现仅依赖前端技术,即博客的最终形式只是一些静态页面。一般说起静态博客,大家想到的首要好处就是加载速度快,阅读体验好。而相对的,对于作者来说,想要发布一篇博客就麻烦了不少。
静态博客的写作与博客平台的所见即所得的编辑方式不同,通常要遵循一些排版格式(最常见通用的就是 Markdown)。脱离了功能全面的编辑框,在插入图片,表格等操作时明显麻烦了不少。
写作完成之后,还需要使用特定的渲染引擎将文本、图片、页面模板和一些页面的功能插件,渲染生成静态页面,再发布到特定的位置。原本一气呵成的写作体验,大致被拆分成了以下几步:
- 找一个(或者魔改一个)自己喜欢的主题模板
- 找一些可靠的图床,挨个试试哪个好用
- 用 Markdown 进行写作(这一步还是挺爽的)
- 为渲染引擎搭建一个运行环境
- 渲染文章,文章多的话渲染可能比较慢
- 发布渲染后的静态资源
- 处理可能出现的图片加载失败,链接错误等一系列问题
- 修改以前的文章或发布新的文章,重复上述流程
以前年轻爱折腾(轻信了安利),觉得这样很 geek 很酷,遂入了静态博客的坑。即使加上这几年静态博客的发展,其实主流的选择也并不多。
Jekyll
Jekyll 可以算作是 Github 的亲儿子了,其渲染引擎直接由 Github 托管,文章上传后可以自动的被渲染部署发布到 Github Pages,一气呵成,非常适合对于独立域名没有执念的博主。
Jekyll 是一种轻折腾的解决方案,上手的门槛只要注册一个 Github 账号,其余的 99 步网上都有大把大把的教程。其缺点也很明显,体验与 Github 强绑定了(Github 本身的访问速度和稳定性也不太加分)。
如果你稍稍还有点别的需求,你可能还需要自己搞定:
- 一个魔改的主题
- 一个靠谱的图床
- 一堆满足你各种代码高亮显示、流程图显示、数学符号公式显示等等需求的各种 Markdown 引擎和插件
- 一堆高级的伪动态插件,如评论系统
我不确定 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 程序的理由有:
- Java Web 容器对性能要求更高一些,小鸡可能比较吃力;
- 除非你打算直接把 Tomcat 暴露成 Web 服务器,通常的方案会在前端使用 Nginx 再做一层转发,进一步降低了性能;
- 个性化需求定制门槛较高,没有 PHP 那样简单方便,所见即所得。
当然现在有了 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 阵营中,我主要考察的是 Wordpress 和 Typecho 。
Typecho 最大的宣传点是:轻量,简单,纯粹。但是网站的稳定版本好像还停留在两年前,已经很久不更新了。
去 Github 上看了一下开发分支,还算活跃,但是把开发版拉下来以后还是跑不起来,算是开箱即废。目前(2019 年底)看来主要问题有:
- 数据库连不上
- 安装完后台直接进不去
- 伪静态支持不太好
- HTTPS 好像支持不好
我花了半个小时淌了淌水,结论是:人生苦短,我用 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 备份插件成功解决了这个问题(插件的好处,你想要的基本都有,最多就是再加钱)。