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 challenge。DNS 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 的确是个不错的选择!