我有一个 Raspberry Pi,其设置包括 PiHole 和球童。
PiHole 用作网络的本地 DNS 服务器,而 caddy 用作通用相应服务上的反向代理。
示例:
192.168.2.71 nextcloud.foo.duckdns.org
nextcloud.foo.duckdns.org { reverse_proxy localhost:11000 }
$ curl --head --verbose https://nextcloud.foo.duckdns.org
* Trying [2a02:a458:814f:0:a438:1aab:a24:12f7]:443...
* Trying 192.168.2.71:443...
* Connected to nextcloud.foo.duckdns.org (192.168.2.71) port 443 (#0)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN: server accepted h2
* Server certificate:
* subject: CN=nextcloud.foo.duckdns.org
* start date: May 1 05:58:44 2024 GMT
* expire date: Jul 30 05:58:43 2024 GMT
* subjectAltName: host "nextcloud.foo.duckdns.org" matched cert's "nextcloud.foo.duckdns.org"
* issuer: C=US; O=Let's Encrypt; CN=R3
* SSL certificate verify ok.
在 Caddyfile 中,我还有一个全局选项/块,
{ acme_dns duckdns <my-token> }
,并且我还使用本指南通过 Let's Encrypt 生成了有效的证书:https://github.com/infinityofspace/certbot_dns_duckdns?tab=readme- ov-文件#用法
此证书包含“foo.duckdns.org”和“*.foo.duckdns.org”作为域。
但是现在,我设置了另一项服务,家庭助理,并在 Caddyfile 中添加了一个条目,即
homeassistant.foo.duckdns.org { reverse_proxy localhost:8123 }
。
问题在于 TLS 握手失败,因此 HTTPS 请求失败。
curl --head --verbose https://homeassistant.foo.duckdns.org
* Trying 192.168.2.71:443...
* Connected to homeassistant.foo.duckdns.org (192.168.2.71) port 443 (#0)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS alert, internal error (592):
* OpenSSL/3.0.11: error:0A000438:SSL routines::tlsv1 alert internal error
* Closing connection 0
curl: (35) OpenSSL/3.0.11: error:0A000438:SSL routines::tlsv1 alert internal error
不过,我仍然可以通过本地主机接口访问该服务。
$ curl --verbose 192.168.2.71:8123
* Trying 192.168.2.71:8123...
* Connected to 192.168.2.71 (192.168.2.71) port 8123 (#0)
> GET / HTTP/1.1
> Host: 192.168.2.71:8123
> User-Agent: curl/7.88.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Referrer-Policy: no-referrer
< X-Content-Type-Options: nosniff
< Server:
< X-Frame-Options: SAMEORIGIN
< Content-Length: 4116
< Date: Sat, 04 May 2024 15:19:24 GMT
<
< HTML response
为什么会出现这种差异?我还尝试运行 sudo certbot renew 但该工具显示证书尚未到期更新
与此请求相关的球童日志是:
May 04 17:07:55 raspberrypi caddy[2499813]: {"level":"debug","ts":1714835275.669332,"logger":"http.stdlib","msg":"http: TLS handshake error from 172.24.0.8:52236: EOF"}
May 04 17:07:56 raspberrypi caddy[2499813]: {"level":"error","ts":1714835276.0812566,"logger":"tls.issuance.zerossl.acme_client","msg":"cleaning up solver","identifier":"homeassistant.foo.duckdns.org","challenge_type":"dns-01","error":"no memory of presenting a DNS record for \"_acme-challenge.homeassistant.foo.duckdns.org\" (usually OK if presenting also failed)"}
May 04 17:07:56 raspberrypi caddy[2499813]: {"level":"debug","ts":1714835276.4435985,"logger":"tls.issuance.zerossl.acme_client","msg":"http request","method":"POST","url":"https://acme.zerossl.com/v2/DV90/authz/PyhpCsoS_EhSSiEGi8UeIQ","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.7.6 CertMagic acmez (linux; arm64)"]},"response_headers":{"Access-Control-Allow-Origin":["*"],"Cache-Control":["max-age=0, no-cache, no-store"],"Content-Length":["145"],"Content-Type":["application/json"],"Date":["Sat, 04 May 2024 15:07:56 GMT"],"Link":["<https://acme.zerossl.com/v2/DV90>;rel=\"index\""],"Replay-Nonce":["igkSNJLHTzdfI2aSomwLOusaK7Fz3HQEHXL8NYrFcWA"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]},"status_code":200}
May 04 17:07:56 raspberrypi caddy[2499813]: {"level":"error","ts":1714835276.4437563,"logger":"tls.obtain","msg":"could not get certificate from issuer","identifier":"homeassistant.foo.duckdns.org","issuer":"acme.zerossl.com-v2-DV90","error":"[homeassistant.foo.duckdns.org] solving challenges: presenting for challenge: could not determine zone for domain \"_acme-challenge.homeassistant.foo.duckdns.org\": unexpected response code 'REFUSED' for _acme-challenge.homeassistant.foo.duckdns.org. (order=https://acme.zerossl.com/v2/DV90/order/uQxNVkgga-pcqKOgZWOJiA) (ca=https://acme.zerossl.com/v2/DV90)"}
May 04 17:07:56 raspberrypi caddy[2499813]: {"level":"debug","ts":1714835276.4437943,"logger":"events","msg":"event","name":"cert_failed","id":"9ff6162d-a94e-497f-aff9-5d068ddc2987","origin":"tls","data":{"error":{},"identifier":"homeassistant.foo.duckdns.org","issuers":["acme-v02.api.letsencrypt.org-directory","acme.zerossl.com-v2-DV90"],"renewal":false}}
May 04 17:07:56 raspberrypi caddy[2499813]: {"level":"error","ts":1714835276.4438388,"logger":"tls.obtain","msg":"will retry","error":"[homeassistant.foo.duckdns.org] Obtain: [homeassistant.foo.duckdns.org] solving challenges: presenting for challenge: could not determine zone for domain \"_acme-challenge.homeassistant.foo.duckdns.org\": unexpected response code 'REFUSED' for _acme-challenge.homeassistant.foo.duckdns.org. (order=https://acme.zerossl.com/v2/DV90/order/uQxNVkgga-pcqKOgZWOJiA) (ca=https://acme.zerossl.com/v2/DV90)","attempt":13,"retrying_in":1800,"elapsed":9168.216986793,"max_duration":2592000}
这与证书验证无关。这不是客户端抱怨服务器证书,而是服务器抱怨来自客户端的某些内容。因此,服务器会将 TLS 警报发送回客户端:
* TLSv1.3 (IN), TLS alert, internal error (592):
* OpenSSL/3.0.11: error:0A000438:SSL routines::tlsv1 alert internal error
不过,我仍然可以通过本地主机接口访问该服务。
$ curl --verbose 192.168.2.71:8123
这不是进行 HTTPS 请求,而是普通的 HTTP 请求。这意味着没有完成 TLS,因此也不会发生 TLS 相关错误。
与此请求相关的球童日志是:
... "tls.obtain","msg":"could not get certificate from issuer","identifier":"homeassistant.foo.duckdns.org", ...
这表明内部服务器已设置为自动获取此子域的证书(即未设置为使用现有通配符),但无法检索证书。
这也解释了握手错误:服务器因 TLS 握手而失败,因为它没有所请求域的可用证书。