1. 为什么每个开发者都该搞懂 AGPL-3.0
如果你平时只是写写业务代码、调调接口,可能觉得开源许可证离你很远。但只要你的项目用到了第三方组件,或者你打算把自己的工具开源出去,许可证就是绕不开的一道坎。我见过太多团队在选型时只看功能不看协议,结果产品上线半年后收到律师函,被迫要么开源全部代码,要么重新造轮子。这种代价,远比一开始花半小时读懂协议要大得多。
AGPL-3.0,全称 GNU Affero General Public License version 3,是 GPL 家族里约束力最强的一个变种。它和普通 GPL 最大的区别在于:它把“分发”这个触发条件扩展到了“通过网络提供服务”。什么意思?你基于一个 AGPL 组件搭了个网站或者 SaaS 服务,哪怕你没有把二进制文件发给任何人,只要用户能通过网络跟你的服务交互,你就必须把完整的对应源码提供给这些用户。这一条直接把很多想“偷偷用、悄悄改、闷声发财”的路给堵死了。
这篇文章适合三类人看:第一类是做技术选型的架构师,需要判断某个 AGPL 组件能不能进自己的商业产品;第二类是把开源项目当副业或者主业的独立开发者,想搞清楚自己选的协议到底意味着什么;第三类是对开源合规感兴趣、想系统补一下许可证知识的技术管理者。我会从协议的核心条款讲起,拆解它和 GPL、LGPL、MIT 这些常见协议的差异,然后重点讲商用场景下怎么判断风险、怎么规避、怎么合规,最后给出一套可以直接照着走的检查清单。
2. AGPL-3.0 的核心条款拆解
2.1 网络交互即触发分发义务
普通 GPL 的触发点是“分发”(distribution)。你把编译好的程序拷贝给别人,或者放到应用商店让人下载,这才算分发,才需要提供源码。但 AGPL 加了一条第 13 条,专门针对网络服务场景:如果用户通过网络与你的程序交互,你有义务向该用户提供获取对应源码的机会。
这条规定的立法意图很明确。当年 MySQL 之类的数据库以 GPL 发布,很多云厂商拿过去改一改就做成托管数据库卖钱,代码改动完全闭源,社区一点好处都拿不到。AGPL 就是为了堵这个漏洞而生的。所以你可以这样理解:GPL 管的是“发软件”,AGPL 管的是“发服务”。
实际判断时有个简单的标准:用户能不能通过网络跟你的系统产生交互?如果能,而且你的系统里链接了 AGPL 代码,那你就要提供源码。注意这里说的是“链接”(link),不是“参考”或者“借鉴”。如果你只是读了 AGPL 项目的源码,然后自己从头写了一个功能类似的模块,那不算衍生作品,不受 AGPL 约束。但如果你直接 import 了它的库、调用了它的函数、或者把它编译进了你的二进制,那就是衍生作品。
2.2 衍生作品与独立进程的边界
这是实操中最容易踩坑的地方。很多人以为“我把 AGPL 组件单独部署成一个微服务,通过 HTTP 调用它,那我的主业务就不算衍生作品了吧?”这个理解在大多数情况下是对的,但有几个前提条件必须同时满足。
第一,你的主业务和 AGPL 服务之间必须是进程隔离的,不能共享内存空间,不能动态链接同一个库。第二,两者之间的通信必须是标准的网络协议,比如 HTTP、gRPC、消息队列,而不是某种私有的、紧耦合的 IPC 机制。第三,你分发的产物里不能包含 AGPL 代码的副本。满足这三条,通常可以认为你的主业务是独立作品,不受 AGPL 传染。
但这里有个灰色地带:如果你把 AGPL 组件和你的代码打包进同一个 Docker 镜像,然后把这个镜像分发出去,那整个镜像就可能被视为一个衍生作品。因为镜像是一个整体分发单元,里面的组件在同一个文件系统里,边界变得模糊。我个人的做法是,如果非要用 AGPL 组件,一定把它拆成独立的容器,通过明确的网络接口调用,并且在文档里写清楚这个组件的协议和源码获取方式。
2.3 源码提供的具体要求
AGPL 要求提供的“对应源码”(Corresponding Source)范围比很多人想象的要广。它不仅包括程序本身的源代码,还包括构建、安装、运行所需的脚本和配置文件,以及修改过的版本所基于的原始版本的信息。换句话说,你不能只丢一个 GitHub 链接就完事,你得确保用户能拿到完整可构建的代码。
具体来说,如果你修改了 AGPL 代码,你必须在修改后的文件里保留原有的版权声明,并且明确标注你改了哪里、什么时候改的。如果你在界面上提供了源码下载入口,这个入口必须足够显眼,不能藏在三层菜单底下。我见过一个案例,某公司把源码链接放在页脚的“法律信息”里,结果被社区投诉,最后不得不把链接挪到主导航栏。
还有一个细节:AGPL 允许你通过“书面报价”的方式提供源码,也就是用户提出请求后你再给。但在网络服务场景下,更稳妥的做法是直接提供一个可下载的链接,因为第 13 条明确说“提供从网络服务器下载对应源码的机会”。你让用户发邮件申请,虽然理论上可行,但实操中容易被认为不够“opportunity”。
3. AGPL 与其他主流许可证的对比选型
3.1 一张表看清六种常见协议的差异
选许可证本质上是在“保护社区利益”和“方便商业使用”之间找平衡。下面这张表是我自己在做技术选型时常用的对照工具,把几个关键维度拉出来横向比较。
| 许可证 | 是否要求开源衍生作品 | 网络服务是否触发 | 是否允许闭源商用 | 是否要求保留版权声明 | 专利授权条款 |
|---|---|---|---|---|---|
| MIT | 否 | 否 | 是 | 是 | 无明确条款 |
| Apache-2.0 | 否 | 否 | 是 | 是 | 有明确授权 |
| LGPL-3.0 | 仅库的修改 | 否 | 是(动态链接) | 是 | 有明确授权 |
| GPL-3.0 | 是 | 否 | 是(但需开源) | 是 | 有明确授权 |
| AGPL-3.0 | 是 | 是 | 是(但需开源) | 是 | 有明确授权 |
| SSPL | 是 | 是(更宽泛) | 受限 | 是 | 无 |
从这张表能看出来,AGPL 在“要求开源”这一列上是最严格的之一。SSPL 是 MongoDB 后来自己搞的,比 AGPL 还要激进,但因为它不是 OSI 认证的开源协议,很多社区不认,所以这里不展开。
3.2 什么场景下应该选 AGPL
如果你是一个开源项目的作者,正在纠结用哪个协议,我的建议是这样的:如果你的核心诉求是“防止云厂商白嫖”,那 AGPL 是最直接的选择。它不需要你额外写什么附加条款,协议本身就包含了网络服务的约束。很多基础设施类项目,比如数据库、消息队列、监控系统,选 AGPL 就是明确告诉外界:你可以用,可以改,但你要是拿它做托管服务卖钱,你得把改动回馈社区。
但如果你希望自己的项目被尽可能多的商业公司采用,那 AGPL 可能会吓跑一批用户。我接触过不少公司的法务流程,AGPL 组件基本是默认拉黑的,除非有非常强的业务理由,否则审批很难通过。所以如果你做的是一个通用工具库,希望被广泛集成,MIT 或者 Apache-2.0 会更合适。
3.3 什么场景下应该避开 AGPL
反过来,如果你是一个商业公司的技术负责人,在选型时看到 AGPL 组件,先别急着用,问自己三个问题:第一,我能不能接受把相关代码开源?第二,我能不能把它隔离成独立服务?第三,我有没有法务资源去审核合规性?如果三个答案都是“不能”或者“没有”,那就果断换方案。
我踩过的一个坑是:早期做一个内部数据分析平台,图省事用了一个 AGPL 的图表库,当时觉得“内部系统不分发,应该没事”。后来这个平台要开放给客户使用,虽然只是通过浏览器访问,但这就触发了 AGPL 的网络服务条款。最后我们花了两个月时间,把那个图表库替换成了一个 MIT 协议的替代品,期间还要重写所有调用逻辑。这个教训告诉我,选型时多花十分钟看协议,能省后面两个月返工。
4. 商用场景下的合规实操指南
4.1 第一步:做一次完整的依赖扫描
很多团队根本不知道自己用了哪些开源组件,更别说知道它们的协议了。所以合规的第一步永远是摸清家底。我常用的工具组合是这样的:对于 JavaScript 项目,用license-checker扫一遍 node_modules;对于 Java 项目,用mvn license:aggregate-add-third-party生成报告;对于 Python,用pip-licenses列出所有包的协议。如果是多语言混合的项目,可以用FOSSA或者ScanCode做统一扫描。
扫描完之后,把所有 AGPL 和 GPL 的组件单独列出来,逐个确认:这个组件是直接依赖还是间接依赖?是运行时依赖还是构建时依赖?构建时依赖通常风险较低,因为最终产物里不包含它的代码。运行时依赖就要重点分析了。
注意:间接依赖往往是最容易被忽略的。你直接用的库是 MIT 协议,但它依赖了一个 AGPL 的子库,这种情况在 Node.js 生态里特别常见。所以扫描一定要扫到最底层。
4.2 第二步:判断使用方式是否构成衍生作品
这一步需要结合前面讲的“进程隔离”原则来具体分析。我一般会画一张调用关系图,把 AGPL 组件放在中间,看它和主业务之间的边界在哪里。如果边界是清晰的网络接口,那风险可控;如果边界模糊,比如共享了数据结构、通过 FFI 调用、或者打包在同一个进程中,那就需要进一步评估。
有一个实用的判断技巧:假设你把 AGPL 组件替换成一个功能相同但协议不同的实现,你的主业务代码需要改多少?如果只需要改配置文件和接口地址,那说明耦合度低,大概率是独立作品。如果需要改大量业务逻辑,那说明两者已经深度交织,很可能被认定为衍生作品。
4.3 第三步:设计合规方案
如果评估下来确实需要合规,通常有三条路可走。第一条是完全开源,把相关代码按照 AGPL 的要求发布出去。这条路适合那些本来就打算开源的项目,或者公司有开源战略的情况。第二条是隔离部署,把 AGPL 组件拆成独立服务,通过 API 调用,主业务保持闭源。这条路适合技术能力强、愿意投入架构改造的团队。第三条是替换组件,找一个协议更宽松的替代品。这条路最彻底,但迁移成本也最高。
我个人的经验是,对于大多数商业项目,隔离部署是性价比最高的方案。它既保留了 AGPL 组件的功能,又避免了开源全部代码。但隔离部署有几个技术细节要注意:服务之间的通信要走标准协议,不能共享数据库连接池,不能共用同一个 JVM 或者容器。日志和监控也要分开,避免因为共享基础设施而被认定为单一作品。
4.4 第四步:建立持续的合规流程
合规不是一次性任务,而是一个持续的过程。新依赖不断引入,旧依赖不断升级,协议也可能发生变化。所以我建议在 CI/CD 流程里加一个许可证检查环节,每次合并请求都自动扫描新增依赖的协议。如果发现 AGPL 或者其它高风险协议,就自动打标签提醒 reviewer。
另外,维护一份许可证白名单和黑名单也很有必要。白名单里放 MIT、Apache-2.0、BSD 这些可以放心用的;黑名单里放 AGPL、SSPL 这些需要特别审批的。中间地带比如 LGPL、MPL,可以设定为“需要架构师确认”。这份清单要随着团队经验不断更新,形成组织记忆。
5. 常见问题与排查技巧实录
5.1 高频问题速查表
下面这张表整理了我在实际工作中被问得最多的几个问题,以及对应的处理思路。
| 问题场景 | 核心判断点 | 建议处理方式 |
|---|---|---|
| 内部系统用了 AGPL 组件,不分发 | 是否通过网络提供服务 | 如果只有内部员工访问,风险较低;如果外部客户能访问,需合规 |
| 用 AGPL 组件做代码生成工具 | 生成物是否包含 AGPL 代码 | 如果生成物是独立作品,通常不受影响;如果生成物链接了 AGPL 库,需注意 |
| 修改了 AGPL 代码但只在公司内用 | 是否触发分发或网络服务 | 纯内部使用且无网络交互,通常不触发;但建议保留修改记录 |
| 用 AGPL 组件做 SaaS,但只调用 API | 是否构成衍生作品 | 进程隔离且标准协议调用,通常可视为独立作品 |
| 项目里同时有 AGPL 和 MIT 组件 | 协议兼容性 | AGPL 与 MIT 兼容,但整体分发时需满足 AGPL 要求 |
5.2 几个容易误判的边界情况
有一种情况特别容易搞混:用 AGPL 组件做开发工具,但最终产品不包含它。比如你用了一个 AGPL 的代码生成器,生成了一堆业务代码,然后把这些代码打包进商业产品。这种情况下,生成器本身没有被分发,生成物也不包含生成器的代码,所以通常不构成衍生作品。但如果你把生成器也打包进了产品,让用户能调用它,那就另当别论了。
另一种情况是动态链接和静态链接的区别。AGPL 和 GPL 一样,对静态链接的约束更强。如果你把 AGPL 库静态链接进了你的二进制,那整个二进制都被视为衍生作品。动态链接的话,如果满足 LGPL 那样的条件(允许用户替换库),可能可以豁免,但 AGPL 本身没有明确的 LGPL 例外条款,所以动态链接也不能完全放心。最稳妥的还是进程隔离。
还有一种情况是云服务商提供的托管服务。比如你在某云上买了一个基于 AGPL 的数据库服务,你只是使用者,不是提供者。这种情况下,合规义务在云厂商那边,你不需要操心。但如果你基于这个服务做了二次开发,然后把二次开发的部分作为服务提供出去,那你就成了提供者,需要承担合规义务。
5.3 独家避坑技巧
第一个技巧:在项目 README 里显式声明许可证兼容性。我习惯在项目根目录放一个LICENSES.md,列出所有直接依赖的协议,并说明本项目的协议选择理由。这样做的好处是,后来接手的人能快速理解边界,减少误用风险。
第二个技巧:对 AGPL 组件做版本锁定。因为协议可能随版本变化,今天 MIT 的库明天可能改成 AGPL。锁定版本并在升级时人工审核协议变化,能避免意外“被传染”。
第三个技巧:保留所有修改记录。如果你确实修改了 AGPL 代码,哪怕只是改了一个配置项,也要在文件头注明修改时间和内容。这不仅是合规要求,也是对自己工作的记录。我见过因为修改记录缺失,导致无法证明哪些是自己写的、哪些是原作者的,最后只能全部开源的情况。
第四个技巧:和法务保持同步。技术团队自己判断协议风险,有时候会过于乐观或者过于悲观。定期和法务过一遍高风险依赖清单,能帮你校准判断标准。我们团队现在的做法是每个季度做一次开源合规 review,把新增的 AGPL 依赖拿出来讨论,决定是隔离、替换还是走审批流程。
6. 从 AGPL 看开源商业模式的演进
AGPL 的出现和流行,其实反映了开源社区和商业公司之间的一种博弈。早期开源项目大多用 MIT 或者 BSD,商业公司拿过去改一改就能闭源卖钱,社区得不到回馈。后来 GPL 出现了,要求分发时开源,但云厂商又找到了漏洞:不分发,只提供网络服务。AGPL 就是补上这个漏洞的产物。
但 AGPL 也不是万能的。它只能约束那些愿意遵守协议的人,对于故意侵权的公司,最终还是得靠法律手段。而且 AGPL 的“网络服务”定义在某些场景下仍然模糊,比如 API 调用算不算“交互”,微服务架构下怎么界定边界,这些问题在司法实践中还没有特别明确的判例。
我个人的观察是,越来越多的基础设施项目开始采用“开放核心”(open core)模式:核心功能用 AGPL 或者 SSPL,企业级功能用商业协议。这样既能保证社区能用到基础版本,又能让商业公司为高级功能付费。这种模式是否可持续,还有待时间检验,但至少它提供了一种在开源和商业之间找平衡的思路。
对于开发者来说,理解 AGPL 不仅仅是为了合规,更是为了理解开源世界的游戏规则。你选择的每一个许可证,都在表达你对“代码应该怎么被使用”的态度。这个态度会吸引志同道合的人,也会劝退一些只想白嫖的人。想清楚自己要什么,比盲目跟风选协议重要得多。
我在实际项目中的体会是,与其纠结“能不能用 AGPL”,不如先想清楚“我愿不愿意开源”。如果答案是愿意,那 AGPL 是个很好的选择,它能保护你的项目不被闭源商业化。如果答案是不愿意,那就老老实实找 MIT 或者 Apache-2.0 的替代品,别在灰色地带试探。技术选型没有绝对的对错,只有适不适合你的业务模式和价值观。