Запуск почтового сервера в Docker (traefik + mailserver)

Настройка и запуск почтового сервера в Docker-контейнере

 5 мин. на чтение
mailserver

Электронная почта, несмотря на бурное развитие мессенджеров и социальных сетей, остается довольно популярным способом коммуникации. Кроме того email в большинстве случаев является выбором номер один в плане доставки чувствительных данных, например таких как пароли. В связи с чем, довольно часто стоит задача поднять свой собственный почтовый сервер, и данный материал попытается ответить на вопрос, как это сделать.


В предыдущем посте я рассказывал как использовать Traefik в качестве реверс-прокси для контейнеров Docker. Сейчас же мы рассмотрим связку Traefik с одним из популярных почтовиков Postfix. Почтовый сервер, как вы уже скорее всего догадались, будем так же запускать в докере. Для это возьмем вот эту реализацию - docker-mailserver.

КОНФИГУРИРОВАНИЕ TRAEFIK

Так как подключаться к нашему почтовому серверу мы планируем посредством шифрованного соединения с обязательным требованием аутентификации, то наш прокси-сервер должен уметь перенаправлять запросы со следующих портов 465 и 993:

  • 465 порт необходим для отправки почты по протоколу ESMTP;
  • 993 порт необходим для получения почты по протоколу IMAP4;

Теперь когда мы определились с необходимыми портами, первым делом добавим две новые точки входа в наш прокси. Для этого внесем следующие изменения в файл traefik.yaml. Так же необходимо помнить, что порты, через которые мы будем осуществлять коммуникации, должны быть добавлены в секцию ports файла docker-compose traefik.

entryPoints:
  
  ...
    
  smtp-ssl:
    address: :465
	
  imap-ssl:
    address: :993	

После перезапуска контейнера с traefik, в дашборде должны появиться новые точки входа:

Traefik точки входа для mailserver

Соответственно должны появиться открытые порты:

# netstat -tulpn | grep docker-proxy
tcp6       0      0 :::465                  :::*                    LISTEN      700540/docker-proxy
tcp6       0      0 :::443                  :::*                    LISTEN      700552/docker-proxy
tcp6       0      0 :::993                  :::*                    LISTEN      700528/docker-proxy
tcp6       0      0 :::80                   :::*                    LISTEN      700564/docker-proxy

В моем случае, открытых портов я не увидел. Может быть из-за того, что я добавил соответствующие правила в iptables и перегрузил файрвол, или же traefik просто не подхватил порты. Но после перезагрузки демона Docker и перезапуска контейнера traefik, все завелось.

Запуск и настройка mailserver

И так, чтобы запустить наш почтовый сервер в докере, согласно документации нам необходимо четыре файла: docker-compose.yml, compose.env, mailserver.env, setup.sh. Скачаем их все:

# mkdir mailserver && cd ./mailserver
# curl -O https://raw.githubusercontent.com/tomav/docker-mailserver/master/setup.sh
# curl -O https://raw.githubusercontent.com/tomav/docker-mailserver/master/docker-compose.yml
# curl -O https://raw.githubusercontent.com/tomav/docker-mailserver/master/mailserver.env
# curl -o .env https://raw.githubusercontent.com/tomav/docker-mailserver/master/compose.env

Добавим разрешения на запуск bash-скрипта:

# chmod a+x ./setup.sh

В файле .env необходимо указать HOSTNAME и DOMAINNAME Вашего почтового сервера. В файле mailserver.env необходимо выставить значение SSL_TYPE в letsencrypt, так как ssl-сертификаты мы планируем получать именно от данного поставщика. Файл setup.sh оставляем без изменений, а вот в файл docker-compose.yml внесем наибольшее кол-во изменений.

Так как ssl-сертификаты мы будем использовать от Let’s Encrypt, то добавим следующий сервис:

  whoami:
    image: containous/whoami
    restart: always
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.entrypoints=https, http"
      - "traefik.http.routers.whoami.rule=Host(`your_host.your_domain_name`)"
      - "traefik.http.routers.whoami.tls=true"
      - "traefik.http.routers.whoami.tls.certresolver=letsEncrypt"

Это позволит автоматически получать и продлевать ssl-сертификаты для домена нашего почтового сервера. Более подробно связку traefik и Let’s Encrypt я описывал в предыдущей статье.

Traefik и контейнеры, в которые проксируется трафик, должны находиться в одной сети, поэтому добавим следующие строки:

networks:
  default:
    external:
      name: traefik_net

Имейте ввиду, у меня эта сеть называется traefik_net, и она является сетью по-умолчанию для всех моих контейнеров. У Вас же может быт совсем другая конфигурация. Более подробную информацию можете найти здесь.

Так как traefik выступает в роли прокси-сервера, то в секции ports сервиса mail оставим только 25й порт. Так же зададим необходимые значения для hostname, domainname и container_name. В секцию volumes добавим файл, где traefik сохраняет данные о полученных сертификатах:

- /home/traefik/config/acme.json:/etc/letsencrypt/acme.json:ro

Последний штрих добавим метки, чтобы traefik знал, куда именно проксировать трафик:

    labels:
      - "traefik.enable=true"
	        
      - "traefik.tcp.routers.mail-smtp.rule=HostSNI(`your_host.your_domain_name`)"
      - "traefik.tcp.routers.mail-smtp.entrypoints=smtp-ssl"
      - "traefik.tcp.routers.mail-smtp.tls.passthrough=true"
      - "traefik.tcp.routers.mail-smtp.service=mail-smtp"
      - "traefik.tcp.services.mail-smtp.loadbalancer.server.port=465"

      - "traefik.tcp.routers.mail-imap.rule=HostSNI(`your_host.your_domain_name`)"
      - "traefik.tcp.routers.mail-imap.entrypoints=imap"
      - "traefik.tcp.routers.mail-imap.tls.passthrough=true"
      - "traefik.tcp.routers.mail-imap.service=mail-imap"
      - "traefik.tcp.services.mail-imap.loadbalancer.server.port=993"

После запуска, в дашборде traefik можно наблюдать, два наших сервиса:

Traefik cервисы для maailserver

Выполним запуск контейнера и произведем первоначальную конфигурацию:

# docker-compose up -d

# ./setup.sh email add <user@domain> [<password>]
# ./setup.sh alias add postmaster@<domain> <user@domain>
# ./setup.sh config dkim

Теперь, когда почтовый сервер настроен, рассмотрим варианты, как сделать его более безопасным.

Защита от спуфинга с помощью SPF и DKIM

Спамеры могут сфальсифицировать ваше доменное имя, рассылая поддельные письма якобы от вашего почтового ящика. Это называется спуфингом. Чтобы этого избежать рекомендуется, использовать следующие методы аутентификации электронной почты в домене:

  • SPF позволяют проверить, было ли письмо с указанным исходным доменом действительно отправлено с сервера, авторизованного владельцем этого домена;
  • DKIM добавляет цифровую подпись к каждому сообщению. Это позволяет принимающему серверу проверить, не было ли сообщение подделано или изменено при доставке;

Чтобы включить SPF у регистратора домена, необходимо добавить DNS запись TXT для SPF, следующего содержания:

v=spf1 a mx:mail.your_domain ip4:xxx.xxx.xx.xxx/32 ip6:xxxx:xxx:xxxx:xxx::1 ~all

Теги, которые используются для создания записи TXT для SPF, называются механизмами. Ниже приведен список механизмов, которые определены в строке выше:

Механизм Описание
v Версия SPF. Необходимое значение: spf1. Этот тег является обязательным, и он должен быть первым тегом в записи.
a Указывает один или несколько почтовых серверов с помощью доменного имени.
mx Указывает почтовый сервер по ссылке на запись MX.
ip4 Указывает один или несколько почтовых серверов с помощью адреса IPv4 или диапазона.
ip6 Указывает один или несколько почтовых серверов с помощью адреса IPv6 или диапазона.
all Этот тег обычно указывается в конце записи. Проверки SPF игнорируют любые механизмы после all.

При инициализации почтового сервера мы выполняли следующую команду:

# ./setup.sh config dkim

Данная команда сформирует цифровую подпись для всех исходящих писем нашего почтового сервера. Кроме этого она создаст файл mail.txt c ключем DKIM, который необходимо добавить как DNS запись типа TXT. Найти данный файл можно по пути ./config/opendkim/keys/your-domain-name/ относительно скрипта setup.sh.

На этом все. Подключившись с помощью почтового клиента к домену your_host.your_domain_name мы можем безопасно получать и отправлять сообщения.