Как я восстановил Let's Encrypt для mail.examle.com и исправил подключение Thunderbird к старому Dovecot/Postfix
В этой статье я разберу реальный случай с почтовым сервером mail.examle.com.
Сервер достаточно старый:
- Dovecot 2.0.9;
- OpenSSL 1.0.1e-fips;
- старый Postfix;
- nginx;
- Let's Encrypt через устаревший
letsencrypt-auto.
Проблема началась с того, что перестало нормально проходить обновление сертификата Let's Encrypt, а после его получения Thunderbird всё равно не хотел подключаться к почтовому серверу.
В итоге оказалось, что здесь наложились сразу несколько независимых проблем:
- nginx перенаправлял запрос проверки Let's Encrypt с HTTP на HTTPS;
certbot-autoуже официально не поддерживается;- Dovecot использовал устаревшие 1024-битные DH-параметры;
- SMTP на порту 465 согласовывал древний TLS 1.0;
- Thunderbird нормально заработал после перехода SMTP на порт 587 с STARTTLS.
Ниже покажу всю диагностику по порядку.
Исходная ошибка Let's Encrypt
Я запускал получение сертификата следующим образом:
Bash:
./letsencrypt-auto certonly \
-a webroot \
--agree-tos \
--renew-by-default \
--webroot-path=/usr/www/mail \
-d mail.examle.com
Certbot сразу предупреждал:
Код:
Your system is not supported by certbot-auto anymore.
certbot-auto and its Certbot installation will no longer receive updates.
Это отдельная проблема:
certbot-auto давно устарел и больше не получает обновлений.Но непосредственно выпуск сертификата ломался по другой причине:
Код:
Challenge failed for domain mail.examle.com
Domain: mail.examle.com
Type: connection
Detail: 192.145.97.65: Fetching
https://mail.examle.com/.well-known/acme-challenge/...
Error getting validation data
Особенно важной здесь была строка:
Код:
Fetching https://mail.examle.com/.well-known/acme-challenge/...
Для HTTP-01 challenge проверка первоначально приходит по HTTP, то есть на порт 80.
Почему nginx ломал ACME challenge
В конфигурации
mail.examle.com у меня был такой редирект:
NGINX:
if ($scheme = http) {
return 301 https://$server_name$request_uri;
}
Одновременно был location для Let's Encrypt:
NGINX:
location ~ /.well-known {
root /usr/www/mail;
allow all;
}
На первый взгляд всё выглядело правильно.
Но серверный
return 301 отправлял в HTTPS в том числе запросы:
Код:
http://mail.examle.com/.well-known/acme-challenge/...
В результате получалась цепочка:
Код:
HTTP :80
↓
301 Redirect
↓
HTTPS :443
↓
ошибка проверки ACME
Правильная конфигурация nginx для ACME
Я разделил HTTP и HTTPS.
Для HTTP оставил отдельный server:
NGINX:
server {
listen 192.145.97.65:80;
server_name mail.examle.com;
location ^~ /.well-known/acme-challenge/ {
root /usr/www/mail;
default_type text/plain;
try_files $uri =404;
allow all;
}
location / {
return 301 https://mail.examle.com$request_uri;
}
}
Таким образом:
- обычные HTTP-запросы перенаправляются на HTTPS;
/.well-known/acme-challenge/остаётся доступным непосредственно по HTTP.
А HTTPS работает отдельно:
NGINX:
server {
listen 192.145.97.65:443 ssl;
server_name mail.examle.com;
ssl_certificate /etc/letsencrypt/live/mail.examle.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mail.examle.com/privkey.pem;
# Остальная конфигурация сайта
}
Проверка webroot вручную
Перед новым запуском Let's Encrypt я решил проверить, действительно ли nginx отдаёт файлы из нужного каталога.
Создал тестовый файл:
Bash:
mkdir -p /usr/www/mail/.well-known/acme-challenge
echo "acme-test-ok" \
> /usr/www/mail/.well-known/acme-challenge/test.txt
Проверил nginx:
Bash:
nginx -t
После чего перезагрузил конфигурацию:
Bash:
service nginx reload
И проверил с помощью curl:
Bash:
curl -i http://mail.examle.com/.well-known/acme-challenge/test.txt
Правильный результат:
Код:
HTTP/1.1 200 OK
acme-test-ok
При этом не должно происходить:
Код:
301 Moved Permanently
Location: https://mail.examle.com/...
Также можно проверить непосредственно backend:
Bash:
curl -i \
-H 'Host: mail.examle.com' \
http://192.145.97.65/.well-known/acme-challenge/test.txt
После этого сертификат Let's Encrypt успешно выпустился.
Проверяю новый сертификат
Проверил симлинки:
Bash:
ls -la /etc/letsencrypt/live/mail.examle.com/
В моём случае они уже указывали на свежие файлы сертификата:
Код:
cert.pem
chain.pem
fullchain.pem
privkey.pem
Затем:
Bash:
openssl x509 \
-in /etc/letsencrypt/live/mail.examle.com/fullchain.pem \
-noout \
-subject \
-issuer \
-dates
Сертификат был корректный:
Код:
subject=/CN=mail.examle.com
issuer=/C=US/O=Let's Encrypt/...
То есть проблема непосредственно с Let's Encrypt была решена.
Thunderbird всё равно ругается
После обновления сертификата Thunderbird поначалу продолжал показывать окно добавления исключения безопасности для:
Код:
mail.examle.com:993
Я решил не добавлять исключение, а проверить сервер.
И это правильный подход: если сервер должен использовать нормальный сертификат Let's Encrypt, создавать постоянное исключение в почтовом клиенте не нужно.
Проверяю IMAPS на порту 993
Сначала проверил, слушает ли порт Dovecot:
Bash:
netstat -lntp | grep ':993'
Результат:
Код:
tcp 0 0 0.0.0.0:993 0.0.0.0:* LISTEN dovecot
Затем проверил TLS локально:
Bash:
openssl s_client \
-connect 127.0.0.1:993 \
-servername mail.examle.com \
-showcerts </dev/null
И по DNS-имени:
Bash:
openssl s_client \
-connect mail.examle.com:993 \
-servername mail.examle.com \
-showcerts </dev/null
В обоих случаях сертификат был правильным:
Код:
subject=/CN=mail.examle.com
issuer=/C=US/O=Let's Encrypt/...
Verify return code: 0 (ok)
То есть:
- порт 993 доступен;
- Dovecot работает;
- сертификат правильный;
- цепочка сертификатов валидна.
Проверяю конфигурацию Dovecot
Проверил:
Bash:
dovecot -n 2>&1 | grep -Ei 'ssl|cert|key|listen|protocol'
Получил:
Код:
listen = *
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.examle.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.examle.com/privkey.pem
protocol imap {
То есть Dovecot уже использовал именно новый Let's Encrypt.
Версия оказалась очень старой:
Bash:
dovecot --version
Результат:
Код:
2.0.9
Обнаруживаю ещё одну проблему: DH 1024
При TLS-подключении OpenSSL показывал:
Код:
Server Temp Key: DH, 1024 bits
Проверил настройки:
Bash:
doveconf -a | grep -i dh
Получил:
Код:
ssl_dh_parameters_length = 1024
Полные SSL-настройки выглядели примерно так:
Код:
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.examle.com/fullchain.pem
ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL
ssl_dh_parameters_length = 1024
ssl_key = </etc/letsencrypt/live/mail.examle.com/privkey.pem
ssl_parameters_file = ssl-parameters.dat
ssl_parameters_regenerate = 0
ssl_protocols = !SSLv2 !SSLv3
В
/etc/dovecot/conf.d/10-ssl.conf при этом находилась строка:
Код:
#ssl_dh_parameters_length = 1024
То есть использовалось значение по умолчанию.
Для такого старого сервера разумно увеличить DH хотя бы до 2048:
Код:
ssl_dh_parameters_length = 2048
После изменения:
Bash:
service dovecot restart
Проверить результат можно так:
Bash:
openssl s_client \
-connect mail.examle.com:993 \
-servername mail.examle.com \
</dev/null 2>&1 |
egrep 'Server Temp Key|Protocol|Cipher|Verify return'
В идеале:
Код:
Server Temp Key: DH, 2048 bits
Protocol : TLSv1.2
Verify return code: 0 (ok)
ECDHE старый Dovecot не использовал
Сам OpenSSL на сервере поддерживал ECDHE:
Bash:
openssl ciphers -v | grep ECDHE
Например:
Код:
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-RSA-AES256-SHA
Но при принудительном подключении:
Bash:
openssl s_client \
-connect mail.examle.com:993 \
-servername mail.examle.com \
-cipher 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA' \
</dev/null
Dovecot отвечал:
Код:
sslv3 alert handshake failure
no peer certificate available
Cipher is (NONE)
То есть наличие ECDHE в OpenSSL ещё не означает, что конкретная старая версия Dovecot будет его нормально использовать.
Проблема оказалась ещё и в SMTP
После исправления сертификата Thunderbird всё равно не мог завершить автоматическую проверку учётной записи.
Настройки были такими:
Код:
IMAP:
mail.examle.com
993
SSL/TLS
SMTP:
mail.examle.com
465
SSL/TLS
Я проверил открытые порты:
Bash:
netstat -lntp | egrep ':(465|587|993)\s'
Все необходимые службы слушали:
Код:
0.0.0.0:993
0.0.0.0:587
0.0.0.0:465
Следовательно, дело было не в закрытом порте.
Проверяю SMTP 465
Запустил:
Bash:
openssl s_client \
-connect mail.examle.com:465 \
-servername mail.examle.com \
-showcerts </dev/null
Сертификат снова был правильный:
Код:
subject=/CN=mail.examle.com
issuer=/C=US/O=Let's Encrypt/...
Verify return code: 0 (ok)
Но в конце обнаружилось главное:
Код:
Server Temp Key: DH, 1024 bits
Protocol : TLSv1
Cipher : DHE-RSA-AES256-SHA
То есть SMTP на 465 порту договаривался всего лишь о:
Код:
TLS 1.0
Для современного Thunderbird это уже слишком старый TLS.
Почему порт 465 не работал в Thunderbird
Сам порт был открыт.
Сертификат был валиден.
DNS был правильным.
Но сервер предлагал старый TLS:
Код:
TLSv1
DHE
DH 1024 bit
Современный Thunderbird такие настройки по умолчанию уже не принимает.
Поэтому я не стал ослаблять настройки безопасности Thunderbird.
Вместо этого проверил второй стандартный SMTP submission порт — 587.
Окончательное решение: SMTP 587 + STARTTLS
В Thunderbird я изменил только настройки сервера исходящей почты.
Было:
Код:
Сервер: mail.examle.com
Порт: 465
Защита соединения: SSL/TLS
Стало:
Код:
Сервер: mail.examle.com
Порт: 587
Защита соединения: STARTTLS
После этого Thunderbird сразу успешно проверил настройки, и почтовый ящик заработал.
Моя итоговая конфигурация Thunderbird
Входящая почта — IMAP
Код:
Протокол: IMAP
Сервер: mail.examle.com
Порт: 993
Защита соединения: SSL/TLS
Метод аутентификации: Обычный пароль
Имя пользователя: полный адрес электронной почты
Например:
Код:
admin@examle.com
Исходящая почта — SMTP
Код:
Сервер: mail.examle.com
Порт: 587
Защита соединения: STARTTLS
Метод аутентификации: Обычный пароль
Имя пользователя: полный адрес электронной почты
То есть в моём случае итоговая схема получилась такой:
Код:
IMAP
mail.examle.com:993
SSL/TLS
SMTP
mail.examle.com:587
STARTTLS
Набор команд для быстрой диагностики
Если столкнусь с подобной проблемой снова, сначала проверю именно эти вещи.
1. Какие почтовые порты слушаются:
Bash:
netstat -lntp | egrep ':(465|587|993)\s'
2. IMAPS:
Bash:
openssl s_client \
-connect mail.examle.com:993 \
-servername mail.examle.com \
</dev/null
3. SMTPS 465:
Bash:
openssl s_client \
-connect mail.examle.com:465 \
-servername mail.examle.com \
</dev/null
4. SMTP Submission 587:
Bash:
openssl s_client \
-starttls smtp \
-connect mail.examle.com:587 \
-servername mail.examle.com \
</dev/null
5. Сертификат Let's Encrypt:
Bash:
openssl x509 \
-in /etc/letsencrypt/live/mail.examle.com/fullchain.pem \
-noout \
-subject \
-issuer \
-dates
6. SSL-настройки Dovecot:
Bash:
doveconf -a | grep -E '^ssl_|^ssl '
7. Версия Dovecot:
Bash:
dovecot --version
8. Версия OpenSSL:
Bash:
openssl version -a
На что смотреть в openssl s_client
Меня интересуют прежде всего строки:
Код:
subject=
issuer=
Protocol :
Cipher :
Server Temp Key:
Verify return code:
Хороший результат проверки сертификата:
Код:
subject=/CN=mail.examle.com
Verify return code: 0 (ok)
Если вижу:
Код:
Protocol : TLSv1
это уже тревожный сигнал для современного почтового клиента.
Если вижу:
Код:
Server Temp Key: DH, 1024 bits
сервер также использует устаревшие DH-параметры.
Не стоит сразу добавлять исключение безопасности
Если Thunderbird предлагает:
Код:
Добавить исключение безопасности
я теперь сначала проверяю сервер через OpenSSL.
Если сервер должен использовать публичный сертификат Let's Encrypt, лучше устранить причину на сервере, а не создавать постоянное исключение в Thunderbird.
Особенно проверяю:
- правильное ли имя хоста;
- правильный ли сертификат отдаётся;
- полная ли цепочка сертификатов;
- действителен ли сертификат;
- какая версия TLS используется;
- какой cipher согласован;
- какой размер DH используется;
- на каком SMTP-порту работает современный TLS.
Что ещё нужно модернизировать
После восстановления почты сама инфраструктура всё равно остаётся устаревшей.
В моём случае это:
Код:
Dovecot 2.0.9
OpenSSL 1.0.1e-fips
старый Postfix
certbot-auto
Поэтому решение с портом 587 позволило быстро вернуть работоспособность Thunderbird, но в перспективе такой почтовый сервер стоит обновить.
Особенно желательно избавиться от:
- TLS 1.0;
- 1024-битного DHE;
- старого OpenSSL;
- Dovecot 2.0.x;
certbot-auto.
Итог
В этой ситуации у меня было сразу несколько проблем, поэтому диагностика только сертификата не давала полной картины.
Сначала Let's Encrypt не мог пройти HTTP-01 из-за nginx:
Код:
HTTP → 301 → HTTPS
После исправления nginx новый сертификат успешно выпустился.
Dovecot на 993 уже корректно отдавал сертификат Let's Encrypt:
Код:
Verify return code: 0 (ok)
Но Thunderbird всё равно не завершал настройку.
Причина обнаружилась на SMTP 465:
Код:
Protocol : TLSv1
Server Temp Key: DH, 1024 bits
В итоге мне даже не пришлось серьёзно переделывать Postfix.
Я просто перевёл Thunderbird с:
Код:
SMTP 465 + SSL/TLS
на:
Код:
SMTP 587 + STARTTLS
И после этого всё заработало.
Итоговая рабочая схема:
Код:
IMAP:
mail.examle.com:993
SSL/TLS
SMTP:
mail.examle.com:587
STARTTLS
Для старого почтового сервера это оказалось самым простым способом восстановить работу современного Thunderbird без искусственного снижения требований безопасности на стороне клиента.