折腾过 NAS 的人大概都有这个习惯:新的服务先不买云服务器,先在自己的群晖上跑起来试试。Halo 完全支持 Docker 部署,而群晖 DSM 7.2 开始把 Docker 套件改名叫了 Container Manager,界面有些变化,但用法基本一致。
这篇文章记录在群晖上部署 Halo 的完整流程,包括数据库配置、网络设置和反向代理。如果你的群晖还在用 DSM 6.x 或 7.0/7.1 的 Docker 套件,流程大同小异,可以直接参考。
一、部署前的准备
硬件要求
群晖机型没有硬性要求,有 Docker 支持即可。为了让后台访问、插件运行和图片处理等操作更稳定,建议给 Halo 预留足够的运行资源:
- 最低建议预留 2GB 可用内存(NAS 本身也要占一部分,所以总内存建议 4GB 以上)。
- 推荐 4GB+ 可用内存,后台操作和插件运行会更从容。
- 如果你的群晖配置较低,可以先减少同时运行的其他容器,后续再根据访问量调整。
需要安装的套件
打开群晖「套件中心」,先搜索并安装 Container Manager:
| 套件 | 作用 |
|---|---|
| Container Manager | Docker 容器管理(旧版叫 Docker) |

如果你只使用后面的推荐方案 A,不需要安装数据库套件。只有准备尝试方案 B(Halo 连接群晖 MariaDB 10)时,再安装以下两个套件:
| 套件 | 作用 |
|---|---|
| MariaDB 10 | 数据库服务 |
| phpMyAdmin | 数据库可视化管理工具 |
安装 phpMyAdmin 时,套件中心会提示安装 Web Station、PHP、Apache HTTP Server 等依赖,按提示确认即可;不同 DSM 或套件版本显示的依赖项可能略有差异。
二、可选:配置 MariaDB 数据库(方案 B 需要)
如果你准备使用后面的方案 A,可以跳过本节。Halo 官方 Docker Compose 文档使用 PostgreSQL 作为示例数据库;群晖 MariaDB 10 只建议在你确认 Docker 容器可以访问套件数据库后再使用。
第一步:初始化 MariaDB
打开 MariaDB 10 套件,首次运行时会提示设置 root 密码。设一个自己能记住的强密码,记录下来。这个密码不要和后面的 Halo 用户密码相同。

第二步:创建 Halo 专用数据库和用户
打开 phpMyAdmin,用 root 账户登录(用户名 root,密码是上一步设置的)。
点击顶部导航栏的「用户账户」,然后点击「新增用户账户」:

填写以下信息:
- 用户名:填
halo - 主机名:选择「任意主机」,即
%(这样数据库用户才允许来自 Docker 网络的连接,但还需要确认 MariaDB 端口本身可以被容器访问) - 密码:点击「生成」按钮随机生成一个强密码,复制下来保存好,后面 docker-compose 配置里要用
- 勾选「创建与用户同名的数据库并授予所有权限」——这一步会自动创建名为
halo的数据库,并授权给这个用户
点击「执行」完成。
三、准备部署目录
群晖的 Docker 数据需要存放在共享文件夹中。打开 File Station,进入 docker 共享文件夹(如果没有就新建一个),在里面创建一个 halo 子文件夹:
docker/
└── halo/
└──── halo2/ // 同时创建 Halo 数据目录
└──── db/ // 同时创建 PostgreSQL 数据库目录(如果使用方案 A)

右键点击 halo 文件夹 → 「属性」→ 「权限」,确保当前用户对这个文件夹有读写权限。一般默认就有,不必额外操作。
四、编写 docker-compose 配置
这里提供两种配置方案。优先使用方案 A;方案 B 需要先确认 Halo 容器能访问群晖 MariaDB 10。
方案 A:Halo + 内置 PostgreSQL 容器(推荐)
如果你懒得折腾数据库,最简单的方案是让 Docker Compose 自己拉一个 PostgreSQL 容器。Halo 和 PostgreSQL 都在 Docker 里通过内部网络通信,不依赖群晖的外部套件。
打开 Container Manager → 左侧「项目」→ 点击「新增」。项目名称填 halo,路径选择刚才创建的 /docker/halo,来源选「创建 docker-compose.yml」,在编辑框中填入:
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.25
restart: on-failure:3
depends_on:
halodb:
condition: service_healthy
networks:
halo_network:
volumes:
- ./halo2:/root/.halo2
ports:
- "8090:8090"
environment:
- JVM_OPTS=-Xmx256m -Xms256m
command:
- --spring.r2dbc.url=r2dbc:pool:postgresql://halodb/halo
- --spring.r2dbc.username=halo
- --spring.r2dbc.password=openpostgresql
- --spring.sql.init.platform=postgresql
- --halo.external-url=http://你的群晖IP:8090/
halodb:
image: postgres:15.4
restart: on-failure:3
networks:
halo_network:
volumes:
- ./db:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
environment:
- POSTGRES_PASSWORD=openpostgresql
- POSTGRES_USER=halo
- POSTGRES_DB=halo
- PGUSER=halo
networks:
halo_network:
注意:把
external-url中的你的群晖IP替换为群晖在内网的 IP 地址,比如http://192.168.1.100:8090/。这个地址不能是localhost或127.0.0.1。
方案 B:连接群晖 MariaDB 10(可选)
如果你想把数据库放在群晖套件里统一管理,可以尝试这个方案。但它依赖 MariaDB 10 套件允许 Docker 容器通过 TCP 访问。部分 DSM、MariaDB 套件或网络配置下,容器即使填写群晖内网 IP,也可能连不上数据库。
继续使用方案 B 前,先确认三件事:
- MariaDB 10 的实际监听端口,常见是
3306或3307。 halo数据库用户的主机名不是只允许localhost,需要允许来自 Docker 网络的连接。- Halo 容器所在的网络可以访问
群晖IP:数据库端口。如果这一步不通,建议直接改用方案 A。
确认可达后,可以参考下面的配置。把示例中的 192.168.1.100、3307 和密码改成你的实际值:
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.25
container_name: halo
restart: on-failure:3
networks:
halo_network:
ports:
- "8090:8090"
volumes:
- ./halo2:/root/.halo2
environment:
- JVM_OPTS=-Xmx256m -Xms256m
command:
- --spring.r2dbc.url=r2dbc:pool:mariadb://192.168.1.100:3307/halo
- --spring.r2dbc.username=halo
- --spring.r2dbc.password=你创建的halo用户密码
- --spring.sql.init.platform=mariadb
- --halo.external-url=http://192.168.1.100:8090/
networks:
halo_network:
关键点:
spring.r2dbc.url中的192.168.1.100是你群晖的内网 IP。不能写localhost或127.0.0.1——容器内部有自己的网络,localhost指向的是容器自己,不是群晖主机。- MariaDB 默认端口是
3306,但如果群晖上之前装了其他 MariaDB 版本的套件,端口可能变成了3307。在 MariaDB 10 套件设置中可以查看实际端口。 - 如果 Halo 启动日志里出现连接超时、连接被拒绝,或容器内无法访问 MariaDB 端口,不要继续反复改密码;先改用方案 A,或者再单独排查群晖 MariaDB 的远程访问、防火墙和 Docker 网络。
spring.sql.init.platform写mariadb而不是mysql。
五、启动 Halo
在 Container Manager 编辑完 docker-compose.yml 后,点击「下一步」,然后「完成」。Container Manager 会自动拉取镜像并启动容器。

首次启动需要拉取镜像,根据网络速度可能需要几分钟。可以在「容器」标签页中看到 halo 容器的状态,等它变成绿色「运行中」即可。
如果想看启动日志,在容器上右键 → 「详情」→ 「日志」标签页。
六、初始化 Halo
容器启动成功后,打开浏览器访问 http://你的群晖IP:8090,会看到 Halo 的初始化页面:

按提示设置站点名称和管理员账号密码,完成初始化后进入后台。如果初始化时填写的站点地址和你后续使用的域名或 IP 不一致,后面可以在后台的「系统设置」中修改。
完成初始化后,再访问 http://你的群晖IP:8090/console 就是 Halo 后台。访问 http://你的群晖IP:8090 是你网站的前台。
七、配置反向代理和域名访问
直接用 IP:8090 访问不太优雅,也不方便记忆。群晖自带反向代理功能,可以把域名 80/443 端口的请求转发到 Halo 的 8090。
打开「控制面板」→ 「登录门户」→ 「高级」→ 「反向代理服务器」→ 点击「新增」:

| 字段 | 值 |
|---|---|
| 来源 - 协议 | HTTPS |
| 来源 - 主机名 | 你的域名(如 blog.example.com) |
| 来源 - 端口 | 443 |
| 目的地 - 协议 | HTTP |
| 目的地 - 主机名 | localhost |
| 目的地 - 端口 | 8090 |
如果你还没有 SSL 证书,可以先去「控制面板」→ 「安全性」→ 「证书」中申请 Let's Encrypt 免费证书(需要你的域名已配置 DDNS 或指向群晖的公网 IP)。
配置好反向代理之后,别忘了回到 Halo 后台的「概览页面」中,把「外部访问地址」改为 https://你的域名。
八、日常管理
升级 Halo
- 在 Container Manager 的「项目」中,找到
halo项目,点击进入。 - 在「YAML 配置」标签页中,修改镜像版本号(比如把
halo:2.25改成你要升级到的目标版本标签)。 - 先导出备份(Halo 后台 → 系统 → 备份),然后点击「构建」重新拉取镜像并启动。
查看日志
Container Manager → 容器 → 选中 halo → 「详情」→ 「日志」。
停止和重启
在 Container Manager 的「项目」标签页,可以直接对整个项目执行「停止」和「启动」操作。也可以在「容器」标签页单独操作。
九、常见问题
Q:容器启动了但访问不了 8090 端口?
检查两点:第一,群晖的防火墙是否拦截了 8090 端口(控制面板 → 安全性 → 防火墙);第二,是否有其他服务占了 8090 端口。
Q:方案 B 中 Halo 连不上 MariaDB?
先确认 spring.r2dbc.url 里没有写 localhost 或 127.0.0.1。如果已经改成群晖内网 IP 仍然连不上,通常就不是 Halo 配置本身的问题,而是 MariaDB 10 套件的端口监听、数据库用户授权、群晖防火墙或 Docker 网络访问限制。想先把 Halo 跑起来,建议直接使用方案 A 的 PostgreSQL 容器。
Q:NAS 资源有限怎么办?
可以适当调低 JVM_OPTS,比如改成 -Xmx128m -Xms128m。这个配置下 Halo 可以运行,但在大量图片上传、搜索索引或同时启用多个插件的场景下,响应可能会慢一些。
Q:怎么让外网也能访问?
需要你的群晖能通过公网 IP 或 DDNS 访问到。可以用群晖自带的 DDNS 服务(控制面板 → 外部访问 → DDNS),然后在路由器上做 443 端口的端口转发。配合群晖反向代理和 Let's Encrypt 证书,就能实现 HTTPS 公网访问。
Q:数据存在哪?
/docker/halo/halo2/ 是 Halo 的工作目录,包含附件、插件、主题、备份文件等运行数据。文章、用户、站点配置等核心数据在数据库中:如果你用的是方案 A,数据库数据在 /docker/halo/db/ 下;如果你用的是方案 B,数据库数据由群晖 MariaDB 10 套件管理。迁移或手动备份时,需要同时处理 Halo 工作目录和对应的数据库。