Короткий ответ: потому что разные конечные точки (IP/контейнеры/процессы/порт‑службы) сервера могут использовать разные файлы сертификатов или старые копии сертификата остаются в памяти/в контейнерах и не перезагружаются. Чтобы понять, почему у вас иногда показывается просроченный, а иногда — свежий — нужно диагностировать, какие именно хосты/порты/контейнеры отдают какой сертификат.
Что типично вызывает такую «переменную» картину
- В DNS у хоста есть несколько A/AAAA записей (round‑robin) и на разных IP стоят разные машины с разными сертификатами.
- Есть и IPv4, и IPv6, и на них — разные certs (клиенты иногда выбирают IPv6).
- Несколько MX/backup‑MX с разными сертификатами.
- TLS терминируется на балансировщике/провайдере (или Cloudflare) и там другой cert.
- Cert обновлён на диск, но процессы (nginx, postfix, dovecot и т. п.) или контейнеры не перезагружены — они продолжают отдавать старый cert из памяти.
- В Docker/ Mailcow сертификат лежит в том месте, куда копируется/монтируется, и не все контейнеры читают одни и те же файлы (копии vs symlink).
- Сценарии восстановления из бэкапа/планировщик задач периодически откатывают старые файлы.
Как диагностировать — шаги и команды
1) Узнайте, на каких IP/записях работает имя:
- dig +short A mail.example.com
- dig +short AAAA mail.example.com
- dig +short MX example.com
2) Для каждого IP/порта проверьте реальный сертификат (пример для IMAPs, SMTP и HTTPS):
- IMAPs (993):
openssl s_client -connect mail.example.com:993 -servername mail.example.com </dev/null 2>/dev/null | openssl x509 -noout -dates -subject -issuer
- SMTP with STARTTLS (25):
openssl s_client -connect mail.example.com:25 -starttls smtp -servername mail.example.com </dev/null 2>/dev/null | openssl x509 -noout -dates -subject -issuer
- HTTPS (443):
openssl s_client -connect mail.example.com:443 -servername mail.example.com </dev/null 2>/dev/null | openssl x509 -noout -dates -subject -issuer
- Проверьте каждый IP явно (вместо имени подставьте IP и обязательно указывайте -servername имя), чтобы увидеть, какой cert отдаёт конкретный адрес:
openssl s_client -connect 1.2.3.4:993 -servername mail.example.com ...
3) Если результаты разные в зависимости от IP — проблема в DNS/несинхронных серверах. Если разные в зависимости от порта — разные службы используют разные certs.
4) На хосте Mailcow — посмотрите контейнеры и где лежат сертификаты:
- В директории с mailcow: docker-compose ps
- Найдите контейнеры nginx, postfix, dovecot и acme (имена могут быть nginx-mailcow, postfix-mailcow, dovecot-mailcow, acme-mailcow и т. п.)
- В каждом контейнере можно посмотреть файлы сертификата:
docker exec -it <container> ls -l /etc/letsencrypt/live/<yourdomain>
docker exec -it <container> openssl x509 -in /path/to/cert.pem -noout -dates -subject
- Посмотрите время изменения файла на хосте (где находятся данные mailcow, обычно data/assets/ssl или data/conf/letsencrypt и т.д.)
5) Проверьте логи ACME/renewal:
- docker logs <acme‑container> (посмотрите, успешно ли обновляется cert и когда)
6) Проверьте, перезагружаются ли сервисы после обновления:
- Частая причина — cert обновлён на диск, но контейнер/процесс не перезагружен и продолжает отдавать старую копию.
- В Docker проще перезапустить соответствующие контейнеры. В директории mailcow:
docker-compose restart nginx-mailcow postfix-mailcow dovecot-mailcow rspamd
(или просто docker-compose restart, если не уверены)
- Можно также внутри контейнера сделать nginx -s reload, dovecot reload и т.д., но в docker‑обстановке перезапуск контейнера надёжнее.
7) Доп. проверки
- Убедитесь, что сертификаты везде одинаковые (сравните fingerprint):
openssl x509 -in cert.pem -noout -fingerprint
- Проверьте, не стоит ли между клиентом и сервером TLS-терминатор (LB, CDN). Если есть, то обновлять нужно там.
- Проверьте cron/скрипты, не откатывают ли старую копию cert по расписанию.
Что делать, когда найдете источник
- Если дело в DNS (несколько IP): синхронизировать сертификаты на всех серверов/балансировщиках; обновить записи/TTL если нужно.
- Если дело в контейнерах, которые не видят новые файлы: обеспечить, чтобы контейнеры монтировали актуальные файлы (symlink на /etc/letsencrypt/live) и/или добавить post‑renew hook, который выполняет docker‑compose restart нужных контейнеров.
- Если cert обновляется, но не перезагружается nginx/postfix/dovecot — настроить postrenew скрипт (letsencrypt hook) для автоматической перезагрузки нужных сервисов/контейнеров.
- Если обнаружите старый backup: удалить/исключить его из использования.
Если хотите, могу:
- Сформировать для вас конкретный набор команд для вашей установки (напишите домен, какие IP показывает dig и список контейнеров docker ps), или
- Подготовить пример post‑renew hook для Mailcow (docker-compose restart нужных контейнеров).