apernet / hysteria

Hysteria is a powerful, lightning fast and censorship resistant proxy.
https://v2.hysteria.network/
MIT License
14.61k stars 1.63k forks source link

特定环境下,hysteria的acme_client申请证书失败 #804

Open iocharset opened 10 months ago

iocharset commented 10 months ago

描述问题 服务器有一个ipv4和一个ipv6的地址,ipv4上caddy监听80和443,跑了一个简单的网站。ipv6上跑hysteria服务。 caddy只监听ipv4的80和443端口,hysteria只监听ipv6的443。

hysteria启动,申请证书的时候,日志输出警告消息: [WARNING] OS reports a contradiction: listen tcp :443: bind: address already in use - but we cannot connect to it, with this error: dial tcp :443: connect: connection refused; continuing anyway 🤞 (I don't know what causes this... if you do, please help?) 紧接着,后面发起的tls-alpn-01 challenge失败:Connection refused。

[WARNING] OS reports a contradiction: listen tcp :80: bind: address already in use - but we cannot connect to it, with this error: dial tcp :80: connect: connection refused; continuing anyway 🤞 (I don't know what causes this... if you do, please help?) 同样的,http-01 challenge也失败:Connection refused。

当我停止caddy服务后,再运行hysteria,证书申请成功,hysteria也得以正常运行。

原因推测 虽然我在hysteria的配置文件中指定了监听的ipv6地址,但当hysteria发起challenge的时候,似乎没有使用我指定的ipv6地址,而是使用 :80 和 :443 ,从而与ipv4上监听的caddy冲突,出现address already in use的警告,最终导致证书申请失败。

预期行为 我认为在ipv4上运行的caddy,不应该和在ipv6上运行的hysteria冲突,hysteria应该用我配置文件中指定的ipv6地址发起challenge,申请证书。

leic4u commented 10 months ago

acme 申请证书时,必须要用 80 端口。发起 HTTP-01 challenge 和 IP 地址也没有关系,主要和你的域名及解析有关。参见:https://letsencrypt.org/docs/challenge-types/

你想 IPv4 和 IPv6 分开,那你的域名应该分成 2 个,一个 a.example.com 使用 A 解析到IPv4 地址,b.example.com 使用 AAAA 解析到 IPv6 地址。

然后你就可以用 b.example.com 来安装并启动 hysteria 服务了。

iocharset commented 10 months ago

acme 申请证书时,必须要用 80 端口。发起 HTTP-01 challenge 和 IP 地址也没有关系,主要和你的域名及解析有关。参见:https://letsencrypt.org/docs/challenge-types/

你想 IPv4 和 IPv6 分开,那你的域名应该分成 2 个,一个 a.example.com 使用 A 解析到IPv4 地址,b.example.com 使用 AAAA 解析到 IPv6 地址。

然后你就可以用 b.example.com 来安装并启动 hysteria 服务了。

我的域名解析的设置是没问题的, 跟你说的一模一样:a.example.com 使用 A 解析到IPv4 地址,b.example.com 使用 AAAA 解析到 IPv6 地址。

实际上,你从日志可以看到,根本原因是端口冲突,我ipv6上的对应端口没有被占用,只有ipv4上的80,443被占用。

hysteria发起challenge的时候,用的不是我指定的ipv6:80和ipv6:443来发送数据,而是:80和:443,这才导致失败。

leonaacn commented 10 months ago

altHTTPPort: 8080 altTLSALPNPort: 4443 在80和443端口被占用不可用的情况下,我设置了备用端口,但是日志还是显示acme申请证书失败,是我对这两个配置理解有错误吗

leic4u commented 10 months ago

altHTTPPort: 8080 altTLSALPNPort: 4443 在80和443端口被占用不可用的情况下,我设置了备用端口,但是日志还是显示acme申请证书失败,是我对这两个配置理解有错误吗

是的,验证必须在 80 和 443 展开,如果占用 80 和 443 端口的是 Nginx,你可以设置一个反向代理,把 80 和 443端口来的验证流量转发给你的 8080 端口。

    location /.well-known/acme-challenge {
        proxy_set_header Host $host;
        proxy_set_header X-Real_IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
        proxy_pass http://127.0.0.1:8080;
    }
toyo2333 commented 7 months ago

提供一个解决思路:全部用docker

这样最终你看到的机器上就是:

  1. TCP443被caddy占用,用于caddy自己去完成证书挑战和反代工作
  2. UDP443端口是hy工作用的的,而hy去挑战的时候就又可以成功走80端口,因为主机的80端口没有被占用。

这样做有一个弊端,就是因为caddy没有接管80端口,导致直接用http访问caddy反代的域名时候无法由caddy完成自动跳转到https的动作(表现就是网页打不开)

对于这个小问题解决方案是:caddy的域名交给Cloudflare的小黄云,并在Cloudflare开启Always Use HTTPS.

完美。

toyo2333 commented 7 months ago

还可以使用caddy的 DNS 挑战 来获取证书。这就和端口无关了。更简单。