从「想搭个博客」到「Halo 跑起来」,中间隔着一个又一个坑:云服务商拦子域名、Halo 不支持路径部署、用户名必须小写、初始化页面找不到……这篇记录完整还原了整个过程,也是博客的第一篇文章。

一、为什么搭博客

程序员总想有个自己的地盘。写技术博客的理由很多:记录踩过的坑、沉淀知识、当作第二张名片。但选什么平台,是个问题。

我当时有两个方向:

方案

特点

适合谁

静态博客(Hugo/Hexo)

零资源、秒开、无维护,纯写作

让博客回归文字的人

动态平台(Halo/WordPress)

有后台、有插件主题生态、可折腾

带着技术玩博客的人

我是 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/   # 最终访问地址

几个要点:

五、当前状态与后续计划

✅ 已完成:

  • Halo 2.25 社区版部署(H2 内嵌库)

  • 站点初始化:楠香自语,管理员 myadmin

  • 登录验证通过,后台可访问

⏳ 待办:

  • 云服务商「新增接入」备案(已排期,审核 1-2 周)

  • 备案通过后:反向代理 blog.example.com + 自动 HTTPS 证书

  • 选主题、装插件(评论、统计、SEO)

  • 开启后台自动备份

  • 把这篇文档作为第一篇文章发布

写在最后

搭博客这件事,技术选型只是开始。真正的坑永远在文档之外:平台限制、网络环境、命名规则……但每踩一个坑,就多一段可以写进文章的故事。这个博客的第一篇文章,就是它自己的诞生过程。

参考