
Halo 是我在给不太熟悉建站的朋友推荐博客程序时,经常会放进候选名单的一个:国产开源、中文文档完整、后台界面清爽,主题和插件都能直接在后台装。但它有两个地方和 PHP 类程序不一样,第一次部署很容易踩坑——它是 Java 应用,内存占用要高一些;它自带的 H2 数据库只适合体验,不适合跑正式站。本文用 Docker 完成部署,重点讲这两个坑怎么避开,以及附件、升级、备份这几件长期运维里的事。
场景 | 是否适合 |
|---|---|
个人博客、写作站 | 适合 |
团队的内容发布站 | 适合 |
需要商城、会员等复杂业务 | 建议用功能更完整的方案 |
追求极致轻量、只写纯文字 | 可考虑更轻的程序 |
它的几个特点:后台界面比较现代,操作逻辑清楚,对不熟悉建站的人友好;国产项目,中文文档完整,遇到问题社区交流没有语言障碍;插件化架构,核心保持精简,功能靠插件扩展;主题可以直接在后台安装。
需要提前知道的一点:Halo 用 Java 实现,启动后会占一块内存作为运行空间。同样 1 GB 内存的机器,跑 PHP 博客绰绰有余,跑 Halo 就比较紧张,再加上数据库基本不够用。
项目 | 最低配置 | 建议配置 |
|---|---|---|
CPU | 1 核 | 2 核 |
内存 | 1 GB | 2 GB 及以上 |
磁盘 | 20 GB | 40 GB |
内存我建议直接从 2 GB 起。 1 GB 能起来,但应用和数据库同机时会很吃紧,表现是后台操作卡顿、偶尔启动失败,排查起来还不容易第一时间想到是内存问题。
数据库:不要用 H2 跑正式站
Halo 自带 H2 内嵌数据库,不用额外部署,适合快速体验。但它不适合长期使用——数据量增长后性能和可靠性都有限,官方也建议生产环境使用外部数据库。
这个选择要在一开始就定下来。 先用 H2 跑起来、写了几十篇文章再想换,就得做数据迁移,比一开始直接上 PostgreSQL 或 MySQL 麻烦得多。本文按 PostgreSQL 部署。
前置条件是已经装好 Docker 和 Compose 插件:
docker --version
docker compose version需要放通的端口:22、80、443。
mkdir -p ~/apps/halo && cd ~/apps/halo编写 compose.yaml:
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: halo
POSTGRES_PASSWORD: 替换为强密码
POSTGRES_DB: halo
volumes:
- pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "halo"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
halo:
image: registry.fit2cloud.com/halo/halo:2.20
ports:
- "127.0.0.1:8090:8090"
volumes:
- ./halo-data:/root/.halo2
environment:
SPRING_R2DBC_URL: r2dbc:pool:postgresql://postgres:5432/halo
SPRING_R2DBC_USERNAME: halo
SPRING_R2DBC_PASSWORD: 与上面保持一致
SPRING_SQL_INIT_PLATFORM: postgresql
HALO_EXTERNAL_URL: https://blog.example.com/
TZ: Asia/Shanghai
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
volumes:
pg-data:这份配置里有四处是我刻意写成这样的:
depends_on 带了健康检查条件。 只写 depends_on 不加条件,Compose 只保证数据库容器先启动,不保证数据库已经能接受连接。Halo 启动又比较快,就会出现"数据库还在初始化,应用已经去连了"的情况,表现是首次启动失败、重启一下又好了——这种时好时坏的问题最难排查。加上 service_healthy 条件就解决了。
数据库地址写的是容器服务名 postgres。 填 localhost 一定连不上,因为在容器里它指向容器自己。
HALO_EXTERNAL_URL 必须填对外的完整地址。 它决定站点生成的链接。填错了,图片链接和跳转地址都会指向错误的位置。
镜像版本固定成具体版本号。 Halo 跨大版本升级有约束,用滚动标签的话,某次拉取镜像就可能悄悄跨了大版本,主题和插件一起不兼容。
./halo-data 存放附件、主题、插件和配置,是必须持久化的数据。
启动:
mkdir -p halo-data
docker compose up -d
docker compose ps
docker compose logs -f halo首次启动要耐心等。 要初始化数据库,Java 应用本身启动也需要一点时间。看到日志里出现启动完成的提示再访问,提前访问看到报错不代表部署失败。
先在域名服务商处添加 A 记录指向服务器公网 IP,解析生效后验证:
dig +short blog.example.com配置反向代理,以 Caddy 为例:
blog.example.com {
reverse_proxy 127.0.0.1:8090
request_body {
max_size 200MB
}
}request_body max_size 要按附件的最大体积来设。 默认值偏小,上传稍大的图片或文件会失败,而 Halo 后台只显示"上传失败",看不出是代理层拦的。
服务器位于中国内地、使用域名对外提供服务时,需要先完成 ICP 备案。
如果后来改了访问域名,要同步更新 HALO_EXTERNAL_URL 并重建容器:
docker compose down && docker compose up -d访问域名会进入初始化页面:
进后台后先处理几项:
Halo 可以直接在后台装主题和插件,比手动上传方便很多。但有一条要特别注意:跨大版本的主题和插件通常不兼容。
装主题前确认它支持你当前的 Halo 版本。装完如果站点出现异常——页面空白、样式错乱——先在后台切回默认主题,站点能恢复就说明是主题的问题。
插件常用的方向:代码高亮、搜索增强、站点地图、评论组件、附件存储对接。装完插件出现异常时,先停用最近装的那个,这是定位最快的方法。
这一项对图片多的博客很值得做。
附件存在服务器本地有两个问题:占磁盘,而且每次被访问都消耗服务器带宽。对接对象存储后,附件存在对象存储里,容量按用量计费,配合内容分发网络分发还能明显减轻带宽压力。
在对象存储控制台创建存储桶,记下名称、地域、访问域名和密钥。
权限设置要分清楚。 博客附件需要被读者公开访问,所以读权限设为公有读;但写权限必须保持私有,上传通过 Halo 用密钥完成。公有读写意味着任何人都能往你的存储桶里传文件,会被拿来放违规内容或者恶意占用空间和流量。
密钥用子账号,只授予这一个存储桶的读写权限,不要用主账号密钥。
在 Halo 后台的附件管理里添加存储策略,选 S3 兼容协议类型,填入存储桶信息。配完上传一张图测试,再去对象存储控制台确认文件确实到了存储桶——只看 Halo 后台显示上传成功是不够的,有可能还在写本地磁盘。
验证项 | 怎么验证 |
|---|---|
HTTPS 访问 |
|
后台登录 | 用初始化创建的账号登录 |
发文章 | 发一篇测试文章,前台可见 |
文章详情页 | 点开文章,渲染正常 |
附件上传 | 上传图片并插入文章,正常显示 |
大文件上传 | 上传一个接近上限的文件 |
容器状态 |
|
移动端 | 手机打开站点,排版正常 |
大文件上传这一项要专门测。 用小图测试完全暴露不出请求体大小的限制,等到真要传一张大图时才发现传不上去。
容器启动失败或反复重启
docker compose logs halo --tail 100
docker compose logs postgres --tail 50三个最常见的原因:数据库连接配置写错、数据库还没就绪应用就启动了、内存不够。内存问题用这两条确认:
free -h
docker stats --no-stream页面能打开但链接指向错误地址:HALO_EXTERNAL_URL 填错了,改完重建容器。
附件上传失败:三处都要查——代理的请求体大小限制、Halo 的附件大小配置、对接对象存储时的密钥权限。
主题装完站点异常:多半是版本不兼容,切回默认主题。
每次重启都很慢:首次启动慢是正常的,如果每次都很慢,看看内存是否吃紧。内存不够会导致频繁换页,整体都会变慢。
升级要看版本跨度
Halo 不支持跨多个大版本直接升级。我的升级流程是:
compose.yaml 里的镜像版本标签。docker compose pull 和 docker compose up -d。第 1 步不能跳。主题和插件跟不上新版本是升级后最常见的问题,提前看说明能少踩很多坑。
备份要覆盖两部分
内容 | 说明 |
|---|---|
数据库 | 文章、页面、评论、配置、用户 |
挂载目录 | 附件、主题、插件、应用配置 |
docker compose exec -T postgres \
pg_dump -U halo halo | gzip > ~/halo-db-$(date +%Y%m%d).sql.gz
tar -czf ~/halo-data-$(date +%Y%m%d).tar.gz -C ~/apps/halo halo-data附件已经放到对象存储的话,挂载目录会小很多,主要是主题和配置。
备份同步到服务器之外,并做一次恢复演练——在另一个环境用备份还原,确认文章、附件、主题设置都在。
变更前建快照:快照回滚会把整块系统盘恢复到快照时间点,之后写入的数据会被清除,运行中的实例会自动关机。回滚前先确认快照之后有没有新发布的内容。
日常维护:每周确认备份成功,关注版本和安全公告,定期清理垃圾评论,留意磁盘和内存水位。
内容方面:文章里用到的图片和引用内容要确认有权使用,转载需获得授权并标注出处;开放评论就要对评论区内容承担管理责任,建议开启审核;不发布违法违规内容。
Halo 部署好之后,日常基本就是写文章、偶尔升级。前面说的几个点——不用 H2 跑正式站、健康检查等数据库就绪、固定镜像版本、升级前看说明——做到了,后面会省心很多。
个人博客和小型内容站运行 Halo,轻量应用服务器的规格足以承载 Java 应用与数据库同机部署,套餐式计费清晰,配合快照可以在每次升级前保留一份可回退的环境。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。