先说结论:AFFiNE 真的能打,而且自部署之后,我把 Notion 里最后一篇东西迁出来,就顺手卸了。这半年我一直在找 Notion 的替代品,前提很硬性——必须支持自部署、必须有白板、必须能处理结构化数据,AFFiNE 刚好把这三样捏在一起,还提供了一个不折腾的 Docker 镜像。这篇文章会记录我完整的部署过程、踩过的坑,以及我对“能不能打”这个问题的最终判断。如果你也在考虑把笔记从 Notion 挪到自部署方案里,这篇应该能帮你省不少时间。
1. AFFiNE到底是个什么东西
1.1 三合一不是噱头,而是“反Notion”的设计
先把 AFFiNE 拆开看。它想做的是把三种能力收进同一个数据模型里:编辑文档,类似 Notion 的 page,支持标题、引用、代码块、图片、嵌套页面这些常见操作;无限白板,给用户一块自由画布,可以把文档块、图形、手写便签、连接线都拖上去;数据库,类似 Notion database,用表格、看板、日历、列表这些视图管理结构化数据。单看每一项,市面上都有独立工具做得比它成熟,但 AFFiNE 真正的点在于这三种东西不是三个孤立的模块,而是在同一个块编辑器里互通的。文档里可以直接嵌一块白板,白板上可以直接挂某个数据库视图,白板里的对象和文档里的块是同一套数据模型。这一点是它和“笔记软件加一个画图插件”这种拼凑方案的本质区别。
AFFiNE 还有一个很关键的背景:它从一开始就把自部署当作一等公民。官方直接提供 Docker 镜像,数据落在你自己的机器上。叠加完全开源的代码,想要魔改、集成、二次开发,理论上都没有什么阻碍。这一点在 Notion 身上基本是看不到的。你可以跑着独立部署的 Notion 替代方案,但 Notion 官方始终保持封闭生态。所以对于“数据控制权”有执念的人来说,AFFiNE 天然就赢在起跑线上。
1.2 为什么应该用Docker而不是去用官方云服务
用官方云服务的问题不在于功能,而在于你拥有什么。笔记数据是长期积累的数字资产,每一次输入都是在制造未来可以被检索、被再加工的信息。如果这些数据只存在于别人家的服务器,哪天服务调整、价格变动、使用政策发生变化,你就会非常被动。自部署的核心价值是数据控制权,具体到 AFFiNE 这个产品上,你能得到几个实实在在的好处:数据完全在自己的 PostgreSQL 里,备份、导出、迁移都自由;离线也能用,不受服务商网络波动影响;可以接自己的域名和证书,做成一个私有知识库;没有用户数限制,给团队用只需要考虑服务器性能。
而 Docker 是自部署最主流的载体。它把 AFFiNE 需要的运行时、依赖、环境变量都打包成标准镜像,你不需要手动配置 Node.js 环境,不需要手工装 PostgreSQL 客户端,只需要会用 docker compose 定义服务之间的关系,就能在十几分钟内把整个应用跑起来。后续升级也简单,拉一个新镜像再启动一次容器就行。
不过这里得先纠一个容易混淆的概念。标题里说“笔记+白板+数据库三合一”,很多刚接触的人会把“数据库”理解成部署时要装的那个数据库,其实完全是两码事。AFFiNE 自带的数据库视图,是应用层用来组织结构化笔记的功能,它承载的是表格、看板、日历这些面向使用者的界面;而 AFFiNE 真正跑起来依赖的 PostgreSQL 和 Redis,是存储层,一个放持久化数据,一个放缓存和临时状态。前者解决你整理信息的问题,后者解决数据放哪里、同步状态怎么维护的问题。这个逻辑先理清了,后面部署的时候看见两个数据库服务就不会懵。
2. Docker部署AFFiNE前的准备工作
2.1 前置条件:一台能稳定跑Docker的机器
部署 AFFiNE 对硬件的要求不算苛刻,但也不能太将就。官方给的建议是 2 核 4G 起步,我实际跑下来的感受是,如果只给自己用,2G 内存也能勉强跑起来,但一旦同时打开数据库视图和白板,CPU 占用会明显往上跳,切页面偶尔会出现延迟。如果你打算存很多笔记、还要做图片和附件管理,内存建议往上加。团队使用的话,4 核 8G 以上更稳妥。
操作系统优先选 Linux。Ubuntu 22.04 或者 Debian 12 这类主流发行版都行。Windows 上也可以用 Docker Desktop 跑,但生产环境我个人不建议,Docker Desktop 在 Windows 上依赖虚拟机层,性能损耗和权限问题都比较麻烦。macOS 用户用 Docker Desktop 没有问题,不过 Apple Silicon 上早期部分镜像有过兼容问题,建议拉最新的 stable 镜像,不要用太老的 tag。
Docker 本身的版本也有讲究。最好用 20.10 以上的版本,配套的 compose 插件要 V2。老版本的 docker-compose 在解析新的 yaml 语法时有各种坑,你完全没必要在环境上浪费时间。装完 Docker 之后可以先检查一下版本:
docker --version docker compose version确认两个命令都能正常输出,再继续往下走。
2.2 两种部署方式,我推荐用docker compose
网上写 AFFiNE 部署的帖子不少,常见有两条路线。第一种是最快的单容器方式,一条命令拉起来:
docker run -d -p 3010:3010 ghcr.io/toeverything/affine:stable这种方式适合第一次上手、只想看个界面的情况。但问题也很明显:老版本镜像内置了 SQLite,数据直接写在容器里,如果你不做卷映射,容器一删数据就全没了。新版官方其实更推荐把 PostgreSQL 和 Redis 单独拆出来,让 AFFiNE 连接外部数据库。这就引出了第二种路线:用 docker compose 把 AFFiNE、PostgreSQL、Redis 三个服务编排到一起。
两种方式我都试过。如果你只是想在本地体验五分钟,那直接 docker run 就好;但如果你已经确定要用它来替代 Notion,那就别图这个省事。compose 方式虽然多写几行配置,但胜在清晰——数据层独立、服务可伸缩、升级时可以控制先后顺序。尤其是数据备份和恢复的时候,数据库独立服务带来的好处会非常明显。所以我下面的步骤直接按 compose 来。
3. 用Docker Compose把AFFiNE跑起来
3.1 目录结构和compose文件
先创建工作目录:
mkdir -p /opt/affine cd /opt/affine touch docker-compose.yml下面这个 compose 文件是我实际部署时用的版本,基于官方仓库最新的 stable 镜像调整过。需要注意,AFFiNE 的镜像名和端口在不同时期有过调整,你部署的时候如果发现镜像拉不下来,一定要去官方 GitHub 仓库看一下当前的 compose 示例,以那里的最新配置为准。
services: affine: image: ghcr.io/toeverything/affine:stable container_name: affine restart: always ports: - "3010:3010" volumes: - ./data:/app/data environment: - AFFINE_SERVER_PORT=3010 - AFFINE_SERVER_HOST=0.0.0.0 - AFFINE_DB_TYPE=postgres - AFFINE_DB_HOST=affine-postgres - AFFINE_DB_PORT=5432 - AFFINE_DB_USER=affine - AFFINE_DB_PASSWORD=yourpassword - AFFINE_DB_DATABASE=affine affine-postgres: image: postgres:16-alpine container_name: affine-postgres restart: always environment: - POSTGRES_USER=affine - POSTGRES_PASSWORD=yourpassword - POSTGRES_DB=affine volumes: - ./postgres:/var/lib/postgresql/data这个文件里没有放 Redis,因为部分版本的 AFFiNE 默认对 Redis 的依赖不是强制项,主要是做缓存和协同消息中间件。如果你的使用场景里有大量实时协同、同一个 workspace 多人在线编辑,建议把 Redis 也加上:
affine-redis: image: redis:7-alpine container_name: affine-redis restart: always volumes: - ./redis:/data然后在 affine 服务的环境变量里补上:
- AFFINE_REDIS_ENABLED=true - AFFINE_REDIS_HOST=affine-redis - AFFINE_REDIS_PORT=6379有三点必须提醒。第一,AFFINE_DB_TYPE一定要设成 postgres,否则部分镜像默认走 SQLite,数据库视图和协同功能会受限。第二,restart: always建议保留,服务进程异常退出后 Docker 会自动拉起,对长期运行的自部署服务来说这是个保底的可靠性措施。第三,数据库密码不要用弱口令,尤其当你的服务器有公网 IP 时。虽然 PostgreSQL 不直接映射到宿主机端口,外部网络默认访问不到,但总有人会因为其他需求去改端口映射,一旦暴露,弱口令就是灾难。
3.2 启动、验证和日志排查
配置文件写好后,在/opt/affine目录下启动:
docker compose up -d第一次启动会拉镜像,PostgreSQL 初始化大概要十几秒到一分钟。看到所有容器都变成 up 状态后,打开http://你的服务器IP:3010就能看到注册页面了。
如果页面打不开,先看日志,这是最直接的排查入口:
docker compose logs -f affine最常见的现象是 affine 容器先起来,但 postgres 还没有初始化完,导致连接数据库失败、容器不断重启。这种情况不用着急,等 postgres 容器完全就绪后,重启一次 affine 容器就好:
docker compose restart affine另外还要提醒一个很多人忽略的问题:防火墙。很多云服务器自带安全组,系统里也可能开着 ufw 防火墙。Ubuntu 上如果启用了 ufw,要记得放行端口:
sudo ufw allow 3010/tcp这一步不做的话,本地 curl 通、外网死活打不开,非常容易让人误判成镜像或配置问题。
4. 常见问题排查与避坑经验
4.1 版本不匹配导致的白屏和登录异常
我自己踩的第一个大坑是 web 端和服务端镜像版本不一致。早期 AFFiNE 是单镜像,后来官方把服务拆成了affine-web和affine-graphql两个镜像。如果你用旧的前端去连新的后端,或者反过来,表现往往是:页面白屏、登录后一直转圈、创建工作区失败。
这类问题很难一眼发现,因为容器状态都是正常运行的,端口也在监听。排查方法就是看容器日志里有没有版本相关的报错,更直接的办法是尽量保持所有镜像的 tag 一致,比如都用stable,或者都锁定到同一个具体版本号。不要一个用 latest、一个用 stable,这种搭配最容易出问题。
我的建议是,自部署不要追新。等官方发 release 说明之后,再统一升级所有镜像。这个项目迭代速度很快,稳定运行比“用上最新特性”重要得多。
4.2 数据备份与恢复
既然要替代 Notion,数据就是命根子。我推荐两类备份配合使用。
第一类是数据库级备份,用 pg_dump 把结构化数据导出来:
docker exec -it affine-postgres pg_dump -U affine affine > affine_backup.sql恢复的时候就反向操作:
cat affine_backup.sql | docker exec -i affine-postgres psql -U affine affine第二类是文件级备份,直接备份 AFFiNE 的数据目录,里面包含附件、白板快照等二进制文件:
tar czvf affine-data-backup.tar.gz /opt/affine/data /opt/affine/postgres实际使用中建议每周做一次数据库备份,附件类文件可以低频一点。恢复备份的顺序很重要:先恢复数据库,再恢复文件,最后重启 affine 容器。顺序反了的话,AFFiNE 会因为数据不一致出现各种奇怪的同步错误。
4.3 内存和性能优化
我部署初期那台 4G 内存的服务器上,AFFiNE 整个体系(包含 PostgreSQL)常驻内存大概在 1.2G 到 1.5G 之间。如果只用 SQLite 模式,内存会低一些,但多端协同和并发能力会明显下降。如果你的服务器内存紧张,可以给容器加资源限制:
deploy: resources: limits: memory: 1G但注意,AFFiNE 本身是为协同场景设计的,内存限制太小会导致容器被 OOMKilled,表现为服务无故消失、重启后数据短暂不可用。个人使用可以给 affine 容器 1G 到 1.5G 的预算,团队使用建议不要设上限,或者直接把物理内存加到 8G 以上。
还有一个小技巧:闲置的旧 workspace 不要留着。AFFiNE 每个 workspace 都会维护一套同步状态和索引,workspace 多了之后,PostgreSQL 的 CPU 占用会明显上升。定期清理不再使用的 workspace,对性能帮助很大。
4.4 反向代理和HTTPS配置
既然做成长期使用的知识库,直接用 IP 加端口访问不太体面,也容易暴露地址。而且很多浏览器对非 HTTPS 环境的权限限制很严格,剪贴板、通知这些 API 会受影响。我建议加一层反向代理。
Caddy 是最省事的方案,它会自动申请和续期证书,配置只需要几行:
your.domain.com { reverse_proxy :3010 }如果你更习惯 Nginx,那要特别注意 WebSocket 的转发。AFFiNE 的实时协同和文档同步依赖 WebSocket,如果不把升级头转发过去,会看到一个非常诡异的症状:页面能打开,数据库内容能加载,但文档一直同步失败、多端不连通。Nginx 配置里要加上这段:
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; }5. 数据库能力实测:和Notion的差距,我实测后的结论
5.1 AFFiNE数据库能做什么
标题里写“笔记+白板+数据库三合一”,很多人最关心的是数据库能力到底有没有被夸大。我在实际使用中建过表格视图、看板视图、日历视图,基本操作体验跟 Notion 的 database 非常接近。
核心能力可以归纳成几块:创建数据库视图,支持表格、看板、日历、列表四种形态;自定义字段类型,包括文本、数字、下拉选择、日期、成员、附件等;多视图同源,切换不同视图不会影响原始数据,改任何一条记录,所有视图同步更新;筛选、排序、分组这些轻量项目管理操作都有。对于阅读清单、任务追踪、课程项目记录、团队事项管理这些场景,AFFiNE 完全够用。
但跟 Notion 对比,差距也很明显。AFFiNE 目前缺少更复杂的公式计算、跨数据库的关联视图,以及丰富的第三方数据库集成。如果你是重度 Notion 用户,靠公式做自动化和复杂计算,靠关联数据库搭信息网络,那 AFFiNE 现阶段会让你有点施展不开。但如果你只是拿数据库做轻量管理,AFFiNE 的体验已经足够顺畅。
5.2 迁移Notion数据的实操建议
AFFiNE 支持导入 Notion 导出文件,这是我敢倒腾的根本原因。实操路径是:在 Notion 后台导出 zip 包,然后在 AFFiNE 里选择导入。
迁移过程中有几个点必须提醒。第一,先导出一个小的测试页面验证流程,不要一上来就全量导入,第一次迁移大概率会碰到格式不完美的情况。第二,迁移完成后重点检查附件,部分数据库块可能变成纯文本,表格字段类型需要手动调整一遍。第三,数据库视图配置不会完整保留,数据会进来,但你已经设置好的排序、筛选、视图布局都要重新建。这不是 bug,是不同产品数据模型本身的差异,迁移成本不可避免。
如果你还在犹豫要不要完全替换 Notion,我的建议是先部署一个 AFFiNE 实例,把最近一两个月的高频笔记迁进去试用,用顺手了再决定要不要全量迁移。不要一上来就走“卸载所有”的极端路线。
5.3 谁适合换,谁不建议换
最后说我的结论。AFFiNE 适合这几类人:在意数据主权,不愿意把笔记长期放在别人服务器上;需要白板和文档结合,画架构图、做头脑风暴、做学习项目记录;想低成本拥有一个团队知识库,不想按人头付订阅费;喜欢折腾自部署,又不希望折腾得太狠,希望有个成熟方案可以直接用。
不适合换的情况也很明确:你在 Notion 生态里深度依赖公式、自动化、第三方插件,这些 AFFiNE 目前还没有完全对应;你的团队已经靠 Notion 形成了很固定的协作习惯,迁移成本大于收益;你需要在移动端高频记录,AFFiNE 的移动端目前跟 Notion 差距不小;你连一台能长期运行的机器都没有,那自部署对你来说就是额外负担。
6. 白板场景和AI能力,这些额外细节值得知道
6.1 白板到底是不是真香
我刚开始用 AFFiNE 时对白板是无感的,直到有一次我需要在文档里画系统架构图,发现以前在 Notion 里得专门把图导成图片再插进去,而在 AFFiNE 里直接新建一个白板块,画完跟文档内容无缝衔接。这个体验上的差距,用过一次就回不去了。
白板本身用的是无限画布,支持自由放置图形、手绘线条、便签、连接线,还能把文档块直接拖到画布上变成对象。最让我意外的是,你可以把数据库视图拖进白板里当作一块实时面板,白板上的图形可以和数据表关联起来。比如我在做项目规划时,左侧放数据库看板,右侧放架构图和里程碑节点,整体思路非常清晰。这种“文档、数据、图形在一个平面上横向打通”的能力,才是 AFFiNE 三合一里最值钱的部分。
6.2 把AI能力接上本地模型
AFFiNE 内置了一些 AI 功能,云版会直接提供模型服务,但自部署版本默认没有配好的模型地址。如果你愿意折腾,可以配置一个兼容 OpenAI 接口的本地模型服务,比如用 Ollama 在服务器上跑一个对话模型,然后把 AFFiNE 的 AI 服务地址指向 Ollama 的接口。这样做的意义在于:所有 AI 请求不出内网,数据不会离开自己的机器,和自部署的初衷完全一致。
我先说清楚,AFFiNE 的 AI 功能目前更多是锦上添花,比如摘要、续写、解释文字,跟深度智能体那类玩法还有距离。而且配置过程需要你对环境变量、模型名称这些概念有基本了解,并不是开箱即用。但如果你本身就在接触本地大模型的部署,那把它和 AFFiNE 接起来会是一个很有意思的组合。我实际用下来,摘要生成和文本润色这类轻量任务,本地模型完全能胜任,速度也还可以,主要是不需要额外花钱,也不会有数据出境的顾虑。
结合我自己的体会,AFFiNE 目前最大的价值不是“替代 Notion 的每一个功能”,而是给你提供了另一个维度上的选择:一个数据完全自持、文档白板数据库天然打通、还能DIY接入本地AI能力的工作台。如果你正好有一台空闲服务器,花一个下午部署起来试试,大概率不会失望。