Docker 部署 Halo:搭建可持久化的开源内容站点
Halo 是一套开源建站工具,可用于个人博客、知识库和内容站点。本指南部署社区版 v2.26.1,使用 Docker Compose 管理 Halo 与 PostgreSQL,并将应用工作目录和数据库数据保存在宿主机。
这套配置适合单机长期自托管,也可以作为生产部署基线;不提供高可用数据库、多节点 Halo 或对象存储。公网使用还需要域名、HTTPS 反向代理、持续备份和监控。
部署结论
| 项目 | 本文采用的值 |
|---|---|
| GitHub 地址 | halo-dev/halo |
| 官方镜像 | halohub/halo:2.26.1 |
| 项目版本 | v2.26.1 |
| 正式部署 | Docker Compose |
| 快速体验 | 不提供:正式路径依赖 PostgreSQL 和安装密码 |
| 适用范围 | 单机持久化自托管;可作为生产基线,不是高可用方案 |
| 主机架构 | 官方镜像支持多平台;具体平台以镜像标签清单为准 |
| 最低资源 | 官方建议至少 1 GB RAM,CPU 无特殊要求,推荐 SSD |
| 对外端口 | 8090:8090 |
| 持久化位置 | ./halo2 -> /root/.halo2;./db -> /var/lib/postgresql/data |
| 依赖服务 | PostgreSQL 15.4 |
| 验证范围 | Docker Desktop 29.7.2(aarch64)完成镜像拉取、双服务健康、HTTP 响应和容器重建持久化验证 |
| 部署日期 | 2026-09-08 |
Halo 需要同时保存工作目录和数据库。Compose 会等待 PostgreSQL 健康后启动应用,数据库端口只在项目内部网络开放,宿主机只暴露 Halo 的 8090 端口。
正在准备渲染...
查看源码
flowchart LR
user[浏览器] -->|HTTP 8090| halo[Halo 2.26.1]
halo -->|R2DBC 5432| db[(PostgreSQL 15.4)]
halo --> workdir[./halo2]
db --> dbdir[./db]准备环境
主机需要 Docker Engine 和 Docker Compose 插件。先确认版本,并检查 8090 端口没有被其他进程占用:
docker --version
docker compose version
ss -ltn | grep ':8090 ' || trueLinux 主机还应准备至少 1 GB 内存。公网部署前把域名解析到服务器,并决定由 Nginx、Caddy 或其他反向代理终止 TLS。Halo 不支持代理到 /blog 一类子目录,应使用独立域名或子域名。
Docker Compose 正式部署
创建目录和密码文件
以下路径适用于由管理员维护的 Linux 服务器:
sudo install -d -m 0750 /opt/halo
sudo chown "$USER":"$(id -gn)" /opt/halo
cd /opt/halo
umask 077
printf 'POSTGRES_PASSWORD=%s\n' "$(openssl rand -base64 36 | tr -d '\n')" > .env
mkdir -p halo2 db.env 包含数据库密码,不要提交到 Git、发送到聊天记录或放进公开备份索引。umask 077 会让新文件默认仅当前用户可读写。
写入 compose.yaml
在 /opt/halo/compose.yaml 写入完整配置:
services:
halo:
image: halohub/halo:2.26.1
restart: on-failure:3
depends_on:
halodb:
condition: service_healthy
networks:
- halo_network
volumes:
- ./halo2:/root/.halo2
ports:
- "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"
command:
- --spring.r2dbc.url=r2dbc:pool:postgresql://halodb/halo
- --spring.r2dbc.username=halo
- --spring.r2dbc.password=${POSTGRES_PASSWORD}
- --spring.sql.init.platform=postgresql
- --halo.external-url=http://localhost:8090/
halodb:
image: postgres:15.4
restart: on-failure:3
networks:
- halo_network
volumes:
- ./db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U halo -d halo"]
interval: 10s
timeout: 5s
retries: 5
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_USER: halo
POSTGRES_DB: halo
PGUSER: halo
networks:
halo_network:本地端口访问时保留 http://localhost:8090/。使用域名时,在启动前把 --halo.external-url 改成最终的 https://halo.example.com/;错误的外部地址会影响 Halo 生成的链接。
校验并启动
先渲染 Compose,确认变量可解析,再拉取镜像并启动服务:
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose psdocker compose config --quiet 无输出且退出码为 0 表示配置可解析。启动后,halodb 应为 healthy,Halo 在初始化完成后也应进入 healthy;首次启动需要等待数据库初始化和应用加载。
完成首次初始化
浏览器打开 http://服务器地址:8090/console。首次访问会进入初始化页面,按页面提示设置站点信息和管理员账号。公网部署应先配置域名与 HTTPS,再用最终域名完成初始化,避免外部地址与实际入口不一致。
管理员密码应使用独立的强密码。初始化完成后登录 Console,新建一篇测试文章并上传一个小附件,用于后续检查应用功能和持久化。
验证部署结果
以下命令是读者在目标服务器上的验收步骤。本次运行验证使用 Docker Desktop 29.7.2(aarch64),已拉取并启动 Halo 2.26.1 与 PostgreSQL 15.4,并将 Halo 临时绑定到 127.0.0.1:18090:halo 与 halodb 均达到 healthy,健康端点返回 HTTP 200 和 {"status":"UP"},Console 返回指向登录页的 HTTP 302,PostgreSQL 公共 schema 已创建数据表。Halo 容器强制重建后,写入 /root/.halo2 的临时标记仍然存在。
运行验证没有完成管理员初始化、测试文章和附件操作,也没有执行备份恢复、HTTPS 或版本升级。相关步骤仍需在目标服务器验收。
容器状态
cd /opt/halo
docker compose ps成功标志是 halo 和 halodb 均处于运行状态,并在健康检查完成后显示 healthy。若 Halo 仍为 starting,等待一个检查周期后再查询。
应用响应
curl -fsS http://127.0.0.1:8090/actuator/health/readiness
curl -I http://127.0.0.1:8090/console健康端点应返回成功响应,Console 请求应得到 HTTP 响应或跳转,而不是连接拒绝或 5xx。
日志和健康状态
docker compose logs --tail=100 halo
docker inspect --format '{{json .State.Health}}' "$(docker compose ps -q halo)"日志不应持续出现数据库认证失败、连接拒绝或启动异常。第二条命令显示健康检查的最近结果。
持久化
先在 Console 确认测试文章和附件存在,再只重建 Halo 容器:
docker compose up -d --force-recreate --no-deps halo
docker compose ps重新打开站点,测试文章、附件、主题和插件仍应存在。该检查验证 Halo 容器重建后的数据保留,但不能替代备份恢复演练。
日常运维
cd /opt/halo
docker compose ps
docker compose logs --tail=200 halo
docker compose restart halo
docker compose exec halo sh需要持续观察日志时再使用 docker compose logs -f halo,查看结束后按 Ctrl-C 退出,不会停止容器。
备份与恢复
Halo 2.8 及以上版本可在 Console 的“备份”页面创建完整备份。任务异步执行,状态完成后下载备份文件,并把副本保存到另一台主机或对象存储。大文件也可以上传到 /opt/halo/halo2/backups/,恢复页面会扫描该目录。
对于 PostgreSQL 部署,还应保存数据库级备份,避免只依赖应用内导出。下面的命令不会把密码写入命令历史:
cd /opt/halo
mkdir -p backups
docker compose exec -T halodb pg_dump -U halo -d halo -Fc > "backups/halo-$(date +%F).dump"
tar -C /opt/halo -czf "backups/halo-files-$(date +%F).tar.gz" halo2 compose.yaml .env
ls -lh backups/恢复前先停止 Halo 写入,并在隔离环境验证备份。数据库恢复轮廓如下,其中备份文件名应替换为实际文件:
docker compose stop halo
docker compose exec -T halodb pg_restore -U halo -d halo --clean --if-exists < backups/halo-YYYY-MM-DD.dump
docker compose start halo
docker compose pspg_restore --clean 会覆盖目标数据库中的对象,只能对已确认的目标执行。恢复后登录 Console,检查文章、附件、主题和插件;应用内备份则在 Console 的“备份 -> 恢复”页面上传或选择文件,恢复完成后按页面提示重启 Halo。
升级与回滚
升级前阅读目标版本的发布说明,完成应用备份、PostgreSQL 备份和 halo2 目录归档。先记录当前镜像:
cd /opt/halo
docker compose images把 compose.yaml 中的 halohub/halo:2.26.1 改成经过评估的目标版本,然后执行:
docker compose pull halo
docker compose up -d halo
docker compose ps
docker compose logs --tail=100 halo完成健康、登录、文章和附件检查后再清理旧镜像。若新版本执行了不兼容的数据迁移,不要只改回旧镜像;停止服务,恢复升级前的数据库与 halo2 备份,再启动原版本。未经恢复演练的降级可能造成数据结构与应用版本不匹配。
生产安全加固
- 使用 Nginx、Caddy 或 Traefik 提供 HTTPS,并将
halo.external-url设置为最终https://地址。 - 反向代理就绪后,将端口绑定改为
127.0.0.1:8090:8090,避免 Halo 端口直接暴露到公网;PostgreSQL 保持无宿主机端口映射。 - 限制
/opt/halo/.env、数据库目录和备份文件的读取权限,备份副本应加密并保存到异机位置。 - 固定 Halo 和 PostgreSQL 镜像版本,先在测试环境评估升级;不要使用会静默跨版本变化的宽泛标签。
- 为 Docker 日志配置轮转,监控磁盘、内存、容器健康状态和备份结果。Compose 单机部署不能提供主机级容灾。
- 启用管理员两步验证,停用闲置账号,并及时更新 Halo、主题和插件。
常见问题
Halo 一直等待数据库或日志显示认证失败
确认两个服务使用同一份 POSTGRES_PASSWORD,并检查数据库健康状态:
docker compose ps
docker compose logs --tail=100 halodb修改 .env 不会更改已经初始化的 PostgreSQL 用户密码。若数据库已有数据,应在 PostgreSQL 内显式修改用户密码并同步 .env;不要删除 db 目录来绕过认证问题。
浏览器无法访问 8090 端口
先从服务器本机请求健康端点,再检查监听端口和防火墙:
curl -v http://127.0.0.1:8090/actuator/health/readiness
ss -ltn | grep ':8090 '
docker compose ps本机可访问而外部不可访问,通常需要放行云安全组或主机防火墙。已经配置反向代理时,应只放行 80/443,并把 Halo 端口绑定到 127.0.0.1。
页面链接仍指向 localhost 或错误域名
检查 compose.yaml 中的 --halo.external-url。把值改成浏览器实际访问的完整地址后重建 Halo:
docker compose up -d --force-recreate --no-deps halo
docker compose logs --tail=100 halo地址需要包含协议,使用反向代理时通常是 https://域名/。
部署完成后
先完成一次应用内备份和 PostgreSQL 恢复演练,再安排自动化异机备份。公网站点应配置 HTTPS、收紧 8090 端口,并为容器健康、磁盘容量和备份任务设置告警。
总结
Halo v2.26.1 已按社区版镜像、PostgreSQL 和双目录持久化的单机方案编排。读者应在目标服务器完成容器状态、应用响应、健康日志和容器重建后的数据检查。
这套 Compose 配置保留了升级和恢复所需的数据边界,但单机部署不具备高可用能力。生产站点仍需 HTTPS、异机备份、监控和经过演练的回滚流程。