为什么本地开发也需要 HTTPS
很多开发者习惯在本地使用 http://localhost 进行开发,认为 HTTPS 只有在生产环境才需要。但现代 Web 平台的能力正在快速向安全上下文(Secure Context)收拢:Service Worker、Web Crypto API、Geolocation、摄像头与麦克风访问、HTTP/2 与 HTTP/3、Cookie 的 Secure 属性等,都要求页面运行在 HTTPS 之下。即便你在本地绕过这些限制,代码一旦部署到测试环境或生产环境,协议差异带来的行为不一致往往会制造难以排查的 bug。
更现实的问题是内网服务。公司内部的 API 网关、微服务、管理后台、IoT 设备控制面板,如果只跑 HTTP,任何能接入内网的人都可以明文嗅探甚至篡改流量。搭建一套自己的私有 CA,为内网域名签发证书,不仅能解决信任问题,还能让整个团队共用同一套可信根证书。
自签名证书、私有 CA 与公共 CA 的区别
理解三者差异是选型的前提。
自签名证书(Self-Signed Certificate) 是指证书的签发者(Issuer)和使用者(Subject)是同一个实体,证书由自己的私钥签名。浏览器和操作系统默认不信任它,因为没有任何受信任的第三方为其背书。它适合个人临时测试,但不适合团队协作——每个人都要单独手动信任。
私有 CA(Private CA) 则模拟了公共 CA 的层级结构:你创建一个根证书(Root CA),用它签发服务器证书(Leaf Certificate)。只要把根证书安装到客户端信任库,所有由它签发的证书都会被自动信任。这是团队和内网环境的正确做法。
公共 CA(如 Let's Encrypt、DigiCert)签发的证书被所有设备默认信任,但无法为 .local、.internal 或纯内网 IP 签发证书,且证书透明度日志(CT Log)会公开你的域名。内网服务通常不希望暴露在公共日志中。
方案一:mkcert —— 最省事的本地开发方案
如果你只是想让 localhost 和几个本地域名跑上 HTTPS,mkcert 是最佳选择。它在本地创建一个 CA,自动将其安装到系统信任库,并为你签发证书。
# 安装(macOS)
brew install mkcert
brew install nss # 如果使用 Firefox
# 创建本地 CA 并安装到系统信任库
mkcert -install
# 为本地域名签发证书
mkcert localhost 127.0.0.1 ::1 dev.example.test "*.dev.example.test"
生成的 localhost+4.pem 和 localhost+4-key.pem 即可配置到 Nginx、Caddy 或 Node.js 服务中。mkcert 的 CA 根证书位于 $(mkcert -CAROOT) 目录,把它分发给团队成员并安装,就能实现团队内的互信。
mkcert 的局限在于它面向开发场景,不提供服务端自动化、证书吊销等能力,不适合作为长期的内网 CA 基础设施。
方案二:用 OpenSSL 搭建私有 CA
当需要为整个内网签发证书时,手动用 OpenSSL 建立 CA 更可控。以下是最小可用流程。
1. 生成根 CA
# 生成根私钥(4096 位,AES256 加密)
openssl genrsa -aes256 -out ca.key 4096
# 生成自签名根证书,有效期 10 年
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \
-subj "/C=CN/O=MyCompany/CN=MyCompany Internal Root CA" \
-out ca.crt
ca.key 是整条信任链的命脉,必须离线保存、严格限制访问权限(chmod 400),理想情况下放在硬件令牌或离线机器上。
2. 为服务器签发证书
# 生成服务器私钥和 CSR
openssl genrsa -out server.key 2048
openssl req -new -key server.key \
-subj "/C=CN/O=MyCompany/CN=api.internal.example.com" \
-out server.csr
# 使用扩展文件指定 SAN(现代浏览器不再看 CN,只看 SAN)
cat > san.cnf <<EOF
subjectAltName = DNS:api.internal.example.com, DNS:*.internal.example.com, IP:10.0.0.10
extendedKeyUsage = serverAuth
EOF
# 用根 CA 签发,有效期 825 天
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out server.crt -days 825 -sha256 -extfile san.cnf
关键点:必须包含 SAN 扩展。Chrome 自 58 版本起完全忽略 Common Name,只认 subjectAltName。同时 extendedKeyUsage = serverAuth 明确证书用途,避免被误用。
3. 分发根证书
将 ca.crt 分发给所有需要访问内网服务的客户端:
- macOS:双击导入「钥匙串访问」,在「系统」钥匙串中设为「始终信任」。
- Windows:
certutil -addstore -f "ROOT" ca.crt或通过组策略批量推送。 - Linux:复制到
/usr/local/share/ca-certificates/,执行update-ca-certificates。 - iOS/Android:通过 MDM 或手动安装描述文件,注意 Android 7+ 后 App 默认不信任用户证书,需要在
network_security_config.xml中显式声明。 - Firefox:使用独立信任库,需在「证书管理器」中单独导入。
方案三:现代工具链
手动 OpenSSL 流程繁琐且容易出错,生产级内网 CA 可以考虑这些工具:
- step-ca(Smallstep):提供 ACME 协议支持,可自动签发和轮换证书,内置 OCSP 和吊销列表,适合作为长期内网 CA。
- CFSSL(Cloudflare):JSON 驱动的证书签发工具,适合批量管理。
- Vault PKI Secrets Engine:HashiCorp Vault 的 PKI 引擎,支持动态短期证书,与身份系统集成,适合有合规要求的企业。
- Caddy:内置
tls internal指令,自动生成并管理本地 CA,配置反向代理时几乎零成本。
常见坑与最佳实践
证书有效期:公共 CA 已将有效期压缩到 398 天,内网证书虽可更长,但建议不超过 825 天,并建立轮换机制。
私钥保护:根 CA 私钥绝不能放在 Web 服务器上。签发服务器证书时应使用中间 CA(Intermediate CA),根 CA 保持离线。
通配符与 SAN:*.internal.example.com 不匹配 internal.example.com 本身,需要同时列入 SAN。通配符也不匹配多级子域。
HSTS 慎用:本地开发环境不要开启 HSTS,否则一旦证书出问题,浏览器会强制 HTTPS 且无法绕过,清理起来非常麻烦。
吊销机制:私有 CA 也应提供 CRL 或 OCSP,至少维护一份吊销列表,证书泄露时能及时止损。
结语
本地和内网 HTTPS 不是可选项,而是现代开发的基线要求。个人开发用 mkcert 几分钟即可搞定;团队内网则应建立正式的私有 CA,配合 step-ca 或 Vault 实现自动化签发与轮换。核心原则只有两条:根私钥离线保护,根证书全员分发。做到这两点,你就能拥有一个既安全又无需忍受浏览器警告的开发环境。
未经允许不得转载:任鹏个人博客 » 自签名证书、私有 CA 与内网 HTTPS:如何搭建可信的本地开发环境


朋友圈点赞图在线生成源码