1. 从一次代码审计说起:AGPL-3.0到底管什么
去年帮一个做企业内部工具的朋友看代码,他们用了一个基于AGPL-3.0协议的开源组件做二次开发,然后打包成SaaS服务卖给客户。我当时就问了一句:你们的源码对外公开了吗?他一脸茫然地说,我们又没分发软件,只是放在自己服务器上跑,为什么要公开?
这个问题其实非常典型。很多开发者对GPL系列协议的理解停留在"开源软件不能商用"这个层面,而AGPL-3.0恰恰是GPL家族里最容易被误解、也最容易踩雷的一个。它的全称是GNU Affero General Public License version 3,由自由软件基金会(FSF)发布,核心目标是堵住GPL在云服务场景下的一个"漏洞"——你可以不分发软件,但只要你通过网络提供服务,就必须把源码交出来。
这篇文章适合三类人看:一是正在做技术选型、纠结要不要引入AGPL组件的后端和架构同学;二是准备把开源项目商业化的独立开发者;三是需要给团队做开源合规培训的技术负责人。我会从协议的核心条款拆起,把商用边界、合规操作、常见误区和实际案例都讲透,让你看完能直接判断自己手里的项目到底能不能用、怎么用。
先说结论:AGPL-3.0不是不能商用,而是商用之后你要承担"源码开放"的义务。这个义务的触发条件、覆盖范围、执行方式,才是真正需要搞清楚的东西。
2. AGPL-3.0的核心条款拆解:它和GPL到底差在哪
2.1 第13条:网络交互触发的源码开放义务
AGPL-3.0和GPL-3.0的正文几乎一模一样,唯一的实质性差异就是新增的第13条。这一条的核心意思是:如果你修改了AGPL授权的程序,并且让用户通过网络与这个程序交互,那么你必须向这些用户提供你修改后的完整源码。
注意这里的几个关键词。"修改"是触发条件之一,但并不是唯一条件——即使你没有修改,只是原样部署,第13条同样要求你提供源码。这一点很多人搞错了,以为只要不改代码就没问题。实际上,只要你通过网络向用户提供了服务,用户就有权获取你运行的这个版本的源码。
"通过网络交互"的定义也比较宽泛。用户通过浏览器访问你的Web应用算,通过API调用算,甚至通过移动端App间接调用后端服务也算。FSF在官方FAQ里明确说过,如果用户能通过网络与程序进行交互,就满足触发条件。这意味着SaaS场景几乎全覆盖。
2.2 与GPL-3.0的继承关系:copyleft的传染性
AGPL-3.0继承了GPL-3.0的强copyleft特性。所谓copyleft,就是"以相同方式共享"——你基于AGPL代码做的衍生作品,必须以AGPL协议发布。这里的"衍生作品"在法律上的界定比较复杂,但技术社区普遍接受的标准是:如果你的代码和AGPL代码形成了紧密的耦合关系(比如链接同一个进程、共享数据结构、互相调用函数),那就构成衍生作品。
反过来,如果你的程序只是通过命令行调用AGPL工具、通过HTTP请求访问AGPL服务、或者通过标准输入输出传递数据,通常被认为是"聚合"而非"衍生",不受copyleft约束。这个边界在实际操作中经常引发争议,后面我会专门用一节来讲怎么判断。
2.3 专利授权与终止条款:比GPL-2.0更现代的设计
AGPL-3.0还包含明确的专利授权条款。任何贡献者通过提交代码,默示授予用户使用其专利的权利。如果用户对贡献者发起专利诉讼,授权自动终止。这个设计比GPL-2.0更完善,对商用企业来说其实是一种保护——你不用担心用了某个AGPL组件之后,被原作者用专利卡脖子。
终止条款方面,AGPL-3.0给了30天的补救期。如果你违反了协议,在收到通知后30天内完成整改,授权可以恢复。这个缓冲期对商用团队比较友好,不至于因为一次疏忽就永久失去使用权。
| 对比维度 | GPL-3.0 | AGPL-3.0 |
|---|---|---|
| 源码开放触发条件 | 分发软件 | 分发软件或网络提供服务 |
| 适用场景 | 桌面软件、嵌入式 | SaaS、Web服务、API服务 |
| 专利授权 | 有 | 有 |
| 违约补救期 | 30天 | 30天 |
| 与GPL-2.0兼容性 | 不兼容 | 不兼容 |
3. 商用场景下的边界判定:什么情况下你必须开源
3.1 SaaS部署:最典型的触发场景
假设你用了一个AGPL-3.0的前端框架或者后端服务组件,部署在自己的云服务器上,用户通过浏览器访问。这种情况下,你几乎肯定需要向用户提供源码。具体来说,你需要提供的是" Corresponding Source"——包括你修改过的部分、以及用来编译、安装、运行该程序所需的所有脚本和配置文件。
这里有个细节容易被忽略:你不需要把源码公开到GitHub上让全世界看到,只需要向"通过网络与你交互的用户"提供。理论上你可以只在用户请求时通过邮件发送源码包。但实际操作中,大多数团队会选择直接公开仓库,因为维护一个"按需提供"的流程成本更高,而且容易遗漏。
3.2 内部使用:不触发开放义务
如果你的AGPL组件只在内网使用,用户仅限于公司员工,且不对外提供服务,那么不触发第13条。因为"通过网络交互"的用户范围是有限的内部人员,FSF认为这不构成对外提供服务。但要注意,如果内网系统后来对外开放了,或者被集成到了对外产品中,义务就产生了。
我见过一个案例:某公司用AGPL组件做内部报表系统,后来业务部门把报表功能开放给了合作伙伴访问,结果就踩线了。所以判断标准不是"部署在哪里",而是"谁在通过网络使用它"。
3.3 工具链使用:通常不构成衍生作品
如果你只是用AGPL授权的编译器、构建工具、代码生成器来处理你的代码,通常不构成衍生作品。比如你用某个AGPL的代码生成工具生成了代码,生成的代码本身不受AGPL约束。但如果生成工具把自身的运行时代码嵌入了输出结果,那就另当别论。
这个边界在FSF的FAQ里有说明:使用GPL工具运行程序,不会使程序的输出受GPL约束,除非工具把自身的一部分复制到了输出中。AGPL同理。
3.4 动态链接与静态链接:技术细节决定法律风险
动态链接AGPL库,通常被认为构成衍生作品,需要开源。静态链接更是明确构成衍生作品。但如果是通过进程间通信(IPC)、RPC、消息队列等方式调用独立的AGPL服务,一般被认为是聚合,不需要开源你的调用方代码。
这个判断标准不是绝对的,最终还是要看具体的耦合程度。我的经验是:如果你不确定,就假设需要开源,然后找法律顾问确认。开源合规这件事,宁可保守一点。
提示:AGPL-3.0的源码开放义务只针对"你修改后的AGPL程序"本身,不要求你公开整个应用的所有代码。但如果你把AGPL代码和自有代码编译进了同一个二进制文件,那整个二进制文件的源码都需要开放。
4. 合规实操:从引入到发布的完整流程
4.1 引入前的许可证审查清单
在把任何AGPL组件引入项目之前,我建议走一遍这个清单:
- 确认组件的确切许可证版本。有些项目写的是"GPL",但实际是AGPL,或者双协议授权。看LICENSE文件和package.json里的license字段。
- 确认是否有商业授权选项。很多AGPL项目采用双协议模式,比如MySQL、MongoDB(早期)、Grafana等,你可以购买商业许可证来规避AGPL义务。
- 评估使用方式。是链接调用、独立部署、还是仅作为开发工具?不同方式的风险等级不同。
- 确认团队能否接受开源义务。如果这个项目是公司的核心产品,开源源码可能不现实,那就需要考虑替代方案。
- 记录审查结论。把组件名称、版本、许可证、使用方式、审查人、审查日期记录下来,形成合规档案。
这个清单看起来简单,但实际执行中经常发现遗漏。我见过一个团队用了某个AGPL的JavaScript库,以为前端代码不算"分发",结果被原作者发邮件要求开源。前端代码通过网络传输到用户浏览器,本身就是一种分发形式。
4.2 源码开放的边界:哪些代码必须给,哪些可以保留
这是商用团队最关心的问题。根据AGPL-3.0的原文,你需要提供的是"Corresponding Source",具体包括:
- 你修改过的AGPL代码部分
- 与AGPL代码链接、合并、共享数据结构的自有代码
- 用于生成、安装、运行目标代码的脚本和配置文件
- 接口定义文件、编译脚本、安装脚本
可以保留不开源的部分:
- 独立运行的、通过标准协议与AGPL服务通信的客户端代码
- 与AGPL代码没有编译级耦合的独立模块
- 你自有的、不包含AGPL代码的业务逻辑(前提是能清晰分离)
实际操作中,最稳妥的做法是把AGPL组件隔离成独立的微服务,通过HTTP或gRPC对外提供服务。这样你的主应用代码就不构成衍生作品,只需要开源你对AGPL服务本身的修改。
4.3 隔离架构的设计模式
如果你确实需要用AGPL组件但又不想开源主应用,隔离架构是唯一可行的技术方案。具体做法:
- 把AGPL组件部署为独立进程或独立容器
- 通过定义良好的API接口与主应用通信
- 主应用不链接AGPL库,不共享内存,不直接调用其内部函数
- AGPL服务的修改部分单独维护,按AGPL协议开源
- 主应用代码保持闭源
这种架构的代价是增加了网络开销和运维复杂度,但换来了合规安全。我帮一个团队做过这种改造,把一个AGPL的报表引擎从主应用里拆出来,单独部署,主应用通过REST API调用。改造花了两周,但避免了整个产品开源的风险。
注意:隔离架构的有效性取决于隔离的彻底程度。如果两个进程之间传递的是复杂的数据结构,或者存在紧密的调用关系,法院可能仍然认定构成衍生作品。建议在架构设计阶段就咨询法律意见。
4.4 发布时的合规检查步骤
当你准备发布一个包含AGPL组件的产品时,按这个顺序检查:
- 确认所有AGPL组件的版本和修改记录
- 准备Corresponding Source包,包括修改后的AGPL代码和构建脚本
- 在产品的"关于"页面或文档中放置源码获取链接
- 确保源码包可以通过网络下载,且下载链接长期有效
- 在源码包中保留原始版权声明和许可证文本
- 如果修改了AGPL代码,在文件头添加修改说明和日期
- 记录发布版本与源码版本的对应关系
这套流程看起来繁琐,但一旦建立起来,后续维护成本并不高。关键是要在CI/CD流程中固化这些检查点,避免人为遗漏。
5. 常见误区与真实踩坑案例
5.1 "我们没分发软件,所以不用开源"
这是最常见的误解。AGPL-3.0第13条专门针对网络服务场景,就是为了堵住这个漏洞。只要用户能通过网络与你的服务交互,你就需要提供源码。SaaS模式恰恰是AGPL重点覆盖的场景。
我见过一个创业团队,用AGPL的数据库中间件做了一套数据查询服务,对外提供API。他们一直以为"软件没离开我们的服务器"就不算分发。后来被社区发现,收到了律师函,最后不得不把整个查询服务的源码开源,包括他们自研的查询优化模块。
5.2 "我们只是内部用,不对外"
内部使用的边界在于"用户范围"。如果只有公司员工通过内网访问,通常没问题。但如果外部合作伙伴、客户、甚至通过公开网络访问的任何人能用,就触发了义务。
有个案例是某公司的运维平台用了AGPL组件,后来把监控面板的只读权限开放给了客户,客户可以通过浏览器查看。这个"开放给客户"的动作,就让内部系统变成了对外服务。
5.3 "我们改了代码但没发布,所以不用开源"
修改与否不影响第13条的触发。即使你原样使用,只要通过网络提供服务,就需要提供源码。修改只是让你需要额外提供修改部分。
5.4 "我们用Docker部署,不算分发"
Docker镜像的分发确实是分发,但AGPL第13条管的是网络交互,不是镜像分发。即使你不分发镜像,只在服务器上跑容器,用户通过网络访问服务,同样触发义务。Docker在这里不是避风港。
5.5 真实案例:从收到通知到完成合规的完整过程
去年有个做在线文档协作的团队找到我,他们用了一个AGPL的富文本编辑器组件,产品已经上线运营了一年多。原作者通过邮件联系他们,指出他们没有遵守AGPL协议。
他们的处理过程是这样的:
第一步,确认事实。他们确实用了AGPL组件,确实通过网络提供服务,确实没有开源。事实清楚,没有争议。
第二步,评估影响范围。他们梳理了代码,发现AGPL组件只用于编辑器部分,与主应用通过iframe隔离,通信通过postMessage。这个隔离程度比较好,意味着只需要开源编辑器相关的修改,不需要开源整个产品。
第三步,制定整改方案。他们决定把编辑器的修改部分开源到GitHub,同时在产品文档中添加源码链接。主应用代码保持闭源。
第四步,与原作者沟通。他们回复了邮件,说明了整改计划,并询问是否有其他要求。原作者表示接受,但要求他们在源码包中保留原始版权声明。
第五步,执行整改。他们花了一周时间整理代码、添加许可证声明、建立源码仓库、更新产品文档。
第六步,确认合规。整改完成后,他们再次联系原作者确认,对方确认没有问题。
整个过程从收到通知到完成整改,大约用了三周。关键是他们没有拖延,也没有试图狡辩,而是积极沟通、快速行动。这个案例说明,AGPL违规并不是世界末日,但前提是你得认真对待。
6. 替代方案与选型建议:什么时候该避开AGPL
6.1 宽松许可证的替代品
如果你的项目确实无法接受AGPL的开源义务,可以考虑以下替代方案:
- MIT许可证:最宽松,几乎没有任何限制,只需保留版权声明。适合大多数商业项目。
- Apache-2.0:宽松,包含明确的专利授权,适合企业级项目。
- BSD系列:同样宽松,条款简单。
- MPL-2.0:弱copyleft,修改的文件需要开源,但与自有代码链接不触发传染。适合想保留部分开源的场景。
- LGPL:弱copyleft,动态链接不触发传染,适合库类组件。
选型时的判断逻辑:如果你的项目需要闭源商用,优先选MIT或Apache-2.0。如果需要专利保护,选Apache-2.0。如果希望修改部分回馈社区但不想开源全部,选MPL-2.0。
6.2 双协议授权的商业版本
很多AGPL项目提供商业授权选项。你可以购买商业许可证,在闭源条件下使用。常见的双协议项目包括:
| 项目 | 开源协议 | 商业授权 |
|---|---|---|
| MySQL | GPL-2.0 | 有 |
| Grafana | AGPL-3.0 | 有 |
| MongoDB | SSPL | 有 |
| Redis | RSALv2/SSPLv1 | 有 |
| Elasticsearch | SSPL/Elastic License | 有 |
购买商业授权的成本需要和自研成本、合规成本做对比。对于核心业务依赖的组件,商业授权往往是更省心的选择。
6.3 自研替代的成本评估
如果既不想开源,又不想买商业授权,那就只能自研替代。自研的成本包括开发成本、测试成本、维护成本、以及功能差距带来的业务损失。我一般建议团队先算一笔账:自研需要多少人月,这些人月的成本是多少,对比商业授权的年费,哪个更划算。
很多时候,商业授权的费用远低于自研成本。但如果是非核心组件,自研一个简化版可能更经济。
6.4 选型决策树
我总结了一个简单的决策流程:
- 这个组件是不是核心业务依赖?如果是,进入第2步;如果不是,考虑用宽松协议的替代品。
- 能否接受开源义务?如果能,直接用AGPL版本;如果不能,进入第3步。
- 有没有商业授权?如果有,评估费用是否可接受;如果没有,进入第4步。
- 能否通过隔离架构规避?如果能,设计隔离方案;如果不能,进入第5步。
- 自研替代的成本是否可接受?如果可接受,自研;如果不可接受,重新评估需求或寻找其他方案。
这个决策树不是绝对的,但能帮你快速理清思路。
7. 团队协作中的AGPL合规管理
7.1 建立开源组件准入流程
合规不是一个人的事,需要流程保障。我建议在团队中建立这样的准入流程:
- 任何新引入的开源组件,必须经过许可证审查
- 审查结果记录在案,包括组件名、版本、许可证、使用方式、风险等级
- 高风险组件(如AGPL)需要技术负责人和法律顾问双重确认
- 准入流程嵌入到代码审查环节,没有审查记录的PR不予合并
这个流程的关键是"嵌入现有工作流",而不是另起一套。开发同学最反感额外的流程,但如果把许可证检查做成CI的一个步骤,大家接受度会高很多。
7.2 自动化工具的使用
手动审查容易遗漏,建议用自动化工具辅助:
- FOSSA:商业工具,支持许可证扫描和合规管理
- Black Duck:商业工具,功能全面
- ScanCode Toolkit:开源工具,可以集成到CI中
- license-checker:Node.js生态的许可证检查工具
- pip-licenses:Python生态的许可证检查工具
这些工具能自动识别依赖树中的许可证类型,标记出AGPL、GPL等高风险许可证。但工具不是万能的,它只能识别标准许可证文本,对于自定义许可证或双协议授权,还是需要人工判断。
7.3 定期审计与文档维护
开源合规不是一次性的工作,需要定期审计。我建议每季度做一次全量扫描,检查是否有新增的AGPL依赖,是否有许可证变更,是否有未记录的修改。
文档维护方面,至少要保留以下记录:
- 开源组件清单(SBOM)
- 每个组件的许可证和审查记录
- AGPL组件的修改记录
- 源码开放的记录(如果有)
- 与原作者或社区的沟通记录
这些文档在遇到合规问题时,能帮你快速定位和响应。
7.4 与法务团队的协作要点
技术团队和法务团队的沟通经常存在障碍。技术人员觉得法务不懂技术,法务觉得技术人员不重视风险。我的经验是,技术人员应该主动做两件事:
第一,把技术问题翻译成法律语言。不要说"我们动态链接了AGPL库",而要说"我们的代码和AGPL代码编译在同一个二进制文件中,构成了衍生作品"。
第二,提供明确的选项和后果。不要只问"这个能不能用",而要给出"方案A需要开源,方案B需要购买授权,方案C需要自研,各自的成本和风险是什么"。
这样法务团队才能给出有效的建议,而不是笼统地说"有风险,建议不用"。
8. 我个人的几条实操心得
踩过几次坑之后,我总结了几个比较实用的经验。
第一,把AGPL组件当成"需要付费"的组件来对待。要么付商业授权的钱,要么付开源的成本,要么付自研的代价。天下没有免费的午餐,AGPL的"免费"是有条件的。
第二,隔离架构要早做。如果项目初期就决定用AGPL组件,一开始就把隔离架构设计好,后期改造的成本会低很多。我见过太多团队后期被迫重构,花的钱比一开始买商业授权还多。
第三,源码开放不等于核心泄露。很多人把源码看得太重,实际上大多数产品的竞争力不在代码本身,而在运营、数据、生态。开源一部分代码,有时候反而能带来社区贡献和品牌曝光。
第四,保留证据。无论是商业授权的购买记录,还是源码开放的记录,还是与作者的沟通记录,都要保存好。万一出现争议,这些证据能帮你省很多事。
第五,不要心存侥幸。AGPL社区虽然不像某些商业公司那样积极维权,但一旦被发现,处理起来很麻烦。主动合规的成本,永远低于被动整改的成本。
最后分享一个判断技巧:如果你不确定某个用法是否触发AGPL义务,就问自己一个问题——"用户能不能通过网络使用到这个AGPL程序的功能?"如果答案是能,那就假设需要开源,然后找专业人士确认。这个简单的判断标准,能帮你避开大部分坑。