Outline + Pocket ID 自部署:国内自建知识库完整踩坑记
0. 写在前面
想在国内搞一个"数据完全自己说了算"的团队知识库,又不想年年交 SaaS 订阅费,Outline 是开源方案里体验最接近 Notion 的。但它不是开箱即用的,最典型的一点:Outline 自己没有用户系统,必须挂一个 OIDC 身份提供商才能登录。本文记录我从零把它和开源 Pocket ID 跑通的全过程,重点放在国内部署才会遇到的那几个坑。
文中域名统一用 example.com 占位:Outline 跑在 wiki.example.com,Pocket ID 跑在 id.example.com。你照抄时换成自己的域名即可。
1. 为什么不用现成 SaaS,要自建
原因就三个:
- 数据与合规:团队文档放境外 SaaS,始终有数据出境的顾虑;国内合规要求高的场景,自建把库落在自己服务器最省心。
- 长期成本:Notion/Confluence 按席位年费,人一多就是持续支出;自建一次性投入后边际成本很低。
- 可玩性:自建后数据、API、集成全在自己手里,后面接 AI、做自动化都自由。
Outline 的定位是"开源自托管的协作文档/wiki",界面和操作接近 Notion,但部署形态是容器化的后端服务,不像语雀、飞书那样点开即用。对"想掌控数据"的小团队或个人,它是甜点区。
2. 核心认知:Outline 没有用户系统,必须配 OIDC
这是第一个,也是最容易被忽略的坑。
Outline 不提供账号密码注册,它强制要求通过 OIDC(OpenID Connect)登录。换句话说,你部署 Outline 之前,得先有一个能发 OIDC 令牌的身份提供商(IdP)。
候选有 Authelia、Authentik、Keycloak、Pocket ID 等。我选 Pocket ID,理由是:
- 轻量,一个容器搞定,没有 Keycloak 那套复杂的 realm/cluster 概念;
- 原生支持 Passkey / WebAuthn,登录用指纹或系统密码,不用记密码;
- 界面新、配置少,给 OIDC client 发
client_id/client_secret的流程很直观。
顺序别搞反:先起 Pocket ID,再起 Outline。Outline 启动时就要去连 OIDC issuer,顺序反了起不来。
实际登录时,Outline 会把浏览器重定向到 Pocket ID 的授权确认页,用户点击「Sign in」后携带授权码回调 Outline。
3. 部署架构与前置条件
整体组件:
| 组件 | 作用 |
|---|---|
| Outline | 知识库主服务(3000 端口) |
| PostgreSQL | 存文档、用户、关系数据 |
| Redis | 缓存与会话 |
| 对象存储 | 存图片/附件(可选:不配 AWS_S3_* 时 Outline 默认用本地磁盘,单机足够;多实例/迁移建议上 S3 兼容的 MinIO 或云 OSS) |
| Pocket ID | OIDC 身份提供商 |
| 反向代理 | nginx/Caddy,统一收口 HTTPS |
注:Outline 不配置
AWS_S3_*时默认用本地文件系统存附件(容器storage目录挂载卷持久化),单机部署完全够用;对象存储属于生产扩展项,下文坑 5 详述。
网络拓扑:公网域名 → 反代(终止 TLS)→ 各容器。OIDC 回调必须走公网可达的 HTTPS 域名(见坑 1)。整体结构见下图:
前置清单:一个域名、一台能装 Docker 的服务器、Docker + Compose、一张通配符 HTTPS 证书(用 acme.sh 签 *.example.com 最省事)。
4. 部署顺序(先 Pocket ID,后 Outline)
4.1 Pocket ID 先行
起好 Pocket ID 后,在它的后台新建一个 OIDC 应用,拿到 client_id 和 client_secret,回调地址先填 https://wiki.example.com/auth/oidc.callback(Outline 的固定回调路径)。
4.2 Outline 部署(关键环境变量)
Outline 用环境变量配置,最核心的几条:
URL=https://wiki.example.com
DATABASE_URL=postgres://outline:密码@postgres:5432/outline
REDIS_URL=redis://redis:6379
SECRET_KEY=<32位以上随机串>
UTILS_SECRET=<32位以上随机串>
# OIDC(自动发现模式,填 issuer 即可)
OIDC_ISSUER=https://id.example.com
OIDC_CLIENT_ID=<Pocket ID 给的>
OIDC_CLIENT_SECRET=<Pocket ID 给的>
OIDC_NAME=Example SSO
# 对象存储(可选:不配则 Outline 默认用本地磁盘)
AWS_S3_ACCESS_KEY_ID=...
AWS_S3_SECRET_ACCESS_KEY=...
AWS_S3_REGION=us-east-1
AWS_S3_BUCKET_NAME=outline
AWS_S3_ENDPOINT=https://s3.example.com # MinIO 填内网地址
# 邮件
SMTP_HOST=smtp.example.com
SMTP_PORT=465
SMTP_USERNAME=...
SMTP_PASSWORD=...
SMTP_FROM_ADDRESS=no-reply@example.com
SECRET_KEY 和 UTILS_SECRET 务必用 openssl rand -hex 32 生成,且一旦生成就不要改,否则旧会话和加密字段会失效。
4.3 反向代理与 HTTPS
Outline 强制 HTTPS。nginx 里把 wiki.example.com 反代到容器 3000,并带上:
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Real-IP $remote_addr;
4.4 回填闭环
Outline 起得来后,用 Pocket ID 登录一次,确认 client_id / client_secret / 回调地址三方一致,认证闭环就通了。
Pocket ID 中为 Outline 新建 OIDC 客户端:回调地址需与 Outline 的 OIDC_CALLBACK_URI 严格一致,客户端密钥已脱敏处理。
5. 国内特有问题(踩坑重点)
坑 1:OIDC issuer 必须是公网 HTTPS 域名
Outline 校验 OIDC 配置时,issuer 填 localhost 或内网 IP 会直接失败,因为要做 HTTPS 回调和安全 cookie。issuer 一定填 https://id.example.com 这种公网可达地址。
坑 2:Passkey 注册强依赖 HTTPS + 可信域名 浏览器只在 HTTPS 且域名受信时才允许注册 Passkey。HTTP 下 Pocket ID 的"添加 Passkey"按钮点了没反应,别以为是 bug,先确认证书生效。
坑 3:Outline 强制安全 Cookie,全链必须 HTTPS 哪怕反代前面是 HTTPS、容器之间是 HTTP 也行,但浏览器到反代这段必须是 HTTPS。任何一环降级成 HTTP,登录态 cookie 不写,表现为"登录了又跳回首页"。
坑 4:redirect_uri 严格匹配
OIDC 回调地址 scheme、host、path、甚至结尾斜杠都要和 Pocket ID 里登记的一字不差。Outline 的回调是 https://wiki.example.com/auth/oidc.callback,少一个字符就报 redirect_uri mismatch。
示意:真实报错现场已修复,此图为依据典型 OIDC 报错还原,域名已脱敏。
坑 5:对象存储不是必选项,默认本地磁盘即可
很多人一上来就纠结 MinIO 还是云 OSS,其实 Outline 不配 AWS_S3_* 时默认用本地文件系统,图片/附件直接写进挂载卷,单机部署完全正常,不必额外搭存储服务。只有在两种场景才需要上 S3 兼容对象存储:一是跑多个 Outline 实例需要共享附件,二是想方便地把附件跨机迁移/备份。此时的建议:小团队用 MinIO 自建最稳(数据全在自己盘);已在用云厂商就开个私有 OSS 桶走 S3 端点。注意 AWS_S3_ENDPOINT 在 MinIO 场景填内网地址,别填公网导致内网流量绕一圈。
坑 6:邮件通知,国内云 25 端口被封 Outline 的邀请、提及通知依赖邮件。国内阿里云/腾讯云默认封 25 端口,用 25 发信必超时。解法:用支持 465(SSL)或 587(STARTTLS) 的企业邮箱,或接 Resend / SendGrid 这类邮件 API。
坑 7:实时协作 WebSocket Outline 的多人同时编辑走 Collaboration 服务的 WebSocket。nginx 反代要放开协议升级:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
漏了这两行,文档能打开但多人光标不同步。
坑 8:子路径部署
如果 Outline 不是挂在域名根(/),而是子路径,静态资源和回调路径都要相应调整,容易踩相对路径的坑。新手建议直接挂根域名,最省事。
6. 安全、备份与运维
- 数据归属:PostgreSQL 库和附件(默认在本地挂载卷,若配了对象存储则在存储桶)都在你自己服务器,随时可迁。
- 备份:定时
pg_dump导库;附件目录(或对象存储桶)定期同步到第二份存储。PG 比附件小得多,优先保证库可恢复。 - 证书:
acme.sh签的通配符证书设自动续期;容器更新用 Docker Compose 拉新镜像,更新前先备份库,出问题回滚镜像标签即可。
7. 效果与值不值得
实际用下来:登录用 Passkey,无密码、快;文档协作流畅,移动端浏览器也能看能改;数据全在自己手里。
示意:依据 Outline 知识库界面还原,集合与文档均为示例。
给谁的建议:
- 值得自建:小团队、对个人/团队数据敏感、愿意花半天折腾的人。
- 别自建:想要零运维、点开就用、不关心订阅费的人,直接上 SaaS。
8. 进阶:把知识库接进 AI(Outline API / MCP)
自建的好处是数据掌握在自己手里。Outline 在个人设置里能生成 API Token,配合社区维护的 outline-wiki-mcp 这类 MCP 服务,就能把知识库接进支持 MCP 的 AI 助手,让 AI 直接读你的文档、按你的资料回答问题,甚至自动建文档归档对话要点。
完整接入配置、连通验证和三个实战场景(基于知识库问答、对话自动归档、协作补文档)单独写了篇教程:《把 Outline 知识库接进 MCP:让 AI 直接读你的文档》。自建完本体,下一步就看这篇。
本文为脱敏示例,部署时把 example.com 换成你自己的域名即可。