let's encrypt 拒绝为内网 ip 签发证书,因其 acme 协议强制要求域名公网可验证,192.168.x.x、10.x.x.x、172.16.x.x 等私有地址被明确列入黑名单,caddy 等客户端会直接报错 invalid domain。

不能自动配 Let's Encrypt 证书,但可以手动配自签名或私有 CA 证书
为什么 Let's Encrypt 拒绝给内网 IP 签发证书
Let's Encrypt 的 ACME 协议强制要求域名可公网验证(HTTP-01 或 DNS-01),192.168.x.x、10.x.x.x、172.16.x.x 这类地址被明确列入黑名单。Caddy 在调用 ACME 客户端时会直接报错:invalid domain name "192.168.1.100" 或 acme: error: 400 :: POST :: https://acme-v02.api.letsencrypt.org/acme/new-order :: Invalid domain。
Caddyfile 里写 IP 地址会直接启动失败
FrankenPHP 启动时依赖 Caddy 的配置解析,如果在 Caddyfile 中把监听目标写成 IP 形式:
{ frankenphp { num_threads auto } }
192.168.1.100 {
php_server
}
会触发 Caddy 报错:invalid hostname "192.168.1.100": must be a valid domain name。Caddy 不允许纯 IP 作为 site address —— 它只接受域名或通配符(如 *),哪怕你只是想本地监听。
可行的替代方案:自签名证书 + 显式信任
对内网环境,最实际的做法是生成自签名证书,并让客户端(浏览器、curl、前端应用)显式信任它:
- 用
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650 -nodes生成一对cert.pem和key.pem - 在
Caddyfile中指定路径:https://192.168.1.100 { tls /path/to/cert.pem /path/to/key.pem php_server } - 浏览器访问时会提示“不安全”,需手动点击“高级 → 继续前往”;若用
curl,加--insecure参数绕过校验 - 企业内网可部署私有 CA,把根证书预装到所有终端,这样自签证书就能被自动信任
更轻量的选择:干脆不用 HTTPS
内网调试阶段,多数场景其实不需要 TLS 加密。FrankenPHP 默认监听 http://localhost:8080,直接去掉 https:// 前缀即可:
localhost:8080 {
php_server
}
注意两点:
– 必须显式写 localhost:8080 或 127.0.0.1:8080,不能只写端口
– 若要绑定到 0.0.0.0:8080 让局域网其他机器访问,Caddyfile 写成:0.0.0.0:8080(Caddy 允许这种形式,且不触发证书逻辑)
真正容易被忽略的是:FrankenPHP 的 HTTPS 能力完全由 Caddy 驱动,它自己不提供证书生成工具。所谓“自动 HTTPS”本质是 Caddy 的 ACME 自动化流程,而这个流程从设计上就和内网 IP 天然互斥。别试图 hack 域名解析或 hosts 文件来骗过 ACME —— 它验证的是公网可达性,不是你本机怎么解析的。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











