# Caddy 自动 HTTPS 教程：安装、配置与续期

> 从官方源安装 Caddy 2，写两行 Caddyfile 就能自动申请 Let's Encrypt 证书、跳转 HTTPS 并自动续期，附 DNS-01 通配符配置。

Source: https://ssl.sh/zh/guides/caddy-automatic-https/
Last updated: 2026-11-10

Caddy 2 默认开启自动 HTTPS：在 Caddyfile 里把 `example.com` 和 `www.example.com` 写成站点地址，Caddy 就会自动申请证书、把 HTTP 跳转到 HTTPS，并在后台续期。

适用于 Debian、Ubuntu 和 RHEL 系 Linux 上的 Caddy 2.x，最新版本以 Caddy 官方文档为准。

## 前提条件

Caddy 自己完成 ACME 验证，所以 80 和 443 端口必须归它用。

- 带 systemd 的 Linux 服务器，有 sudo 权限。
- `example.com`、`www.example.com` 的 A/AAAA 记录指向服务器，例如 `203.0.113.10`。
- 服务器在中国大陆的，域名需已 ICP 备案。
- 防火墙和安全组对所有来源放行 TCP 80、443，且没有 Nginx、Apache 占用这两个端口。

```bash
dig +short example.com A
sudo ss -ltnp | grep -E ':(80|443) '
```

## 第一步：从官方源安装 Caddy

Caddy 官方为 Debian/Ubuntu 提供了 apt 源：

```bash
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
```

Fedora、Rocky 等系统按官方文档启用 `@caddy/caddy` COPR 源安装。装好后有一个 `caddy` systemd 服务，读取 `/etc/caddy/Caddyfile`。

## 第二步：编写 Caddyfile

把域名写成站点地址，Caddy 就会自动开启 HTTPS：

```caddy
# /etc/caddy/Caddyfile
{
    email admin@example.com
}

example.com, www.example.com {
    root * /var/www/example.com
    file_server
}
```

反向代理后端应用时，把站点块里的两行换成 `reverse_proxy 127.0.0.1:3000`。全局 `email` 可以不写，只用于 ACME 账户。

## 第三步：检查并重载

改完 Caddyfile 先格式化和校验，再重载服务，Caddy 会在重载后立即申请证书：

```bash
caddy fmt --overwrite /etc/caddy/Caddyfile
caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
sudo journalctl -u caddy --no-pager -n 50 | grep -iE 'certificate|obtain|error'
```

几秒后日志里每个域名都会出现 `certificate obtained successfully`。

## 第四步（可选）：用 DNS-01 申请通配符证书

官方包不含 DNS 模块，需要用 xcaddy 编译带模块的版本。域名在阿里云 DNS 的：

```bash
xcaddy build --with github.com/caddy-dns/alidns
```

在 Caddyfile 里引用 RAM 子账号的 AccessKey（通过 systemd 环境变量传入）：

```caddy
*.example.com, example.com {
    tls {
        dns alidns {
            access_key_id {env.ALIYUN_ACCESS_KEY_ID}
            access_key_secret {env.ALIYUN_ACCESS_KEY_SECRET}
        }
    }
    reverse_proxy 127.0.0.1:3000
}
```

各 DNS 模块的参数名以对应 caddy-dns 项目的说明为准；腾讯云 DNSPod、Cloudflare 也有对应模块。想指定 Let's Encrypt 证书配置文件，在 `tls` 块里加 `issuer acme { profile tlsserver }`（官方标为实验性），见 [Let's Encrypt 证书配置文件](https://ssl.sh/zh/guides/lets-encrypt-certificate-profiles/)。

## 验证

配置正确时，HTTP 请求返回跳转，证书颁发者是 Let's Encrypt 或 ZeroSSL。用 [SSL 证书检查](https://ssl.sh/zh/tools/ssl-checker/) 从外部检查，或在终端运行：

```bash
curl ssl.sh/example.com
```

确认跳转和实际返回的证书：

```bash
curl -sI http://example.com | head -n 3
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -issuer -dates
```

## 自动续期

续期是内置的，不需要 cron 或定时器。Caddy 会定期检查证书，CA 提供 ARI 时按建议窗口续期，否则在到期前很早就续期，新证书热替换，不断开连接。2027 年 2 月 10 日 Let's Encrypt 默认证书改为 64 天、2028 年 2 月 16 日改为 45 天，Caddy 都不需要改配置。

会让续期失败的情况：上线后关掉了 80/443、域名解析改走、删除了数据目录。定期看日志，并把域名加到 [ssl.sh 监控](https://ssl.sh/zh/monitor/)（开发中）：

```bash
sudo journalctl -u caddy --since "7 days ago" | grep -i renew
```

## 常见问题排查

- **listen tcp :443: bind: address already in use**：端口被其他程序占用（常见是宝塔装的 Nginx），停掉它或者让它退到 Caddy 后面。
- 日志里出现 `Timeout during connect` 或 `connection refused`：80/443 不通（安全组、运营商封端口、未备案拦截）或解析不对，原因和 [certbot 连接超时](https://ssl.sh/zh/errors/certbot-timeout-during-connect/) 相同。
- **too many certificates already issued**：配置有误时反复重启触发了频率限制，调试时用 `acme_ca https://acme-staging-v02.api.letsencrypt.org/directory`，见 [Let's Encrypt 频率限制](https://ssl.sh/zh/errors/lets-encrypt-rate-limit/)。
- **CAA record prevents issuance**：CAA 记录没有允许 Caddy 使用的 CA，见 [CAA 记录阻止签发](https://ssl.sh/zh/errors/caa-record-prevents-issuance/)。
- 浏览器提示证书不受信任、颁发者是 Caddy Local Authority：用了 `tls internal` 或 `localhost` 这类地址，见 [自签名证书报错](https://ssl.sh/zh/errors/mozilla-pkix-error-self-signed-cert/)。
