从「想搭个博客」到「Halo 跑起来」,中间隔着一个又一个坑:云服务商拦子域名、Halo 不支持路径部署、用户名必须小写、初始化页面找不到……这篇记录完整还原了整个过程,也是博客的第一篇文章。
一、为什么搭博客
程序员总想有个自己的地盘。写技术博客的理由很多:记录踩过的坑、沉淀知识、当作第二张名片。但选什么平台,是个问题。
我当时有两个方向:
我是 Java 后端,Halo 是国产头部 Java 开源项目(Spring Boot + WebFlux,Apache 系),选它等于一边写博客一边玩开源技术——这个价值只有动态方案能给。所以定了:Halo 社区版(免费版),核心功能全免费,个人博客完全够用。
二、两个关键的选型决策
决策一:数据库用 H2 还是 PostgreSQL?
官方推荐 PostgreSQL,但 H2 内嵌在 JVM 里,少一个常驻进程、省 150-250M 内存、单容器部署。我的服务器资源有限,已跑着几个业务容器,起步阶段资源紧张,H2 是最优解。
官方文档原话(可核验):
不推荐在生产环境使用默认的 H2 数据库……如果因为某些原因(如内存不足以运行独立数据库)必须要使用,建议按时备份数据。
所以我的策略:起步用 H2 省资源,开启自动备份兜底;以后数据多了、访问量大了,随时可以迁 PostgreSQL(Halo 的备份是应用层完整备份,跨库恢复就像搬家,不锁死)。
决策二:子域名还是路径?
原本想省事用路径 example.com/blog/,结果查到一个硬性事实:
Halo 官方明确不支持子路径部署——项目作者 Ryan Wang 在官方社区的原话:「不支持二级目录,文档已经明确说明」。有人试过 context-path=/myhalo,首页登录页全乱,官方直接说不行。
所以只剩一条正路:独立域名 blog.example.com。这反而更符合长期规划:功能隔离、互不干扰,将来主域名还能做成「个人导航页」。
三、踩坑记录(重点)
坑 1:云服务商拦截子域名(环境级大坑)
早就踩过:之前想用 chat.example.com 子域名挂一个内部服务面板,DNS 解析正常但 HTTPS 死活不通,反向代理日志报 NXDOMAIN / Connection reset——请求根本没到服务器,是云服务商网络层对 80/443 做域名检查,子域名即使主域名已备案也会被拦。
根因是「主体 ICP 备案 ≠ 接入备案」。所以博客要公开,得先在云服务商控制台办「新增接入」备案(免费,审核 1-2 周)。备案等待期间,先把 Halo 在服务器内部跑起来、文章写起来,公开只是最后一步。
坑 2:Halo 初始化页面「消失」了
部署完成后访问 http://localhost:8090/console,竟然跳到登录页而不是初始化页!官方文档明明说首次访问会进初始化页。
排查过程:翻了 Halo 源码(开源的好处),找到 InitializeRedirectionWebFilter——它只在请求带 Accept: text/html 时触发初始化重定向,curl 默认 */* 不触发,直接走了正常安全流程跳到登录页。用浏览器访问其实一切正常。
而真正的初始化页面在 /system/setup,不在 /console。用 curl 抓表单 + CSRF token 直接提交,完成初始化。
坑 3:用户名必须小写
提交初始化表单报 400:
The username can only be lowercase and can only contain letters, numbers, hyphens, and dots.
MyAdmin 含大写字母不合法,改为 myadmin 后一次通过。Halo 用户名规则:全小写,字母数字连字符点号。
坑 4:模拟登录时 RSA 加密踩雷
验证登录时,Halo 登录页用 jsencrypt 对密码做 RSA 加密。我提取公钥时用 tr -d '\\/' 把 base64 里的字符误删了一堆,导致服务端解不出密码,报 invalid-credential。修正为只还原 JS 转义的 \/ 后,登录成功。
四、部署配置(最终形态)
docker-compose.yaml:
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.25
container_name: halo-blog
restart: unless-stopped
volumes:
- ./halo2:/root/.halo2
ports:
- "127.0.0.1:8090:8090" # 只绑定本机,不暴露公网
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
environment:
- JVM_OPTS=-Xmx256m -Xms256m # 限制 JVM 内存
command:
- --halo.external-url=https://blog.example.com/ # 最终访问地址
几个要点:
镜像用 fit2cloud 国内源(
registry.fit2cloud.com/halo/halo),拉取快端口只绑 127.0.0.1,外部只能经反向代理访问,安全组都不用开 8090
external-url 直接配最终形态(https://blog.example.com/),以后公开时链接、SEO、站点地图全是最终域名,不用二次改
JVM 限 256m,防止挤占服务器上其他服务
五、当前状态与后续计划
✅ 已完成:
Halo 2.25 社区版部署(H2 内嵌库)
站点初始化:楠香自语,管理员 myadmin
登录验证通过,后台可访问
⏳ 待办:
云服务商「新增接入」备案(已排期,审核 1-2 周)
备案通过后:反向代理 blog.example.com + 自动 HTTPS 证书
选主题、装插件(评论、统计、SEO)
开启后台自动备份
把这篇文档作为第一篇文章发布
写在最后
搭博客这件事,技术选型只是开始。真正的坑永远在文档之外:平台限制、网络环境、命名规则……但每踩一个坑,就多一段可以写进文章的故事。这个博客的第一篇文章,就是它自己的诞生过程。
参考
Halo 官方文档:https://docs.halo.run
Halo 初始化说明:https://docs.halo.run/getting-started/setup
Halo 不支持子路径的官方答复:https://bbs.halo.run/d/6610-halo-如何添加基础路径
云服务商备案控制台:https://console.cloud.tencent.com/beian
楠香自语:我的博客诞生记
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法