46

Let’s Encrypt renew出现“Challenge failed for domain xxxx”

 4 years ago
source link: https://www.tuicool.com/articles/6BziMzr
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

某个私用的子域名上了Let’s Encrypt签发的证书,上周用 renew 命令延长证书有效期时出现下面的错误:

Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/xxx.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator standalone, Installer None
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for xxxx
Waiting for verification...
----------------------------------------
Exception happened during processing of request from ('::ffff:66.133.109.36', 45260, 0, 0)
Traceback (most recent call last):
  File "/usr/lib64/python2.7/SocketServer.py", line 295, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/lib64/python2.7/SocketServer.py", line 321, in process_request
    self.finish_request(request, client_address)
  File "/usr/lib64/python2.7/SocketServer.py", line 334, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib/python2.7/site-packages/acme/standalone.py", line 207, in __init__
    BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
  File "/usr/lib64/python2.7/SocketServer.py", line 651, in __init__
    self.finish()
  File "/usr/lib64/python2.7/SocketServer.py", line 710, in finish
    self.wfile.close()
  File "/usr/lib64/python2.7/socket.py", line 279, in close
    self.flush()
  File "/usr/lib64/python2.7/socket.py", line 303, in flush
    self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 32] Broken pipe
----------------------------------------
Challenge failed for domain xxxx
http-01 challenge for xxxx
Cleaning up challenges
Attempting to renew cert (xxxx) from /etc/letsencrypt/renewal/xxxx.conf produced an unexpected error: Some challenges have failed.. Skipping.
All renewal attempts failed. The following certs could not be renewed:
  /etc/letsencrypt/live/xxxx/fullchain.pem (failure)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

All renewal attempts failed. The following certs could not be renewed:
  /etc/letsencrypt/live/xxxx/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 renew failure(s), 0 parse failure(s)

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: xxxx
   Type:   unauthorized
   Detail: Invalid response from
   http://xxxx/.well-known/acme-challenge/vQ5zuvoh188fvC0GE8U5KnJ5yQMf1GamNzJCW-Ho-D8
   [xxx.xxx.xxx.xxx]: "<html>\n<head>\n<meta
   http-equiv=\"Content-Type\" content=\"textml;charset=UTF-8\" />\n
   <style>body{background-color:#FFFFFF}</style>"

   To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A/AAAA record(s) for that domain
   contain(s) the right IP address.

一直以来用的好好的,这次突然撂挑子不干了,简直莫名其妙。根据错误信息排查潜在问题,都没毛病:

  1. ip已经正确解析,错误信息和log中可以验证这点;
  2. 绑定80端口也没问题,已经停止了Nginx;
  3. certbot已经升级到了最新版本;
  4. 用Python3.6的pip重新安装certbot并尝试,问题依旧。

自行尝试加上网找方案,一番折腾无果后暂时放弃了。心想也许是服务端抽风,说不定过几天就好了。

今天再次尝试续期证书,还是同样的问题。意识到这应该不是服务端问题,不然肯定引起大面积反应了,配置或者使用上有新问题的可能性更大。

用”invalid response”等关键字搜不出什么有用的结果。过了一会后忽然想到抛出异常中的 “::ffff:66.133.109.36” 这个ip是什么玩意?复制ip上Google查询,竟然直接找到了问题原因:用于验证域名的80端口被阿里云拦截了,certbot收到的返回与预期不符合,于是提示“hallenge failed for domain xxxx”的错误。至于这个ip,应该是阿里云上层防火墙的公共ip。

接着自己尝试用80端口访问域名,果然出现拦截的页面,画风如下:

yumingtishi.jpg

知道了问题的原因,找解决办法还是挺容易的。个人能想到的三种解决办法是:

  1. 域名备案;这个不用说了吧,说多了也不好;
  2. 暂时将域名解析到境外服务器,获取到证书更新后再解析回来;
  3. 域名验证从http改成dns。

前两个办法比较简单,本文就不多说了。这里说一下用dns方式验证域名的步骤。

dns验证有两个重要参数:

  • –preferred-challenges,验证方式,填写dns或dns-01;
  • –server, 验证服务器,填写https://acme-v02.api.letsencrypt.org/directory

还有一个 --manual 参数,但在“非交互式”环境下,必须同时指定 --manual-auth-hook 选项。什么是“非交互式”环境? renew 就是非交互式环境,因为不需要外部输出和参与;而 certonly (一般)是交互式的,因为执行过程中需要用户输入必要的信息。

本人没看 auth-hook 脚本的写法,所以用dns方式 renew 证书是不可行了。那就干脆重新再获取一次证书吧!输入命令:

certbot renew -d 域名 --preferred-challenges dns --manual --server https://acme-v02.api.letsencrypt.org/directory

命令会询问是否同意记录当前机器的ip,选“y”(当然个人认为选n也没问题)。接着命令会输出dns记录的验证信息,按照指定值在dns控制台加上 TXT 记录。dns记录添加完成后等半分钟左右让记录生效,然后按回车键,记录无误的话证书就生成了。

感谢伟大的防火墙和备案机制,又让我长见识了!

参考

  1. Invalid response use certbot in ubuntu
  2. Let’s Encrypt 免费通配符 SSL 证书申请教程

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK