缘起

家里有一台联想小主机(Intel Celeron N3450 / 3GB 内存 / 500GB 机械硬盘),刷了 iStoreOS(基于 OpenWrt 的软路由系统),通过 WiFi 接入家庭网络,平时跑着 Jellyfin 看片、还有个 Telegram 下载机器人。

这次的目标很简单:在这台小主机上搭一套自己的博客系统,能网页写作、自动发布。


第一步:摸清家底

先 SSH 上去看服务器到底装了什么、状态如何。

踩的坑:连不上

Windows 的 OpenSSH 客户端能连,但密码 zzzz. 怎么都认证失败。折腾了半天(试了 SSH_ASKPASS、ssh2 库、plink),最后发现——密码其实是 zzzz,那个句号是中文句末标点,不是密码的一部分

摸到的家底

内容
系统 iStoreOS 24.10.4(OpenWrt 衍生)
CPU Intel Celeron N3450 @ 1.10GHz,4 核
内存 3.2GB,空闲 2.7GB
磁盘 东芝 500GB 机械盘,只用了 2.3GB,空闲 99%
在跑的服务 Jellyfin(媒体)、tg-downloader(TG 机器人)、Samba、NFS、Docker

一切健康,空间充裕,可以开搞。


第二步:磁盘清理

虽然磁盘很空,还是顺手清理了一下:

  • 删了 fstab 死配置:有个指向不存在的 /dev/sda4 的挂载配置(根本没这个分区),开机时会报错
  • 清了 Docker 垃圾:4 个悬空镜像(<none>)、构建缓存
  • 碎片整理跳过:机械盘但用量极低(0.5%),碎片率≈0,整理纯磨损无收益

关于"容量识别"的澄清

当时发现 iStoreOS 后台显示 250GB,但实际是 500GB 盘。排查发现是 /proc/partitions 的显示 bug(它显示成 250GB 还自相矛盾:一个分区比整个盘还大)。用 fdisktune2fsdf 三个独立来源交叉验证,确认是 500GB 盘,sda3 有 458GiB,容量没少


第三步:博客系统——从 Zola 到 Hugo

这部分折腾最久,换了两次方案。

尝试一:Zola

先装了 Zola(Rust 写的静态站点生成器),理由是单二进制、轻量。

  • 装在 /opt/zola/,配 nginx 8888 端口发布
  • 先用自写模板,后来换 zola-paper 主题(类 Hugo Paper)
  • zola-paper 太老(2023年),跟 Zola 0.22 有兼容问题,要手动 patch feed 变量名
  • 又换成 tabi 主题(支持中文、现代简约)

尝试二:迁移到 Hugo

Zola 用下来发现主题生态太少——换了两个主题都不太满意,而且老主题兼容性问题多。最终决定迁移到 Hugo

理由:

  • 主题数量是 Zola 的几十倍,质量高、更新勤
  • 构建速度极快(毫秒级)
  • 单二进制,部署简单
  • 中文社区成熟

迁移过程:

  • 装 Hugo v0.146.0(标准版,因为 extended 版依赖 glibc,iStoreOS 是 musl 跑不了)
  • PaperMod 主题(Hugo 最火的简约主题)
  • 把现有文章转成 Hugo 的 front matter 格式(--- YAML)
  • 配自动构建钩子
  • 卸载 Zola 全部残留(释放 ~128MB)

第四步:Gitea + 自动发布

光有博客生成器不够,要实现"写完自动发布",需要版本管理 + 钩子。

装 Gitea

Docker 拉 Forgejo/gitea 镜像各种失败(Codeberg EOF、Docker Hub reset),最后改用官方二进制直装(136MB,ghfast 镜像下载):

  • 端口 3000(Web)、2222(内置 SSH,避开 dropbear 的 22)
  • 因为 gitea 拒绝 root 运行,创建了 git 用户
  • 装了 gitgit-http opkg 包
  • 配 procd 开机自启

自动发布钩子

核心机制:每次 push 到 zzzz/blog 仓库,自动触发 Hugo 构建。

p u s h p o s t - r e c e i v e h u g o b u i l d n g i n x

踩的坑:钩子"损坏"

一开始直接改了 post-receive 文件,把 Gitea 原生钩子覆盖了,Gitea 报"Git 钩子已损坏"。

正确做法(按 Gitea 文档):不改主钩子文件,把自定义脚本放进 post-receive.d/ 子目录。Gitea 原生钩子会遍历执行 .d/ 里的所有脚本。修复后警告消失。


第五步:网页编辑器(解决写作痛点)

博客和自动发布都有了,但写作体验是最大痛点:

  • Gitea 自带编辑器没有预览功能(1.22 版换 Monaco 后预览弱化了)
  • 命令行写不友好
  • 本地写又要上传

最终方案:做一个独立的网页编辑器

技术选型

调研了 GitHub/Gitea 的预览机制、各种开源编辑器组件后,选定:

  • 编辑器组件:Vditor(国人开发,中文友好,分屏+所见即所得)
  • 部署端口:8889(紧邻 8888)
  • 跨域:nginx 同源反代(免 CORS,不改 Gitea)
  • 认证:PAT 在 nginx 反代层注入(前端零暴露)

架构

V 8 d 8 i : 8 t 9 o f n p 8 r e g o 8 ( + t i s 8 n c n t 8 g h x - i r n ( e x + c e t i / o v k e / e g n ) i ) t e a G - i h a t u p e g i a o / A b P u I i l d

踩的坑:正文不能编辑

编辑器做好后,发现正文区是空的、不能编辑。用浏览器实测发现 Vditor 根本没渲染。

排查:CDN 版本号写错了——我凭印象写了 vditor@3.10.0,这个版本根本不存在,CDN 返回 404。改成真实版本 3.11.2 后正常。

还顺手加了兜底机制:CDN 挂了会自动降级成纯文本框,保证至少能编辑发布。


最终成果

服务器上的服务

服务 地址 用途
博客(对外) http://192.168.1.214:8888 Hugo + PaperMod
编辑器(写作) http://192.168.1.214:8889 Vditor 网页编辑器
Gitea http://192.168.1.214:3000 Git 仓库(账号 zzzz)
Jellyfin http://192.168.1.214:8096 媒体(原有的)

写博客的日常流程

H u g 8 o 8 8 9 8 8 8 ( 8 )

全程不用命令行。

链路验证

本文档本身就是通过这条链路发布的——在编辑器里写好,点发布,经过 nginx 反代 → Gitea API → Hugo 构建,最终呈现在你眼前。如果能看到这篇文章,说明全链路正常。✅


反思

整个过程踩了不少坑,但每个坑都有收获:

  1. 别凭印象写版本号——CDN 404 的 bug 就是这么来的,应该先查 npm registry
  2. 别直接改第三方管理的文件——Gitea 钩子警告的教训,要用它提供的扩展机制(.d/ 子目录)
  3. musl vs glibc——iStoreOS 是 musl,extended 版 Hugo 跑不了,要选标准版
  4. 国内网络现实——GitHub/Docker Hub 直连不稳,ghfast 镜像是救星

最终这套"Hugo + Gitea + Vditor 编辑器"的组合,既轻量(纯静态 + nginx,无额外运行时)又实用(网页写作、一键发布),很适合这种小主机自用的场景。