家里那台 Beelink EQ13 买回来两年了。最初是为了 HAOS,跑在 PVE 上。顺手又起了一个 VM 把搁置多年的个人博客捡回来——继续跑 WordPress,通过 Cloudflare Tunnel 让外网能访问,当时感觉省了每个月好几美元的 VPS 费用,就很爽了。
最近开始折腾 LXC 跑 Docker 容器,冒出一个想法:要不把 WordPress 也容器化,不就少一个 VM 吗?
结果这一念之差,让我开始了一段绕远的迁移之旅,最后博客根本不在这台机器上跑了。
WordPress + Docker 这事不大对
找了一份 docker compose,MySQL、WordPress 容器、卷挂载一应俱全,看着挺完整。但是盯着挂载仔细看一眼:官方镜像的套路是起来之后把自己解压缩到挂载的卷上,整个 /var/www/html 都在卷里。那镜像有什么意义?以后升级照样是从 WordPress 自己的后台点一下,docker compose pull 根本不管事。
“正确"的做法是只挂 wp-content,核心代码留在镜像里。好,那挂哪些、留哪些,要一条一条想清楚,挂错了升级机制就坏掉。然后还要操心备份、版本兼容、SQL 注入——一个一年发不了几篇的个人博客,凭什么需要一整套动态后端?
Ghost 也看了一眼
顺手研究了一下 Ghost。专注博客和 newsletter,Node.js 写的,听起来比 WordPress 现代一截。打开官方 docker-compose 一看:Ghost 5 还能 SQLite,6.0 起强制 MySQL 8。整套自托管方案七八个服务——Ghost 本体、MySQL、ActivityPub Fediverse 集成、Tinybird Analytics……
产品力比 WordPress 强是真的,但容器化下来仍然是一坨需要运维的东西,并没有更轻松。
静态才是正确答案
Jekyll 也瞄了一眼,然后意识到:Jekyll 和 Hugo 输出都是静态 HTML,生产环境根本不需要任何进程在跑。博客这种东西,最终就是一堆 HTML 而已。
路线一下子清晰:Hugo 在本地写文章,推 GitHub,Cloudflare Pages 自动构建发布。家里那台 Beelink 一根手指都不用动。
旧文章迁过来
用 wordpress-to-hugo-exporter 导出,几百篇 Markdown 一下就出来了。HTML 没有全部转成 Markdown,所以 hugo.toml 里 markup.goldmark.renderer.unsafe = true 要开。
旧文章和新文章分开放,旧的在 content/wp/,新的在 content/posts/。两个让旧链接不死的细节:
- 每篇旧文章 frontmatter 里有导出工具带来的
url: /archives/<id>,老链接完全不变。 - 旧文章引用的图片放
static/wp-content/uploads/,文章里的图片路径一行都不用改。
两个 section 要同时出现在首页列表,需要在 hugo.toml 里告诉 PaperMod:
|
|
感觉良好
写这篇文章的方式:编辑器(任选,再也不用操心 WordPress 的编辑器了)里新建文件夹和 index.md,写完 git push。Cloudflare Pages 监控 GitHub,自动发布,很快就能访问了。
跟 WordPress 比起来,少了:
- 一个 VM
- 一个 PHP runtime
- 一个 MySQL 数据库
- 一份要操心的备份
- 一份要操心的安全更新
再见 WordPress! 想当年我入门 web 开发,好像还是从折腾 WordPress 插件开始的呢。但它终究已经不适合个人博客了。
感谢赛博活佛们。