X

Letsencrypt: Timeout during connect (likely firewall problem)

Получил сообщение, что на одном из доменов вскоре закончится сертификат LetsEncrypt. Это было странно, тк на сервере настроено автообновление. Не беда, подумал я, надо сходить на сервер и запустить обновление вручную. Так я и поступил, однако наткнулся на ошибку: Timeout during connect (likely firewall problem) ..

Выглядело это так

$ certbot renew

....

 - The following errors were reported by the server:

   Domain: node-02.site.com
   Type:   connection
   Detail: Fetching
   https://node-02.site.com/.well-known/acme-challenge/vXQ44vt4_faINmMp3-h0Acpj-o-MDGVQMwUrjztmOsM:
   Timeout during connect (likely firewall problem)

   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. Additionally, please check that
   your computer has a publicly routable IP address and that no
   firewalls are preventing the server from communicating with the
   client. If you're using the webroot plugin, you should also verify
   that you are serving files from the webroot path you provided.

Т.к. сам домен работал, причем все еще с сертификатом от Letsencrypt (он истекал, но еще не истек), я был уверен в том, что с DNS записями все ок. Из сообщения ясно, что LetsEncrypt не смог выкачать "challenge" файл в момент валидации. Т.к. я уже сталкивался с подобным и проблема была в настройке пути к папке в конфигурации nginx, я первым делом создал этот файл вручную и попробовал открыть его в браузере.

  • https://node-02.site.com/.well-known/acme-challenge/vXQ44vt4_faINmMp3-h0Acpj-o-MDGVQMwUrjztmOsM

Файл был доступен. Т.е. это действитльно было похоже на то, что проблема в файрволле. На следующем шаге, я очистил все правила iptables и попробовал снова - не помогло. Тогда я попробовал проверить с сервера который находился у другого провайдера - файл был доступен...

Из всего этого получалось, что блокировка срабатывает где-то до моего сервера, причем распространяется она только на запросы с letsencrypt серверов .. теория интересная, но маловероятная. Тем не менее я решил ее проверить, сервер находится у Hetzner и в панели Robot для Dedicated серверов есть свой файрвол. В нем не было никаких записей, но я его решил отключить..

Hetzner Robot Firewall

К сожалению, это тоже не помогло, certbot возвращал ту же ошибку.

Дальше, я около часа гуглил и искал решение. В одном из постов,я наткнулся на сайт: https://letsdebug.net . Я ввел свой домен и получил занятное сообщение

AAAA - Not Working
ERROR
node-02.site.com has an AAAA (IPv6) record (2a01:4f8:162:6350::2) 
but a test request to this address over port 80 did not succeed. 
Your web server must have at least one working IPv4 or IPv6 address. 
You should either ensure that validation requests to this domain 
succeed over IPv6, or remove its AAAA record.

A timeout was experienced while communicating with 
node-02.site.com/2a01:4f8:162:6350::2: 
Get "http://node-02.site.com/.well-known/acme-challenge/letsdebug-test": 
dial tcp [2a01:4f8:162:6350::2]:80: i/o timeout

Trace:
@0ms: Making a request to http://node-02.site.com/.well-known/acme-challenge/letsdebug-test (using initial IP 2a01:4f8:162:6350::2)
@0ms: Dialing 2a01:4f8:162:6350::2
@10000ms: Experienced error: dial tcp [2a01:4f8:162:6350::2]:80: i/o timeout

Из этого сообщения стало ясно, что LetsEncrypt не может провалидировать запрос который делает по IPv6. Это обясняло почему у меня все работает, а у letsEncrypt нет. Дело в том, что мой ПК использует IPv4, как и другой сервер, с которого я проводил тесты.

Далее, я попробовал сделать запрос http с моего другого сервера, где был настроен IPv6, пинг не прошел

# curl -6 -i --max-time 15 'http://node-02.site.com'
curl: (28) Connection timed out after 15001 milliseconds

запрос не прошел. Тогда я пошел на сервер и убедился, что nginx ничего не блочит и правильно настроен, я получил ответ

$ curl -6 -i --max-time 15 'http://node-02.site.com'

HTTP/1.1 301 Moved Permanently
Server: nginx/1.14.1
Date: Mon, 24 Aug 2020 11:38:27 GMT
Content-Type: text/html
Content-Length: 185
Connection: keep-alive
Location: https://node-02.site.com/

Т.е. в моем случае была ситуация, когда nginx настроен, но по какой-то странной причине не был доступен из вне. Я проверил настройки сети, открытые порты, iptables для IPv6, все было в норме

$ sysctl -a | grep ipv6.*disable
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.all.disable_policy = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.default.disable_policy = 0
net.ipv6.conf.enp4s0.disable_ipv6 = 0
net.ipv6.conf.enp4s0.disable_policy = 0
net.ipv6.conf.lo.disable_ipv6 = 0
net.ipv6.conf.lo.disable_policy = 0


$ cat /etc/sysconfig/network-scripts/ifcfg-enp4s0 
### Hetzner Online GmbH installimage

DEVICE=enp4s0
ONBOOT=yes
BOOTPROTO=none

IPV6INIT=yes
IPV6ADDR=2a01:4f8:162:6350::2/64
IPV6_DEFAULTGW=fe81::1
IPV6_DEFROUTE=yes


$ netstat -tulpn | grep '443\|80'
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      1179/nginx: master  
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1179/nginx: master  
tcp6       0      0 :::443                  :::*                    LISTEN      1179/nginx: master  
tcp6       0      0 :::80                   :::*                    LISTEN      1179/nginx: master


$ ip6tables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Я попробовал достучаться с двух внешних сервисов

  • По IP: http://www.ipv6now.com.au/pingme.php
  • По домену: http://ipv6-test.com/validate.php

Но, получил все ту же ошибку..

Я уже собрался писать в поддержку Hetzner, но решил сперва попробовать рецепт №1 от всех компьютерных проблем - перезагрузка. Я остановил все нужные сервисы и убедился что балансер перевел запросы на другой сервер. Далее, чтобы не терять момент, я установил обновления пакетов и перезагрузился. Сразу после перезагрузки, я попробовал сделать пинг с другого своего сервер, но сервер по ipv6 все еще не был доступен.

Я решил установить traceroute и попробовать посмотреть на каком сервере "падает" запрос. После установки traceroute я обнаружил, что пинг проходит и нигде не падает. Я снова попробовал сделать запрос со своего сервера и на этот раз он прошел успешно. Далее, я проверил, через упомянутые сервисы и убедился, что коннект по IPv6 начал работать.

Я перезапустил обновление сертификата и в этот раз все прошло успешно, сертификат был обновлен.

Выводы

Как видите, я тут столкнулся с тем, что ошибка в certbot не была информативна для меня и я сразу не понял, что проблема в IPv6 адресе. Т.к. IPv6 на сервере используется по большей части для того, чтобы корректно работала валидация Gmail, то о проблеме я даже не подозревал.

Возвращаясь, к тому, что же произошло и почему коннект отвалился. Я предполагаю, что у Hetzner-а были какиу-то инфраструктурные изменения в маршрутизации и для моего сервера попросту отвалился роут по IPv6. Когда я сделал перезагрузку, сработал триггер и через пару минут, роут был добавлен и коннект появился. Это мое основное предположение. Другой, вариант, что в одном из пакетов был баг и что-то подвисло. Обновление пакетов и перезагрузка, решили эту проблему.

Как бы там не было, мой проблема решена. А когда вы столкнетесь с ошибкой: Timeout during connect (likely firewall problem) при обновлении сертификата, просто убедитесь что у Вас все ок с IPv6 и "challenge" файл доступен по этому протоколу.