Notifo v1.3.0 Docker Compose 部署指南
Notifo 1.3.0 Docker Compose 三容器部署实测:MongoDB 与 Mailhog 配套、健康检查与管理员初始化、SMTP 集成收信验证、数据持久化、环境变量表与常见问题。
Notifo v1.3.0 Docker Compose 部署指南
目标:用一份经过实测的 docker-compose.yml,把 Notifo 1.3.0 主服务、MongoDB 与 Mailhog(本地 SMTP 模拟器)三容器拉起,完成健康检查、管理员登录、首个 App 创建与 Email 渠道收信验证。本文所有命令与回显均在 Docker Compose v2 环境实测通过(2026-10-30)。
一、环境信息
| 项目 | 内容 |
|---|---|
| 组件版本 | Notifo 1.3.0(squidex/notifo:1.3.0,截至 2026-10-30 的最新正式版) |
| 容器运行时 | Docker + Docker Compose v2(docker compose 子命令) |
| 实测宿主端口 | Notifo 8151(容器 5000)、Mailhog UI 8150(容器 8025) |
| MongoDB | mongo:5(官方文档推荐与实测配套版本,容器内 27017) |
| Mailhog | mailhog/mailhog(SMTP 1025 + Web UI 8025,仅用于测试收信) |
| 操作系统 | Linux x86_64(宿主) |
二、镜像选型说明
| 镜像 | 角色 | 选型依据 |
|---|---|---|
squidex/notifo:1.3.0 | 通知主服务(ASP.NET Core 7) | 官方唯一镜像;内部自带健康检查 curl -f http://localhost:5000/healthz(实测 docker inspect 可见该定义) |
mongo:5 | 必备存储 | Notifo 仅支持 MongoDB;官方 docker-compose 模板即使用 mongo:5,实测 1.3.0 与其兼容 |
mailhog/mailhog | SMTP 模拟器(可选) | 生产环境换成真实 SMTP/SES;测试环境用 Mailhog 在 8025 端口网页收信,验证 Email 渠道零成本 |
💡 Notifo 容器内置
dotnet-counters、dotnet-dump等诊断工具(环境变量DIAGNOSTICS__*指向/tools/),排障时可docker exec直接使用,无需换镜像。
三、前置条件
- 宿主已安装 Docker 与 Docker Compose v2;
- 端口未被占用:
8151(Notifo)、8150(Mailhog UI); - 准备工作目录
notifo/,其下将创建docker-compose.yml与data/数据目录; - 明确对外访问地址(下文以
http://192.168.1.200:8151为例),必须与浏览器实际访问地址一致,否则邮件里的跟踪/偏好链接会指向错误主机。
四、部署步骤
1)编写 docker-compose.yml
name: notifo-1-3-0-stack
services:
notifo-mongo:
image: mongo:5
volumes:
- ./data/mongo:/data/db
networks:
- notifo-net
restart: unless-stopped
notifo:
image: "squidex/notifo:1.3.0"
ports:
- "8151:5000"
environment:
- URLS__BASEURL=http://192.168.1.200:8151
- STORAGE__MONGODB__CONNECTIONSTRING=mongodb://notifo-mongo
- ASPNETCORE_URLS=http://+:5000
- IDENTITY__USERS__0__EMAIL=admin@notifo.io
- IDENTITY__USERS__0__PASSWORD=Q1w2e3r4!
- IDENTITY__ADMINCLIENTID=notifo-admin
- IDENTITY__ADMINCLIENTSECRET=q1w2e3r4
- IDENTITY__GOOGLECLIENT=
- IDENTITY__GOOGLESECRET=
- IDENTITY__GITHUBCLIENT=
- IDENTITY__GITHUBSECRET=
- IDENTITY__MICROSOFTCLIENT=
- IDENTITY__MICROSOFTSECRET=
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/healthz"]
start_period: 60s
depends_on:
- notifo-mongo
volumes:
- ./data/assets:/app/Assets
networks:
- notifo-net
restart: unless-stopped
notifo-mailhog:
image: mailhog/mailhog
ports:
- "8150:8025"
networks:
- notifo-net
restart: unless-stopped
networks:
notifo-net:
driver: bridge
ipam:
config:
- subnet: 10.89.81.0/24
要点:
URLS__BASEURL按你的实际 IP/域名修改,邮件正文与跟踪链接全部以它为前缀(实测通知接口返回的trackSeenUrl即该前缀);IDENTITY__USERS__0__*定义初始管理员(首个登录账号),IDENTITY__ADMINCLIENT*定义 OAuth client_credentials 客户端供自动化脚本使用(实测可换 token);- 邮箱渠道的 SMTP 服务器不在环境变量里配置,而是登录后在 App 的 Settings → Email integration 中按 App 配置(见步骤 4)。
2)启动与自检
docker compose up -d
docker compose ps # 等待 notifo 状态变为 Up (healthy),约 30~60 秒
curl -s http://localhost:8151/healthz
实测 /healthz 正常回显(节选):
{"entries":{"gc":{"data":{"Gen0CollectionCount":307,"HeapSizeBytes":42444368,
"WorkingSetString":"457.1 MB"},"description":"Application must consume less than 8 GB memory.",
"status":"Healthy"}},"status":"Healthy"}
3)登录管理界面并创建 App
- 浏览器打开
http://192.168.1.200:8151,用admin@notifo.io / Q1w2e3r4!登录; - Dashboard → Apps → 新建 App(如
demo),创建成功后 App 页会展示 4 把 API Key(Admin/WebManager 各两把); - 记录一把 Admin 角色的 API Key,后续 API 调用使用
X-ApiKey头携带(认证细节见《Notifo v1.3.0 API 使用详解》)。
4)配置 Email 集成(对接 Mailhog)并实测收信
- App → Settings → Integrations → 新增 SMTP 集成,填入:
host:notifo-mailhog(Compose 网络内的服务名)port:1025fromEmail:notifo@example.com,fromName:Notifo Demo
- 保存后集成状态即显示 Verified(实测:SMTP 集成即时探活);
- 通过 API 建一个用户并发布一条通知(命令见 API 篇),几秒后在 Mailhog 界面
http://192.168.1.200:8150应看到主题为 Your notifications from demo 的摘要邮件——这就是 Notifo 的邮件摘要(digest)机制在工作,实测正文逐条列出通知标题与内容,并附「更改邮件偏好」链接(指向$URLS__BASEURL/api/email-preferences?...)。
⚠️ 若通知列表里 Email 渠道状态为 Skipped,且系统日志出现
EMAIL: Cannot find template 'Unnamed'.,说明该通知发布时 Email 集成尚未启用或模板缺失——先完成本步再发布即可(实测复现过该报错)。
五、数据持久化说明
| 数据 | 容器内路径 | 宿主挂载 | 说明 |
|---|---|---|---|
| MongoDB 全部业务数据 | /data/db | ./data/mongo | App/用户/订阅/通知/模板/日志全在这里,库名默认 Notifications |
| 资源文件(Assets) | /app/Assets | ./data/assets | 通知图片等媒体资源,默认 assetStore 类型为 Folder |
备份策略(实测可用):
# 备份:逻辑导出 Mongo + 打包 assets
docker exec notifo-1-3-0-stack-notifo-mongo-1 mongodump --archive --gzip > notifo-mongo-$(date +%F).archive.gz
tar czf notifo-assets-$(date +%F).tgz data/assets
# 恢复:空库导入后重启主服务
docker exec -i notifo-1-3-0-stack-notifo-mongo-1 mongorestore --archive --gzip < notifo-mongo-2026-10-30.archive.gz
六、环境变量表
| 环境变量 | 示例值 | 说明 |
|---|---|---|
URLS__BASEURL | http://192.168.1.200:8151 | 对外访问地址,邮件链接/跟踪 URL 的前缀,必改 |
URLS__CALLBACKURL | 空 | Webhook 回调地址覆盖(一般留空) |
STORAGE__MONGODB__CONNECTIONSTRING | mongodb://notifo-mongo | Mongo 连接串,服务名即主机名 |
STORAGE__MONGODB__DATABASENAME | 未设(默认 Notifications) | 自定义库名(实测默认库名) |
ASPNETCORE_URLS | http://+:5000 | Kestrel 监听地址,配合端口映射使用 |
IDENTITY__USERS__0__EMAIL | admin@notifo.io | 初始管理员邮箱(序号 0 可扩展多个初始用户) |
IDENTITY__USERS__0__PASSWORD | Q1w2e3r4! | 初始管理员密码,上线必须更换 |
IDENTITY__ADMINCLIENTID | notifo-admin | OAuth client_credentials 客户端 ID(自动化用) |
IDENTITY__ADMINCLIENTSECRET | q1w2e3r4 | 对应密钥,实测可经 /connect/token 换取 Bearer token |
IDENTITY__GITHUBCLIENT/SECRET | 空 | GitHub 登录 OAuth 凭据(不填则隐藏该登录方式) |
IDENTITY__GOOGLECLIENT/SECRET | 空 | Google 登录 OAuth 凭据 |
IDENTITY__MICROSOFTCLIENT/SECRET | 空 | Microsoft 登录 OAuth 凭据 |
💡 双下划线
__是 .NET 配置的层级分隔符:IDENTITY__USERS__0__EMAIL对应 appsettings.json 里的identity:users[0]:email。全部参数的取值与默认值详见《Notifo v1.3.0 配置参数详解》。
七、配置参数说明
本文只覆盖部署必需的环境变量。Notifo 的完整配置体系(存储、消息队列、资产存储、Web Push VAPID、诊断、日志、SignalR 等)见《Notifo v1.3.0 配置参数详解》,其中包含官方 appsettings.json 的逐组解读与按场景推荐。
八、配置文件挂载
Notifo 的配置除了环境变量,还可以用 .NET 标准的 JSON 覆盖文件:
volumes:
- ./data/assets:/app/Assets
- ./appsettings.Production.json:/app/appsettings.Production.json:ro
覆盖优先级:环境变量 > appsettings.Production.json > appsettings.json(镜像内置)。适合把不常改动的大块配置(如 assetStore、logging)固化成文件、敏感项留给环境变量的混合做法。媒体资源目录 /app/Assets 对应 assetStore:folder:path 的默认值,换其他资产后端(如 Mongo GridFS、S3)时该挂载可去掉。
九、等价 docker run
不使用 Compose 时的等价命令(先建网络):
docker network create notifo-net
docker run -d --name notifo-mongo --network notifo-net \
-v "$PWD/data/mongo:/data/db" mongo:5
docker run -d --name notifo --network notifo-net \
-p 8151:5000 \
-e URLS__BASEURL=http://192.168.1.200:8151 \
-e STORAGE__MONGODB__CONNECTIONSTRING=mongodb://notifo-mongo \
-e ASPNETCORE_URLS=http://+:5000 \
-e IDENTITY__USERS__0__EMAIL=admin@notifo.io \
-e IDENTITY__USERS__0__PASSWORD='Q1w2e3r4!' \
-e IDENTITY__ADMINCLIENTID=notifo-admin \
-e IDENTITY__ADMINCLIENTSECRET=q1w2e3r4 \
-v "$PWD/data/assets:/app/Assets" \
--restart unless-stopped \
squidex/notifo:1.3.0
docker run -d --name notifo-mailhog --network notifo-net \
-p 8150:8025 --restart unless-stopped mailhog/mailhog
十、常用运维命令
# 健康与服务状态
docker compose ps
curl -s http://localhost:8151/healthz | python3 -m json.tool
curl -s http://localhost:8151/ping # 轻量探活
# 日志
docker compose logs -f notifo # 主服务日志(Kestrel 输出)
# App 级投递日志在 Dashboard 的 Logs 页,或 API:GET /api/apps/{appId}/logs
# Mongo 直查(排障利器,实测库名 Notifications)
docker exec notifo-1-3-0-stack-notifo-mongo-1 mongosh --quiet \
--eval 'db.getSiblingDB("Notifications").getCollectionNames().join(",")'
# 版本升级(1.3.0 已是最新正式版;未来出新版时)
# 1) 编辑 docker-compose.yml:把 image 行改为 Releases 公告的新 tag
# 2) 拉取新镜像并重建服务
docker compose pull notifo && docker compose up -d notifo
# 彻底移除(含数据卷,谨慎)
docker compose down -v
十一、常见问题(FAQ)
Q1:容器一直 unhealthy 或重启?
启动期 60 秒内属正常(start_period: 60s,Mongo 就绪后主服务才开始迁移)。超过 2 分钟仍 unhealthy 时先看 docker compose logs notifo,最常见原因是 Mongo 连接串主机名写错或 8151 端口冲突。
Q2:API 调用一直 401?
Notifo 的 API Key 认证使用 X-ApiKey 请求头,而不是 Authorization: Bearer。实测把 App API Key 放进 Bearer 会稳定返回 401;Bearer 只用于 OAuth client_credentials 换来的 token(详见 API 篇认证一节)。
Q3:邮件渠道显示 Skipped,Mailhog 没收到信?
两种实测复现过的原因:① 发布通知时 Email 集成还没配置/未启用;② 无模板且未携带 preformatted 文本,日志报 EMAIL: Cannot find template 'Unnamed'.。先配置 SMTP 集成再发布,或发布时带 preformatted.subject/body。
Q4:邮件里的链接指向错误地址?
URLS__BASEURL 与实际访问地址不一致所致。实测跟踪链接(/api/tracking/...)与邮件偏好链接(/api/email-preferences?...)都直接拼接 BASEURL,改完环境变量需重建容器生效。
Q5:发布接口返回 204 但用户没收到通知?
先查该 App 的系统日志:若记录 Event has no subscriber.,说明主题没有匹配的订阅者——确认用户订阅的主题前缀与发布主题一致(实测订阅与发布均返回 204 空体,成败只能靠列表/日志确认)。
Q6:多实例部署要注意什么?
需要同时配置 Redis clustering(clustering:type=Redis)、SignalR sticky session(或 web:signalR:sticky=true)以及外部消息队列(messaging:type 改 Kafka/RabbitMQ/PubSub),单机默认的 Scheduler 模式不支持多副本竞争。