Photo by Towfiqu barbhuiya
Postfix STARTTLS

Postfix TLS/STARTTLS

24.12.25

Шифрование сейчас все актуальнее и актуальнее. Проникает во все сферы. Почта и postfix также не остаются в стороне. Поэтому обсудим что такое Postfix TLS/STARTTLS и что как настраивать и почему.

На SMTP/25 обычно включают opportunistic STARTTLS. Это значит, что если отправители умеют — шифруемся, если нет — всё равно принимаем, иначе потеряете часть писем. А вот на submission/587 для своих клиентов (почтовики, сайты, приложения) шифрование можно и нужно сделать обязательным.

Будем думать, что уже есть:

  • FQDN для почтового сервера, например  mail.example.com, который резольвится на ваш IP.
  • Открыты порты: 25 (SMTP), 587 (submission), опционально 465 (smtps), плюс 80/443 или DNS‑доступ для выпуска сертификата.
  • Postfix установлен и работает.

Выпускаем сертификат Let’s Encrypt (certbot)

Устанавливаем certbot (на Ubuntu 22.04 обычно через snap или apt — выберите ваш стандарт), затем получаем сертификат для имени mail‑хоста. В итоге должны появиться файлы:

  • /etc/letsencrypt/live/mail.example.com/fullchain.pem
  • /etc/letsencrypt/live/mail.example.com/privkey.pem

Включаем STARTTLS на входящем SMTP/25

Откройте /etc/postfix/main.cf и добавьте параметры:

# Входящие SMTP-соединения: предлагаем STARTTLS, но не требуем
smtpd_tls_security_level = may

# Сертификат Let's Encrypt
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file  = /etc/letsencrypt/live/mail.example.com/privkey.pem

# Кеш TLS-сессий (меньше CPU на рукопожатиях)
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

# Умеренная детализация TLS в логах для диагностики
smtpd_tls_loglevel = 1

Почему  may? Порт 25 используется для передачи почты между почтовыми серверами (MTA-MTA), а не от пользователя к серверу. Заставлять весь интернет шифроваться на 25 нельзя «безболезненно» — часть серверов просто не доставит вам письма.

Делаем обязательный TLS на submission/587

Порт 587 (submission) используется для отправки почты почтовыми клиентами (Outlook, Thunderbird) на почтовый сервер, выступая как современный и безопасный канал, который требует аутентификации и обеспечивает шифрование.

В /etc/postfix/master.cf включите (или добавьте) сервис submission и переопределите настройки только для него:

submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_tls_auth_only=yes
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject

Ключевые строки:

  • smtpd_tls_security_level=encrypt — TLS обязателен на 587 (без STARTTLS клиент не сможет отправлять).
  • smtpd_tls_auth_only=yes — запрещает аутентификацию без шифрования

Исходящая доставка

Включаем режим TLS «по возможности». Чтобы Postfix шифровался при доставке на внешние домены (где TLS поддерживается):

smtp_tls_security_level = may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

Если поставить encrypt глобально, начнутся потери отправки (недоставки) на домены без TLS (или с кривым TLS). Но и выключать шифрование отправки нельзя, так как это снижает доверие к вашей почте (будете попадать в СПАМ). Поэтому для «интернета целиком» лучше использовать may.

Применяем:

sudo postfix check
sudo systemctl reload postfix

Автообновление сертификата

Let’s Encrypt сертификаты обновляются автоматически, но Postfix должен «подхватить» новые файлы. Вариант — использовать post-hook/deploy-hook механику, чтобы после renew выполнялся systemctl reload postfix.

Какие отличия между post-hook и deploy-hook? При ключе post-hook скрипты запустятся всегда, независимо от успеха обновления сертификата (success или failure), а во втором случае, только после удачного обновления.

Варианты настройки, первый простой. Добавить опцию --post-hook или --deploy-hook в crontab строку:

0 1 * * 7  certbot renew --post-hook "systemctl restart postfix; systemctl restart dovecot"

Второй вариант – создать шелл-скрипт в директории /etc/letsencrypt/renewal-hooks/post/, либо /etc/letsencrypt/renewal-hooks/deploy/ например, restart-services.sh

#!/bin/sh

systemctl restart postfix
systemctl restart dovecot

И установить права на выполнение:

chmod +x /etc/letsencrypt/renewal-hooks/deploy/restart-services.sh

Быстрая проверка STARTTLS

Как проверить, что все настроили правильно и что всё работает? Проверка 25 порта:

penssl s_client -starttls smtp -connect mail.example.com:25 -servername mail.example.com

Проверка 587 порта

openssl s_client -starttls smtp -connect mail.example.com:587 -servername mail.example.com

Что важно увидеть:

  • сертификат выдан на нужное имя (SAN/CN), цепочка без ошибок, рукопожатие проходит.
  • на 587 без STARTTLS соединение должно «ругаться» и не давать логиниться, если включён обязательный TLS.

Типовые ошибки в логах Postfix и лечение

Логи на Ubuntu чаще всего смотрят через:

sudo tail -f /var/log/mail.log

или journalctl -u postfix -f

Postfix не может прочитать privkey (permission denied)

Это ошибки загрузки ключа/сертификата, TLS не поднимается. Частая причина — права доступа к /etc/letsencrypt/… и privkey.pem, которые Postfix (и Dovecot) не читают по умолчанию.

Что делать? Корректно разрешить доступ (группа/ACL/разрешения) так, чтобы Postfix мог читать ключ, но ключ не стал «общем достоянием» для всех.

Клиент на 587-й подключается, но не видит STARTTLS и не может отправить

Причина: вы включили TLS только в main.cf, но не активировали submission (что-то не так настроили) в master.cf или не переопределили там smtpd_tls_security_level=encrypt

Проверьте блок submission и сделайте systemctl reload postfix

«TLS library problem», «SSL_accept error», «handshake failure»

Обычно связано с несовместимостью по протоколам/шифрам или с неправильной цепочкой сертификатов. Начните с проверки через openssl s_client и проверьте, что используете  fullchain.pem, а не «обрезанный» сертификат.