Поднимаем собственный почтовый сервер на VDS

6 сентября 2018

Как вам может быть известно, я не очень доверяю SaaS-решениям. Причин тому больше одной. SaaS’ы оставляют за собой право менять Terms of Service в любой момент как им вздумается. SaaS’ы сливают персональные данные. SaaS’ы меняют пользовательский интерфейс и функционал на свое усмотрение. Наконец, если вы используете SaaS’ы от какого-нибудь Google, то однажды получив в них бан за любое нарушение ToS (который, напомню, постоянно меняется), назад вы больше никогда не разбанитесь. В прошлой статье мы решали описанные проблемы, поднимая / перенося на VDS свой блог. Сегодня же мы попробуем разобраться, как с нуля поднять собственный почтовый сервер с TLS, спам-фильтром и списками рассылок.

Примечание: Описанные далее действия производились на Ubuntu Linux 16.04. Однако для других версий Ubuntu, ровно как и для других дистрибутивов Linux, последовательность шагов должна не сильно отличаться.

Подготовка

Примем за рабочую теорию, что у вас есть выделенный сервер (VDS) и указывающее на него доменное имя. Далее в качестве примера я буду использовать домен mail.eax.me. Если VDS у вас нет, сейчас есть множество VDS-провайдеров, предоставляющих их за смешные деньги. На момент написания этих строк я предпочитаю пользоваться DigitalOcean. При регистрации в DigitalOcean по моей реферальной ссылке вы получаете на счет 10$, что позволит бесплатно пользоваться VDS в течение двух месяцев.

В /etc/hosts прописываем Fully Qualified Domain Name (FQDN):

12.34.56.78    mail.eax.me    mail

Ставим необходимые пакеты:

sudo apt install mysql-server mysql-client postfix postfix-mysql \
    dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql

При установке Postfix на вопрос «General type of mail configuration» говорим «Internet Site». На вопрос о доменном имени отвечаем «mail.eax.me».

Postfix представляет собой Mail Transfer Agent (MTA), он будет отвечать за отправку и получение почты по SMTP. Dovecot будет предоставлять доступ к письмам по протоколу IMAP (также поддерживается ныне устаревший POP3). СУБД MySQL будет использоваться для хранения информации о доменах, пользователях и алиасах. Вместо MySQL с тем же успехом можно взять и MariaDB.

Наполняем базу

В MySQL создаем пользователя и базу данных:

$ mysql --user root --password
mysql> CREATE DATABASE mail;
mysql> CREATE USER 'mail'@'localhost' IDENTIFIED BY 'pa55w0rd';
mysql> GRANT ALL ON mail.* TO 'mail'@'localhost';
mysql> exit

Заходим под новым пользователем:

$ mysql mail --user mail --password

Создаем следующие таблицы:

CREATE TABLE `virtual_domains` (
`id`  INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `virtual_users` (
`id` INT NOT NULL AUTO_INCREMENT,
`domain_id` INT NOT NULL,
`password` VARCHAR(106) NOT NULL,
`email` VARCHAR(120) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id)
  ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `virtual_aliases` (
`id` INT NOT NULL AUTO_INCREMENT,
`domain_id` INT NOT NULL,
`source` VARCHAR(100) NOT NULL,
`destination` VARCHAR(100) NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id)
  ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Вводим информацию о доменах, пользователях и алиасах:

INSERT INTO virtual_domains (`id`, `name`) VALUES (1, 'eax.me');

INSERT INTO virtual_users (`id`, `domain_id`, `email`, `password`)
  VALUES (1, 1, 'mail@eax.me',
    ENCRYPT('s3cr3t', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))));

INSERT INTO virtual_aliases
  (`id`, `domain_id`, `source`, `destination`)
    VALUES (1, 1, 'postmaster@eax.me', 'mail@eax.me');

В колонке destination таблицы virtual_aliases можно указывать несколько получателей через запятую, в том числе и на всяких gmail.com. Таким образом, можно создавать списки рассылки. Если алиасы образуют цепочку, например postmaster@eax.me → mail@eax.me → somebody@eaxmple.org, то это тоже превосходно работает.

Настраиваем Postfix

Правим /etc/postfix/main.cf:

# дописываем или изменяем:

# пока что без TLS
smtpd_use_tls=no
myhostname = mail.eax.me
mydestination = localhost

virtual_transport = lmtp:unix:private/dovecot-lmtp
# то, что пока нет таких файлов - это ОК
virtual_mailbox_domains = mysql:/etc/postfix/mysql-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-users.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-aliases.cf

smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions = permit_sasl_authenticated,⏎
  permit_mynetworks,reject_unauth_destination

Создаем /etc/postfix/mysql-domains.cf:

hosts = 127.0.0.1
user = mail
password = pa55w0rd
dbname = mail
query = SELECT 1 FROM virtual_domains WHERE name='%s'

…, а также /etc/postfix/mysql-users.cf:

hosts = 127.0.0.1
user = mail
password = pa55w0rd
dbname = mail
query = SELECT 1 FROM virtual_users WHERE email='%s'

…, и наконец /etc/postfix/mysql-aliases.cf:

hosts = 127.0.0.1
user = mail
password = pa55w0rd
dbname = mail
query = SELECT destination FROM virtual_aliases WHERE source='%s'

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

sudo chown postfix:postfix /etc/postfix/mysql-*.cf
sudo chmod o-rwx /etc/postfix/mysql-*.cf

Перезапускаем Postfix:

sudo service postfix restart

Проверяем, что он видит домены, пользователей и алиасы:

$ sudo postmap -q mail@eax.me mysql:/etc/postfix/mysql-users.cf
1
$ sudo postmap -q eax.me mysql:/etc/postfix/mysql-domains.cf
1
$ sudo postmap -q postmaster@eax.me mysql:/etc/postfix/mysql-aliases.cf
mail@eax.me

Теперь самое время заняться настройкой Dovecot.

Настраиваем Dovecot

Конфигурация Dovecot состоит из нескольких файлов, каждый из которых предстоит немного подправить.

Правим /etc/dovecot/dovecot.conf:

protocols = imap lmtp

Затем /etc/dovecot/conf.d/10-mail.conf:

mail_location = maildir:/var/mail/vhosts/%d/%n
mail_privileged_group = mail

В /etc/dovecot/conf.d/10-auth.conf меняем следующее:

auth_mechanisms = plain login
# эту строчку нужно закомментировать:
#!include auth-system.conf.ext
!include auth-sql.conf.ext

Далее правим /etc/dovecot/conf.d/auth-sql.conf.ext:

passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
  driver = static
  args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}

Редактируем /etc/dovecot/dovecot-sql.conf.ext:

driver = mysql
connect = host=127.0.0.1 user=mail password=pa55w0rd dbname=mail
default_pass_scheme = SHA512-CRYPT
password_query = \
    SELECT email as user, password \
    FROM virtual_users \
    WHERE email='%u';

Правим в /etc/dovecot/conf.d/10-master.conf следующее:

# ...

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
}

# ...

service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }

  unix_listener auth-userdb {
    mode = 0600
    user = vmail
  }

  user = dovecot
}

# ...

service auth-worker {
  user = vmail
}

Наконец, в файле /etc/dovecot/conf.d/15-lda.conf указываем:

postmaster_address = postmaster@eax.me

Фух, с конфигами покончено. Теперь для каждого домена говорим:

sudo mkdir -p /var/mail/vhosts/eax.me

Создаем пользователя и группу vmail, проставляем права и перезапускаем Dovecot:

sudo groupadd -g 5000 vmail
sudo useradd -g vmail -u 5000 vmail -d /var/mail
sudo chown -R vmail:vmail /var/mail
sudo chown -R vmail:dovecot /etc/dovecot
sudo chmod -R o-rwx /etc/dovecot
sudo service dovecot restart

Dovecot настроен!

Проверяем

К этому моменту у вас должен крутиться SMTP на порту 25 и IMAP на порту 143. Пока что без TLS и спам-фильтра, но это уже самый настоящий почтовый сервер. Проверяем, что к нему можно подключиться почтовым клиентом. Затем добавляем в DNS MX-запись, указывающую на mail.eax.me. Обновление зоны занимает какое-то время — обычно около часа, но особо «умные» провайдеры могут кэшировать данные на сутки. То, что зона обновилась, можно увидеть так:

$ dig eax.me MX

...

;; ANSWER SECTION:
eax.me.         3599    IN  MX  5 mail.eax.me.

...

После этого проверяем, что почта приходит с какого-нибудь GMail и уходит на него (возможно, попадая при этом в каталог «Спам»), также проверяем работу алиасов. В случае возникновения проблем смотрим в файл /var/log/mail.log — туда пишет логи как Postfix, так и Dovecot.

Прикручиваем TLS

Поскольку мы не дураки платить за сертификаты, то воспользуемся Let’s Encrypt. После установки certbot’а говорим:

sudo certbot --standalone certonly -d mail.eax.me

Теперь актуальный ключ и сертификат всегда будут лежать в:

/etc/letsencrypt/live/mail.eax.me/fullchain.pem
/etc/letsencrypt/live/mail.eax.me/privkey.pem

Правим /etc/postfix/main.cf:

smtpd_use_tls=yes
smtpd_tls_auth_only = yes
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.eax.me/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.eax.me/privkey.pem
# Эта настройка говорит по возможности слать исходящую почту по TLS
# Без нее GMail будет помечать письма как "незашифрованные"
smtp_tls_security_level=may

Затем редактируем /etc/dovecot/conf.d/10-ssl.conf

ssl = required
# символы < перед путями к файлам - не опечатка
ssl_cert = </etc/letsencrypt/live/mail.eax.me/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.eax.me/privkey.pem

Перезапускаем Postfix и Dovecot:

sudo service postfix restart
sudo service dovecot restart

Postfix слушает с TLS на порту 25. Dovecot слушает одновременно порты 143 и 993. Меняем настройки почтового клиента и проверяем, что все работает. Мне в случае с Claws Mail в свойствах SMTP пришлось выбрать галочку «Use STARTTLS command to start encryption session».

Но это еще не все! Нужно, чтобы Postfix и Dovecot автоматически перечитывали сертификаты при их обновлении.

В /etc/letsencrypt/cli.ini пишем:

renew-hook=/etc/letsencrypt/certbot-renew-hook.sh

Создаем /etc/letsencrypt/certbot-renew-hook.sh:

#!/bin/sh

set -e

systemctl reload postfix
systemctl reload dovecot

Наконец, говорим:

sudo chmod ug+x /etc/letsencrypt/certbot-renew-hook.sh

Скрипт будет автоматически вызываеться при каждом успещном обновлении сертификата и перезапускать демонов.

Настраиваем SpamAssassin

Apache SpamAssassin — это открытое решение для фильтрации спама. Сразу отмечу, что крутизны спам-фильтров GMail’а от него, пожалуй, ожидать не стоит. Тем не менее, по моим наблюдениям, со спамом он борется вполне достойно.

Ставим SpamAssassin и создаем пользователя spamd:

sudo apt install spamassassin spamc
sudo adduser spamd --disabled-login

Правим /etc/default/spamassassin таким образом:

SPAMD_HOME="/home/spamd/"
OPTIONS="--create-prefs --max-children 5 --username spamd ⏎
  --helper-home-dir ${SPAMD_HOME} -s ${SPAMD_HOME}spamd.log"
PIDFILE="${SPAMD_HOME}spamd.pid"
CRON=1

В /etc/spamassassin/local.cf дописываем:

rewrite_header Subject ***** SPAM _SCORE_ *****
report_safe             0
required_score          5.0
use_bayes               1
use_bayes_rules         1
bayes_auto_learn        1
skip_rbl_checks         0
use_razor2              0
use_dcc                 0
use_pyzor               0

Правим /etc/postfix/master.cf:

# тут нужно дописать строчку -o content_filter...
smtp      inet  n       -       y       -       -       smtpd
  -o content_filter=spamassassin

# в конец дописываем:
spamassassin unix -     n       n       -       -       pipe
  user=spamd argv=/usr/bin/spamc -f -e
  /usr/sbin/sendmail -oi -f ${sender} ${recipient}

Говорим:

sudo service spamassassin start
sudo service postfix restart

То, что SpamAssasin работает, можно определить по заголовкам X-Spam-Checker-Version и X-Spam-Status во входящих письмах. Письма, помеченные как спам, будут иметь соответствующий Subject, а также заголовок X-Spam-Flag: YES. Для проверки того, что спам определяется, можно послать себе специальное письмо, которое вы найдете в файле:

/usr/share/doc/spamassassin/examples/sample-spam.txt

Но это еще не окончательное решение. Спам все еще приходит, просто он помечен, как спам. Его, конечно, можно отфильтровывать на стороне клиента, но лучше бы делать это на сервере.

В этом нам поможет расширение для Dovecot под названием sieve:

sudo apt install dovecot-sieve dovecot-managesieved

Правим /etc/dovecot/conf.d/20-lmtp.conf:

protocol lmtp {
  #mail_plugins = $mail_plugins
  mail_plugins = $mail_plugins sieve
}

Редактируем /etc/dovecot/conf.d/90-sieve.conf:

plugin {
   # то, что пока не таких файлов и путей - это ОК
   sieve = ~/.dovecot.sieve
   sieve_global_dir = /var/lib/dovecot/sieve/
   sieve_global_path = /var/lib/dovecot/sieve/default.sieve
   sieve_dir = ~/sieve
}

Далее говрим:

sudo mkdir /var/lib/dovecot/sieve/

Создаем /var/lib/dovecot/sieve/default.sieve:

require "fileinto";
if header :contains "X-Spam-Flag" "YES" {
  fileinto "SPAM";
}

Чтобы каталог SPAM автоматически создавался, если его еще нет, правим файл /etc/dovecot/conf.d/15-lda.conf:

lda_mailbox_autocreate = yes

Завершающие шаги:

sudo chown -R vmail:vmail /var/lib/dovecot
sudo sievec /var/lib/dovecot/sieve/default.sieve
sudo service dovecot restart

Ну вот и все, теперь спам будет сыпаться в каталог SPAM. Обратите внимание, что не все почтовые клиенты проверяют появление новых каталогов, если только их прямо об этом не попросить.

Заключение

Несмотря на то, что заметка вышла довольно длинной, в действительности повторить описанные шаги занимает один вечер. За дополнительной информацией обращайтесь к официальным сайтам соответствующих проектов. Если вы используете на сервере фаервол, обратите внимание, что для корректной работы certbot’а порт 80 должен быть открыт. Если вас интересует прикручивание к почте веб-интерфейса, тут можно порекомендовать RoundCube. В качестве открытого антивируса можно посоветовать ClamAV. Впрочем, я затрудняюсь сказать, насколько хороши его антивирусные базы. Настройка как RoundCube, так и ClamAV, к сожалению, выходят за рамки данного поста.

А доводилось ли вам поднимать собственный почтовый сервер, и если да, то что вы для этого использовали?

Метки: .

Понравился пост? Узнайте, как можно поддержать развитие этого блога.

Также подпишитесь на RSS, Google+, Facebook, ВКонтакте или Twitter.