let’s encrypt对子域名的实际限制是:每个注册域名每3小时最多50张证书,每张证书最多100个域名;通配符或单证书覆盖多子域不触发限速,但为每个子域单独申请则易超限。

Caddy 的自动 HTTPS 机制本身不限制子域名数量,但实际能成功申请和续期的子域名数,取决于 Let’s Encrypt 的速率限制策略 —— 这是根本约束,FrankenPHP 不会绕过它。
Let’s Encrypt 对子域名的实际限制是什么
Let’s Encrypt 官方明确限制:每个注册域名(registered domain)下,每 3 小时最多可申请 50 张证书,每张证书最多包含 100 个域名(SANs)。注意这里的“注册域名”指 example.com 这一级,不是 www.example.com 或 api.example.com。
也就是说,如果你用一个 Caddyfile 同时配置了:
sub1.example.com<br>sub2.example.com<br>...<br>sub50.example.com
——只要它们都在同一张证书里(即用通配符或单张多域名证书覆盖),就只算 1 次申请,不触发限速。但若你为每个子域名单独启动一个 FrankenPHP 实例、各自配独立 Caddyfile 和 SERVER_NAME,就极可能在短时间内撞上“50 certs / 3 hours”上限,导致后续申请返回 urn:ietf:params:acme:error:rateLimited 错误。
FrankenPHP 的 Caddy 配置如何影响证书申请行为
- 默认情况下,FrankenPHP 使用 Caddy 的
http自动 HTTP-01 挑战,所有匹配的子域名会尝试共用一张证书(只要它们解析到同一台服务器) - 若你在 Caddyfile 中显式使用
tls internal,则完全跳过 Let’s Encrypt,生成自签名证书 —— 此时无任何子域名数量限制,但浏览器会报不安全 - 若用泛域名证书(
*.example.com),需先通过 DNS-01 挑战验证主域所有权;FrankenPHP 本身不内置 DNS 提供商插件,必须配合 Caddy 的dns模块(如dns cloudflare)并配置 API 凭据,否则泛域名申请会失败
生产环境常见踩坑点
容易被忽略的是:Caddy 的证书缓存路径(/data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/)如果被清空或挂载为临时卷,每次重启都会当成“全新实例”,重新触发 ACME 流程 —— 这会让多个子域名配置在反复部署中快速耗尽配额。
另一个隐性问题:开发时本地用 localhost 或 127.0.0.1 测试,Caddy 默认 fallback 到 tls internal;但一旦切到真实域名,且 DNS 尚未生效或 TTL 未刷新,Caddy 会不断重试 HTTP-01,短时间内发起大量无效验证请求,同样计入速率限制。
真正卡住你的往往不是 FrankenPHP 或 Caddy 的能力,而是 ACME 协议层的守门人规则 —— 它不看你是谁,只认域名、IP 和请求频次。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











