Skip to content

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 端口。

Mermaid 流程图
查看源码
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 端口没有被其他进程占用:

bash
docker --version
docker compose version
ss -ltn | grep ':8090 ' || true

Linux 主机还应准备至少 1 GB 内存。公网部署前把域名解析到服务器,并决定由 Nginx、Caddy 或其他反向代理终止 TLS。Halo 不支持代理到 /blog 一类子目录,应使用独立域名或子域名。

Docker Compose 正式部署

创建目录和密码文件

以下路径适用于由管理员维护的 Linux 服务器:

bash
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 写入完整配置:

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,确认变量可解析,再拉取镜像并启动服务:

bash
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps

docker 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:18090halohalodb 均达到 healthy,健康端点返回 HTTP 200{"status":"UP"},Console 返回指向登录页的 HTTP 302,PostgreSQL 公共 schema 已创建数据表。Halo 容器强制重建后,写入 /root/.halo2 的临时标记仍然存在。

运行验证没有完成管理员初始化、测试文章和附件操作,也没有执行备份恢复、HTTPS 或版本升级。相关步骤仍需在目标服务器验收。

容器状态

bash
cd /opt/halo
docker compose ps

成功标志是 halohalodb 均处于运行状态,并在健康检查完成后显示 healthy。若 Halo 仍为 starting,等待一个检查周期后再查询。

应用响应

bash
curl -fsS http://127.0.0.1:8090/actuator/health/readiness
curl -I http://127.0.0.1:8090/console

健康端点应返回成功响应,Console 请求应得到 HTTP 响应或跳转,而不是连接拒绝或 5xx

日志和健康状态

bash
docker compose logs --tail=100 halo
docker inspect --format '{{json .State.Health}}' "$(docker compose ps -q halo)"

日志不应持续出现数据库认证失败、连接拒绝或启动异常。第二条命令显示健康检查的最近结果。

持久化

先在 Console 确认测试文章和附件存在,再只重建 Halo 容器:

bash
docker compose up -d --force-recreate --no-deps halo
docker compose ps

重新打开站点,测试文章、附件、主题和插件仍应存在。该检查验证 Halo 容器重建后的数据保留,但不能替代备份恢复演练。

日常运维

bash
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 部署,还应保存数据库级备份,避免只依赖应用内导出。下面的命令不会把密码写入命令历史:

bash
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 写入,并在隔离环境验证备份。数据库恢复轮廓如下,其中备份文件名应替换为实际文件:

bash
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 ps

pg_restore --clean 会覆盖目标数据库中的对象,只能对已确认的目标执行。恢复后登录 Console,检查文章、附件、主题和插件;应用内备份则在 Console 的“备份 -> 恢复”页面上传或选择文件,恢复完成后按页面提示重启 Halo。

升级与回滚

升级前阅读目标版本的发布说明,完成应用备份、PostgreSQL 备份和 halo2 目录归档。先记录当前镜像:

bash
cd /opt/halo
docker compose images

compose.yaml 中的 halohub/halo:2.26.1 改成经过评估的目标版本,然后执行:

bash
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,并检查数据库健康状态:

bash
docker compose ps
docker compose logs --tail=100 halodb

修改 .env 不会更改已经初始化的 PostgreSQL 用户密码。若数据库已有数据,应在 PostgreSQL 内显式修改用户密码并同步 .env;不要删除 db 目录来绕过认证问题。

浏览器无法访问 8090 端口

先从服务器本机请求健康端点,再检查监听端口和防火墙:

bash
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:

bash
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、异机备份、监控和经过演练的回滚流程。

参考资料

全部公开文章由同一个站点构建和发布。