Caddy 之 HTTPS 配置

2022/11/6 caddy安装配置

在这个很多功能使用都要求 HTTPS 的浏览器环境下,一般站点使用 Caddy 配置代理真的很方便,不需要申请再手动配置 SSL 证书,更不需要考虑定期更新证书以免忘记更新导致站点访问报错。如果是想要了解怎么使用可以参考 Caddy 使用入门,这里主要参考 Automatic HTTPS (opens new window) 来聊聊怎么在各自场景下用 Caddy 给解析的域名配置 HTTPS 。

Caddy is the first and only web server to use HTTPS automatically and by default.

Caddy 默认情况下会给所有的站点配置 HTTPS,对本地地址使用的是自签名的证书,对公共 DNS 解析的域名使用 ACME CA(目前是 Let's Encrypt (opens new window)ZeroSSL (opens new window))提供的证书。Caddy 默认会把 HTTP 重定向到 HTTPS,更方便的一点是 Caddy 还会自动更新证书。

# 80 和 443 开放的时候

这种情况下配置 HTTPS 非常简单,简单到就是不需要做任何额外的配置,只要根据需求配置好 Caddy 然后启动就会自动配置,直接访问域名就会跳转到对应的 HTTPS 站点。

# 80 和 443 不开放的时候

如果由于某些原因不能开放 80 和 443 端口的情况下,直接按照默认配置是无法成功启用 HTTPS 的,启动的时候会给出类似下面的报错:

启动提示 ssl 错误

这是因为如果要获得受信任的 TLS 证书是需要受信任的第三方机构进行验证通过的。这种验证默认情况下是访问 80/443 端口进行验证,但是由于 80/443 端口是不可访问的,就会导致验证不通过,从而造成 SSL 证书生成失败,自然也就无法使用 HTTPS 了。

实际上 ACME protocol (opens new window) 提供了三种验证方式,Caddy 默认会随机使用 HTTP challenge 或者 TLS-ALPN challenge 中的一种进行验证。其中 HTTP challenge 是通过域名的 A/AAAA 记录找到对应的主机,然后使用 HTTP 请求通过 80 端口访问临时的加密资源,如果获取到预期的资源就会颁发证书;TLS-ALPN challenge 是对主机的 443 端口访问获取资源进行校验。两者的要求就是 80 或 443 端口开放,即使 Caddy 不能监听也要能监听端口的把对应请求转发到 Caddy 的端口上。

因此在 80 和 443 端口不能访问的情况下,只能选择第三种 DNS challengeDNS challenge 就是通过 DNS 查找到域名对应的一条特殊的 TXT解析记录,如果其解析结果是 CA 预期的值就会颁发证书。这种验证方式不需要服务器任何开放端口,并且请求证书的服务器也不需要是公网可访问的。

不过由于 DNS challenge 需要配置域名的解析,所以需要提供一些配置来让 Caddy 操作对应 DNS 服务商提供 API 来设置和清除验证用的特殊 TXT解析记录。Caddy 2 使用 新的和改进的 DNS 提供者接口 (opens new window) 处理 ACME DNS challenge。

# 获取带有 DNS 服务商插件的 Caddy

首先要获取一个安装了对应 DNS 服务商插件的 Caddy,有几种常用的方法可以获取:

# 方法一

Caddy 下载

这种方法相对比较简单,只要找到对应插件添加后下载即可。只是下载的时候需要注意选择合适的平台即可。

# 方法二

---shell xcaddy build --with github.com/caddy-dns/REPOSITORY


这种方法相对比较复杂,需要安装 xcaddy 以及对应环境等,适合高阶用户操作。

#### 方法三

除了上述两种方法外还可以使用官方提供的 docker 进行操作。后面的例子是基于官方 docker 加上要安装的插件构建想要的 Caddy。

```shell
FROM caddy:2.6.2-builder AS builder

RUN xcaddy build \
    --with github.com/caddyserver/nginx-adapter \
    --with github.com/caddy-dns/alidns

FROM caddy:2.6.2

COPY --from=builder /usr/bin/caddy /usr/bin/caddy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

如果使用 docker 的话,这种方法相对来说是最简单的,都是基于官方 docker 进行操作。

# 方法四

如果没有找到对应 DNS 提供商,也可以参考 这里 (opens new window) 提供的方案。(注意:该方案未实际操作

# 启用 DNS challenge

按照上述操作获取了一个带有 DNS 服务商插件的 Caddy 后只需在配置中启用 DNS challenge 即可。

# 全局选项(对所有站点使用)

在 Caddyfile 的顶部使用 全局 acme_dns 选项 (opens new window) 进行配置:

{
    acme_dns <provider> ...
}

# 例如
{
    acme_dns alidns {
      access_key_id {env.ALIYUN_ACCESS_KEY_ID}
      access_key_secret {env.ALIYUN_ACCESS_KEY_SECRET}
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 站点单独配置

如果是为了指定站点配置,可以在站点的配置项中加上 tls 指令 (opens new window)

tls {
    dns <provider> ...
}
# 例如
tls {
  dns alidns {
    access_key_id {env.ALIYUN_ACCESS_KEY_ID}
    access_key_secret {env.ALIYUN_ACCESS_KEY_SECRET}
  }
}
1
2
3
4
5
6
7
8
9
10

如果您的凭据在环境中,您也可以使用 {env.*) 占位符。不同 DNS 服务商插件的配置项可能会有所区别,根据对应文档进行配置即可。

# JSO 配置

如果使用 JSON,请使用 颁发者配置自动化策略 acme58 (opens new window) 设置:

{
  "module": "acme",
  "challenges": {
    "dns": {
      "provider": {
        "name": "alidns",
        "access_key_id":"YOUR_ALIYUN_ACCESS_KEY_ID",
        "access_key_secret":"YOUR_ALIYUN_ACCESS_KEY_SECRET"
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 禁用自动 HTTPS

上面都是怎么自动配置 HTTPS 的,那如果就是想要一个 HTTP 站点呢,也是可以的:

  • 在配置文件中明确禁用,配置 auto_https 属性
    • off:完全禁用
    • disable_redirects: 仅禁用 HTTP 到 HTTPS 重定向
    • disable_certs:仅禁用证书自动化
    • ignore_loaded_certs:即使手动加载证书,也执行证书自动化
  • 不在配置中提供任何主机名或 IP 地址
  • 专门监听 HTTP 端口
  • 在配置中为网站地址加上前缀 http://
  • 手动加载证书(除非设置了 ignore_loaded_certificates)

对于简单的站点,用 Caddy 实现 HTTPS 的确是个不错的选择!