AFFiNE 自托管部署:把知识库搬回自己的服务器
前言
以前我用 Notion,后来转到了 AFFiNE。
转的原因很简单:Notion 的数据不在我手里。哪天它改定价、改功能、甚至关停,我的笔记去哪?而且 Notion 不开源,离线体验一直是个槽点。
AFFiNE 是 AGPL 开源的,界面跟 Notion 很像但更偏向「文档 + 白板」的融合。最关键的 —— 它支持 Docker Compose 自托管,数据完全在自己服务器上。
这篇文章就是我把 AFFiNE 搬到自托管服务器上的完整记录。
其实吧,官方有一键部署的 docker-compose.yml,照着跑就行。但生产环境不是跑起来就完事了 —— 数据库密码要改、备份要配、反代要加 HTTPS、AI 功能要接 API Key。这些才是本文的重点。
系统架构:跑起来需要什么
AFFiNE 的服务栈有四层:
用户请求 → AFFiNE 前端 (Port 3010) ├── PostgreSQL 16 ← 文档、工作区等结构化数据 ├── Redis ← 会话、任务队列、实时同步 └── 文件存储 ← 用户上传的图片/附件 (Blob)PostgreSQL 是强依赖 —— 所有文档数据都存在里面。Redis 负责实时协作的 Pub / Sub。文件存储默认走本地目录,也可以接 S3。
硬件需求不算高:2 核 CPU + 2GB 内存就能跑,4GB 更从容。存储方面,基础安装占 1.5GB,实际消耗看你的文档量和上传文件。
部署:五步跑起来
第一步:拉配置
mkdir affine && cd affinewget -O docker-compose.yml https://github.com/toeverything/affine/releases/latest/download/docker-compose.ymlwget -O .env https://github.com/toeverything/affine/releases/latest/download/default.env.example第二步:改 .env
打开 .env,至少要改这几个:
DB_DATA_LOCATION=./postgresUPLOAD_LOCATION=./storageCONFIG_LOCATION=./configDB_USERNAME=affineDB_PASSWORD=改成一个强密码DB_DATABASE=affine第三步:启动
docker compose up -d等 1-2 分钟让 PostgreSQL 初始化完。
第四步:初始化管理员
访问 http://你的IP:3010/admin,创建管理员账户。
第五步:验证
# 确认三个容器都在跑docker compose ps
# 健康检查curl http://localhost:3010/api/healthz到这里,一个可用的 AFFiNE 实例就跑起来了。
但 —— 这只是「能用」,离「好用」还差几步。
加固:从能用到好用
反向代理 + HTTPS
AFFiNE 本身不处理 HTTPS,前面套一层 Nginx 或 Caddy。以 Nginx 为例:
server { listen 443 ssl http2; server_name affine.你的域名.com;
ssl_certificate /etc/ssl/certs/你的证书.pem; ssl_certificate_key /etc/ssl/private/你的密钥.key;
location / { proxy_pass http://127.0.0.1:3010; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;3 collapsed lines
proxy_set_header X-Forwarded-Proto $scheme; }}WebSocket 的 Upgrade 头必须透传,否则实时协作会挂。
权限修复
有时候文件上传会报权限错误:
sudo chown -R 1000:1000 ./postgres ./storage ./config容器里的 AFFiNE 进程跑在 UID 1000 下,宿主机目录权限不对就会写不进去。
数据库备份
PostgreSQL 的数据是你的命根子。每天自动备一份:
# 手动备份docker compose exec postgres pg_dump -U affine affine > backup_$(date +%Y%m%d).sql
# 恢复cat backup.sql | docker compose exec -T postgres psql -U affine affine自动化丢进 cron:
0 3 * * * cd /opt/affine && docker compose exec -T postgres pg_dump -U affine affine > /backup/affine_$(date +\%Y\%m\%d).sql进阶功能:AI、邮件、OAuth
启用 AI 助手
AFFiNE 内置了 AI 写作助手,需要配 API Key。在 .env 里加上:
# OpenAI 兼容接口(也可以用 DeepSeek、通义千问等)AI_PROVIDER=openaiAI_API_KEY=你的KeyAI_API_BASE=https://api.openai.com/v1 # 或者你的代理地址你有自己的 AI 代理网关的话,直接把 AI_API_BASE 指向代理地址就行,一个 Key 跑多个模型。
邮件通知(SMTP)
用于邀请成员、密码重置等:
MAILER_HOST=smtp.你的邮件服务器.comMAILER_PORT=587MAILER_USER=发件邮箱MAILER_PASSWORD=邮箱密码或授权码MAILER_SENDER=发件人地址OAuth 第三方登录
支持 Google、GitHub 等 OAuth 登录:
OAUTH_GOOGLE_CLIENT_ID=你的ClientIDOAUTH_GOOGLE_CLIENT_SECRET=你的SecretOAUTH_GITHUB_CLIENT_ID=你的ClientIDOAUTH_GITHUB_CLIENT_SECRET=你的Secret去对应的开发者平台申请 OAuth App,回调地址填 https://你的域名/oauth/callback。
升级与维护
升级流程很简单,但一定要先备份:
# 1. 停服 + 备份docker compose downdocker compose exec postgres pg_dump -U affine affine > backup_before_upgrade.sqlcp -r ./config ./config_backup_$(date +%Y%m%d)
# 2. 拉新镜像docker compose pull
# 3. 启动docker compose up -d
# 4. 看日志确认没报错docker compose logs --tail=100如果升级出了问题,回滚就是换回旧镜像 + 恢复数据库,十分钟内能搞定。
踩坑记录
PostgreSQL 连接密码问题
Neon 或某些云 PostgreSQL 的密码如果包含特殊字符,URL 直传可能报 password authentication failed。用 PGPASSWORD 环境变量或者 sed 替换 .env 中的占位符更稳。直连地址比带 -pooler 的连接池地址可靠。
端口冲突
如果服务器上已经跑了其他 PostgreSQL 或 Redis,检查 docker-compose.yml 里的端口映射,改掉冲突的就行。
文件存储空间
用户上传的图片和附件都堆在 ./storage 下。如果文档量大,建议定期巡检或者直接挂 S3 兼容存储(AFFiNE 支持 S3 作为 Blob 存储后端)。
总结
AFFiNE 自托管的核心门槛不高 ——Docker Compose 一行命令就能跑。真正花时间的是那些「跑起来之后」的事:配 HTTPS、做备份、接 AI、开 OAuth。
但做完之后,你的知识库数据就完全在自己手里了。不用操心云服务涨价、功能阉割、数据泄露。这种掌控感,说实话,是自托管最大的价值。
而且 AFFiNE 本身也在快速迭代,从 Alpha 到现在的版本,功能越来越完整。如果你已经在用 Notion 或任何云笔记,花一个下午迁移过来,值得。