缘起
家里有一台联想小主机(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 还自相矛盾:一个分区比整个盘还大)。用 fdisk、tune2fs、df 三个独立来源交叉验证,确认是 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用户 - 装了
git和git-httpopkg 包 - 配 procd 开机自启
自动发布钩子
核心机制:每次 push 到 zzzz/blog 仓库,自动触发 Hugo 构建。
踩的坑:钩子"损坏"
一开始直接改了 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 反代层注入(前端零暴露)
架构
踩的坑:正文不能编辑
编辑器做好后,发现正文区是空的、不能编辑。用浏览器实测发现 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 | 媒体(原有的) |
写博客的日常流程
全程不用命令行。
链路验证
本文档本身就是通过这条链路发布的——在编辑器里写好,点发布,经过 nginx 反代 → Gitea API → Hugo 构建,最终呈现在你眼前。如果能看到这篇文章,说明全链路正常。✅
反思
整个过程踩了不少坑,但每个坑都有收获:
- 别凭印象写版本号——CDN 404 的 bug 就是这么来的,应该先查 npm registry
- 别直接改第三方管理的文件——Gitea 钩子警告的教训,要用它提供的扩展机制(
.d/子目录) - musl vs glibc——iStoreOS 是 musl,extended 版 Hugo 跑不了,要选标准版
- 国内网络现实——GitHub/Docker Hub 直连不稳,ghfast 镜像是救星
最终这套"Hugo + Gitea + Vditor 编辑器"的组合,既轻量(纯静态 + nginx,无额外运行时)又实用(网页写作、一键发布),很适合这种小主机自用的场景。