SSL/HTTPS 配置 #
概述 #
Caddy 最显著的特点是自动 HTTPS,它会自动获取、续期和管理 SSL 证书,无需手动配置。
text
┌─────────────────────────────────────────────────────────────┐
│ Caddy 自动 HTTPS 流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 检测域名配置 │
│ ↓ │
│ 2. 自动申请 Let's Encrypt 证书 │
│ ↓ │
│ 3. 自动配置 HTTPS │
│ ↓ │
│ 4. 设置 HTTP → HTTPS 重定向 │
│ ↓ │
│ 5. 自动续期证书 │
│ │
└─────────────────────────────────────────────────────────────┘
自动 HTTPS #
基本配置 #
caddyfile
# 只需指定域名,Caddy 自动处理 HTTPS
example.com {
respond "Hello, HTTPS!"
}
Caddy 会自动:
- 获取 Let’s Encrypt 证书
- 配置 HTTPS 监听
- 设置 HTTP 到 HTTPS 重定向
- 自动续期证书
多域名证书 #
caddyfile
# 多个域名共享证书
example.com, www.example.com, api.example.com {
respond "Multiple domains"
}
禁用自动 HTTPS #
caddyfile
# 禁用自动 HTTPS
example.com {
tls off
respond "HTTP only"
}
# 或使用端口指定
http://example.com {
respond "HTTP only"
}
证书获取方式 #
HTTP 验证(默认) #
caddyfile
# 默认使用 HTTP-01 验证
example.com {
respond "HTTP-01 challenge"
}
要求:
- 服务器必须监听 80 端口
- 域名必须解析到服务器 IP
- 防火墙允许 80 端口访问
TLS 验证 #
caddyfile
# 使用 TLS-ALPN-01 验证
example.com {
tls {
protocols tls1.2 tls1.3
}
respond "TLS-ALPN-01 challenge"
}
要求:
- 服务器必须监听 443 端口
- 域名必须解析到服务器 IP
- 防火墙允许 443 端口访问
DNS 验证 #
适用于内网或无法通过 80/443 端口验证的场景:
caddyfile
# Cloudflare DNS 验证
*.example.com {
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
respond "Wildcard certificate"
}
DNS 提供商配置 #
caddyfile
# Cloudflare
*.example.com {
tls {
dns cloudflare {
api_token {env.CLOUDFLARE_API_TOKEN}
}
}
}
# 阿里云 DNS
*.example.com {
tls {
dns alidns {
access_key_id {env.ALIYUN_ACCESS_KEY_ID}
access_key_secret {env.ALIYUN_ACCESS_KEY_SECRET}
}
}
}
# 腾讯云 DNS
*.example.com {
tls {
dns tencentcloud {
secret_id {env.TENCENTCLOUD_SECRET_ID}
secret_key {env.TENCENTCLOUD_SECRET_KEY}
}
}
}
# DigitalOcean
*.example.com {
tls {
dns digitalocean {env.DO_AUTH_TOKEN}
}
}
# AWS Route 53
*.example.com {
tls {
dns route53 {
access_key_id {env.AWS_ACCESS_KEY_ID}
secret_access_key {env.AWS_SECRET_ACCESS_KEY}
}
}
}
通配符证书 #
基本配置 #
caddyfile
# 通配符证书需要 DNS 验证
*.example.com {
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
respond "Wildcard domain"
}
通配符 + 主域名 #
caddyfile
# 同时覆盖主域名和子域名
example.com, *.example.com {
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
# 根据子域名路由
@api host api.example.com
handle @api {
reverse_proxy localhost:3000
}
@www host www.example.com
handle @www {
root * /var/www/html
file_server
}
handle {
respond "Main domain"
}
}
自定义证书 #
使用自有证书 #
caddyfile
example.com {
tls /etc/ssl/certs/example.com.crt /etc/ssl/certs/example.com.key
respond "Custom certificate"
}
证书和密钥文件 #
caddyfile
example.com {
tls {
# 证书文件
certificate /etc/ssl/certs/example.com.crt
# 密钥文件
key /etc/ssl/private/example.com.key
}
respond "Custom certificate"
}
PEM 格式内联 #
caddyfile
example.com {
tls {
certificate {
format pem
content "-----BEGIN CERTIFICATE-----\n..."
}
key {
format pem
content "-----BEGIN PRIVATE KEY-----\n..."
}
}
respond "Inline certificate"
}
证书存储 #
默认存储位置 #
text
# Linux
/var/lib/caddy/.local/share/caddy/certificates/
# macOS
~/Library/Application Support/Caddy/certificates/
# Windows
%AppData%\Caddy\certificates\
自定义存储位置 #
caddyfile
{
# 全局配置
storage file_system {
root /data/caddy
}
}
example.com {
respond "Custom storage"
}
分布式存储 #
caddyfile
{
# 使用 Consul 存储(需要插件)
storage consul {
address consul.example.com:8500
token {env.CONSUL_TOKEN}
prefix caddy
}
}
example.com {
respond "Consul storage"
}
证书管理 #
查看证书 #
bash
# 通过 API 查看证书
curl localhost:2019/certificates | jq
# 输出示例
{
"certificates": [
{
"domains": ["example.com"],
"issuer": "Let's Encrypt",
"not_before": "2024-01-01T00:00:00Z",
"not_after": "2024-04-01T00:00:00Z"
}
]
}
手动续期 #
bash
# Caddy 自动续期,但也可以手动触发
# 重载配置会检查证书是否需要续期
caddy reload --config Caddyfile
证书撤销 #
bash
# 撤销证书(需要通过 API 或重新配置)
# 删除存储的证书后重新启动
rm -rf /var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/example.com/
caddy reload --config Caddyfile
TLS 配置选项 #
协议版本 #
caddyfile
example.com {
tls {
# 指定最小和最大协议版本
protocols tls1.2 tls1.3
}
respond "TLS protocols"
}
加密套件 #
caddyfile
example.com {
tls {
# 指定加密套件
ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
}
respond "Custom ciphers"
}
曲线设置 #
caddyfile
example.com {
tls {
# 指定椭圆曲线
curves x25519 secp256r1 secp384r1
}
respond "Custom curves"
}
完整 TLS 配置 #
caddyfile
example.com {
tls {
# 协议版本
protocols tls1.2 tls1.3
# 加密套件
ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
# 曲线
curves x25519 secp256r1 secp384r1
# ALPN
alpn h2 http/1.1
# 客户端认证(可选)
client_auth {
mode require_and_verify
trusted_ca_file /etc/ssl/ca.crt
}
}
respond "Full TLS config"
}
客户端证书认证 #
要求客户端证书 #
caddyfile
example.com {
tls {
client_auth {
# 模式:request | require | verify_if_given | require_and_verify
mode require_and_verify
# 信任的 CA 证书
trusted_ca_file /etc/ssl/ca.crt
# 可选:信任的证书列表
trusted_leaf_file /etc/ssl/client.crt
}
}
respond "Client cert required"
}
客户端证书模式 #
| 模式 | 说明 |
|---|---|
request |
请求证书,但不强制 |
require |
要求证书,但不验证 |
verify_if_given |
如果提供则验证 |
require_and_verify |
要求并验证证书 |
获取客户端证书信息 #
caddyfile
example.com {
tls {
client_auth {
mode require_and_verify
trusted_ca_file /etc/ssl/ca.crt
}
}
# 获取客户端证书信息
respond "Client CN: {tls_client_subject}"
}
本地开发 HTTPS #
使用自签名证书 #
caddyfile
localhost {
tls internal
respond "Local HTTPS"
}
信任本地证书 #
bash
# 安装本地 CA 到系统信任库
caddy trust
# 或手动信任
# macOS
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ~/Library/Application\ Support/Caddy/certificates/local/localhost.crt
开发环境配置 #
caddyfile
{
# 本地开发使用内部 CA
local_certs
}
# 本地项目
project1.localhost {
tls internal
reverse_proxy localhost:3001
}
project2.localhost {
tls internal
reverse_proxy localhost:3002
}
# 使用自定义域名(需要修改 hosts 文件)
dev.example.com {
tls internal
reverse_proxy localhost:3000
}
ACME 配置 #
使用不同 CA #
caddyfile
{
# 全局配置 ACME CA
acme_ca https://acme-v02.api.letsencrypt.org/directory
}
example.com {
respond "Production CA"
}
使用测试 CA #
caddyfile
{
# 使用 Let's Encrypt 测试环境
acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}
example.com {
respond "Staging CA"
}
自定义 ACME 配置 #
caddyfile
example.com {
tls {
# 自定义 ACME 端点
issuer acme {
dir https://acme-v02.api.letsencrypt.org/directory
email admin@example.com
}
}
respond "Custom ACME"
}
ZeroSSL 证书 #
caddyfile
example.com {
tls {
issuer zerossl {
eab_kid {env.ZEROSSL_KID}
eab_hmac_key {env.ZEROSSL_HMAC_KEY}
}
}
respond "ZeroSSL certificate"
}
证书故障排查 #
常见问题 #
bash
# 1. 检查端口是否开放
sudo netstat -tlnp | grep -E ':80|:443'
# 2. 检查域名解析
dig example.com +short
# 3. 检查防火墙
sudo ufw status
# 4. 检查证书状态
curl localhost:2019/certificates | jq
# 5. 查看日志
sudo journalctl -u caddy -f
验证证书 #
bash
# 检查证书详情
openssl s_client -connect example.com:443 -servername example.com
# 检查证书过期时间
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
# 验证证书链
openssl verify -CAfile /etc/ssl/certs/ca-bundle.crt /path/to/cert.crt
常见错误解决 #
caddyfile
# 错误1:端口被占用
# 解决:检查并释放端口
# 错误2:域名未解析
# 解决:配置 DNS 解析
# 错误3:防火墙阻止
# 解决:开放端口
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# 错误4:证书获取频率限制
# 解决:使用测试 CA 或等待
{
acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}
完整示例 #
生产环境配置 #
caddyfile
{
email admin@example.com
acme_ca https://acme-v02.api.letsencrypt.org/directory
}
example.com {
tls {
protocols tls1.2 tls1.3
}
root * /var/www/html
file_server
encode gzip zstd
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
}
log {
output file /var/log/caddy/access.log
}
}
www.example.com {
redir https://example.com{uri} permanent
}
通配符证书配置 #
caddyfile
{
email admin@example.com
}
*.example.com, example.com {
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
@api host api.example.com
handle @api {
reverse_proxy localhost:3000
}
@www host www.example.com
handle @www {
root * /var/www/html
file_server
}
handle {
respond "Default handler"
}
}
双向 TLS 配置 #
caddyfile
api.example.com {
tls {
client_auth {
mode require_and_verify
trusted_ca_file /etc/ssl/ca.crt
}
}
reverse_proxy localhost:3000 {
header_up X-Client-Cert {tls_client_cert}
header_up X-Client-CN {tls_client_subject}
}
}
下一步 #
现在你已经掌握了 SSL/HTTPS 配置,接下来学习 缓存配置 了解如何优化网站性能!
最后更新:2026-03-28