Настройку будет проводить на CentOS Stream release 9
Postfix представляет собой Mail Transfer Agent (MTA), он будет отвечать за отправку и получение почты по SMTP.
Dovecot будет предоставлять доступ к письмам по протоколу IMAP
(также поддерживается ныне устаревший POP3).
СУБД MariaDB будет использоваться для хранения информации о доменах, пользователях и алиасах.
Вместо MariaDB с тем же успехом можно взять и MySQL.
В /etc/hosts прописываем Fully Qualified Domain Name (FQDN):
1 |
12.34.56.78 mail.example.com mail |
Ставим необходимые пакеты:
1 |
dnf install mariadb postfix postfix-mysql dovecot dovecot-mysql dovecot dovecot-mysql |
При установке Postfix на вопрос «General type of mail configuration» говорим «Internet Site».
На вопрос о доменном имени отвечаем «mail.example.com».
Наполняем базу
В MySQL создаем пользователя и базу данных:
1 |
$ mysql --user root --password |
1 2 3 4 |
mysql> CREATE DATABASE mail_db; mysql> CREATE USER 'mail_user'@'localhost' IDENTIFIED BY 'pa55w0rd'; mysql> GRANT ALL ON mail_db.* TO 'mail_user'@'localhost'; mysql> exit |
Заходим под новым пользователем:
1 |
$ mysql mail_db --user mail_user --password |
Создаем следующие таблицы:
1 2 3 4 5 |
CREATE TABLE `virtual_domains` ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
1 2 3 4 5 6 7 8 9 10 |
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; |
1 2 3 4 5 6 7 8 9 |
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; |
Вводим информацию о доменах, пользователях и алиасах:
1 |
INSERT INTO virtual_domains (`id`, `name`) VALUES (1, 'example.com'); |
1 2 3 |
INSERT INTO virtual_users (`id`, `domain_id`, `email`, `password`) VALUES (1, 1, 'mail@example.com', ENCRYPT('parol', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16)))); |
1 2 3 |
INSERT INTO virtual_aliases (`id`, `domain_id`, `source`, `destination`) VALUES (1, 1, 'postmaster@example.com', 'mail@example.com'); |
В колонке destination таблицы virtual_aliases можно указывать несколько получателей через запятую,
в том числе и на всяких gmail.com. Таким образом, можно создавать списки рассылки.
Если алиасы образуют цепочку, например postmaster@example.com → mail.example.com → somebody@example.org,
то это тоже превосходно работает.
Настраиваем Postfix
Правим /etc/postfix/main.cf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# дописываем или изменяем: # пока что без TLS smtpd_use_tls=no myhostname = mail.example.com 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 # увеличиваем максимальный размер письма до 50 Мб message_size_limit = 52428800 # fatal: configuration error: mailbox_size_limit is smaller than message_size_limit # Ошибка возникает из-за того что значение параметра message_size_limit больше чем значение mailbox_size_limit, # а должно быть наоборот, кстати virtual_mailbox_limit в конфигурационном файле не указан, # видимо если его не указать то стандартное значение равно 51200000 # что в моём случае оказалось меньше message_size_limit. mailbox_size_limit = 102400000 virtual_mailbox_limit = 102400000 |
Создаем /etc/postfix/mysql-domains.cf:
1 2 3 4 5 |
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:
1 2 3 4 5 |
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:
1 2 3 4 5 |
hosts = 127.0.0.1 user = mail password = pa55w0rd dbname = mail query = SELECT destination FROM virtual_aliases WHERE source='%s' |
Поскольку файлы содержат пароль от базы, стоит выставить на них правильные права:
1 2 |
chown postfix:postfix /etc/postfix/mysql-*.cf chmod o-rwx /etc/postfix/mysql-*.cf |
Перезапускаем Postfix:
1 |
$ systemctl postfix restart |
Проверяем, что он видит домены, пользователей и алиасы:
1 |
$ postmap -q mail@example.com mysql:/etc/postfix/mysql-users.cf |
1
1 |
$ postmap -q example.com mysql:/etc/postfix/mysql-domains.cf |
1
1 |
$ postmap -q postmaster@example.com mysql:/etc/postfix/mysql-aliases.cf |
mail.example.com
Теперь самое время заняться настройкой Dovecot.
Настраиваем Dovecot
Конфигурация Dovecot состоит из нескольких файлов, каждый из которых предстоит немного подправить.
Правим /etc/dovecot/dovecot.conf:
1 |
protocols = imap lmtp |
Затем /etc/dovecot/conf.d/10-mail.conf:
1 2 |
mail_location = maildir:/var/mail/vhosts/%d/%n mail_privileged_group = mail |
В /etc/dovecot/conf.d/10-auth.conf меняем следующее:
1 2 3 4 |
auth_mechanisms = plain login # эту строчку нужно закомментировать: #!include auth-system.conf.ext !include auth-sql.conf.ext |
Далее правим /etc/dovecot/conf.d/auth-sql.conf.ext:
1 2 3 4 5 6 7 8 |
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:
1 2 3 4 5 6 7 |
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 следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# ... 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 указываем:
1 |
postmaster_address = postmaster@example.com |
Фух, с конфигами покончено. Теперь для каждого домена говорим:
1 |
mkdir -p /var/mail/vhosts/example.com |
Создаем пользователя и группу vmail, проставляем права и перезапускаем Dovecot:
1 2 3 4 5 6 |
groupadd -g 5000 vmail useradd -g vmail -u 5000 vmail -d /var/mail chown -R vmail:vmail /var/mail chown -R vmail:dovecot /etc/dovecot chmod -R o-rwx /etc/dovecot systemctl restart dovecot && systemctl status dovecot |
Проверяем: UID должно совпадать
1 |
grep -E '^vmail|5000' /etc/passwd /etc/group |
Dovecot настроен!
Проверяем
К этому моменту у вас должен крутиться SMTP на порту 25 и IMAP на порту 143.
Пока что без TLS и спам-фильтра, но это уже самый настоящий почтовый сервер.
Проверяем, что к нему можно подключиться почтовым клиентом.
Затем добавляем в DNS MX-запись, указывающую на mail.example.com.
Обновление зоны занимает какое-то время — обычно около часа,
но особо «умные» провайдеры могут кэшировать данные на сутки.
То, что зона обновилась, можно увидеть так:
1 2 3 4 5 6 7 |
$ dig example.com MX ... ;; ANSWER SECTION: example.com. 3599 IN MX 5 mail.example.com. ... |
После этого проверяем, что почта приходит с какого-нибудь GMail и уходит на него
(возможно, попадая при этом в каталог «Спам»), также проверяем работу алиасов.
В случае возникновения проблем смотрим в файл /var/log/mail.log — туда пишет логи как Postfix, так и Dovecot.
Дополнение: С недавних пор некоторые почтовые сервисы начали отклонять письма, если у почтового сервера нет reverse DNS и SPF записей. Добавление reverse DNS происходит по-разному у разных VDS-провайдеров. У DigitalOcean нужно назвать VDS доменным именем сервера (например, «mail.example.com»). Проверить, что все в порядке, можно командой dig -x 1.2.3.4. SPF запись включается простым добавлением TXT-записи с содержимым v=spf1 mx -all. Она говорит, что слать письма с example.com могут только сервера, указанные в MX-записях домена. Для проверки выполняем команду dig -t TXT example.com.
Тестирование порта 143
Добавим пользователя для тестирования:
1 2 3 |
INSERT INTO virtual_users (`id`, `domain_id`, `email`, `password`) VALUES (3, 1, 'test@example.com', ENCRYPT('test', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16)))); |
Теперь мы можем попытаться аутентифицироваться как test по телнету:
1 2 3 4 5 6 7 8 9 10 |
:~$ telnet mail.example.com 143 Trying 65.91.21.51... Connected to mail.example.com. Escape character is '^]'. * OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ STARTTLS LOGINDISABLED] Dovecot (Debian) ready. a login test@example.com test * BAD [ALERT] Plaintext authentication not allowed without SSL/TLS, but your client did it anyway. If anyone was listening, the password was exposed. a NO [PRIVACYREQUIRED] Plaintext authentication disallowed on non-secure (SSL/TLS) connections. * BYE Disconnected for inactivity. Connection closed by foreign host. |
Правильно настроенный Dovecot должен регистрировать:
1 |
Nov 28 11:05:36 vps2 dovecot: imap-login: Login failed: Plaintext authentication disabled: user=<>, rip=107.175.245.18, lip=172.17.0.2, session=<Cszf2YXuzK1rr/US> |
1 2 3 |
ssl=required #ssl_min_protocol=TLSv1.2 |
Более мягкий Dovecot разрешит вход в систему через telnet, поэтому его следует настроить без :
1 2 |
#ssl=required #ssl_min_protocol=TLSv1.2 |
openssl s_client -connect servername:143 не будет работать, поскольку для этого требуется, чтобы сервер немедленно использовал TLS. openssl сообщит, среди прочего:
Прикручиваем TLS
Поскольку мы не дураки платить за сертификаты, то воспользуемся Let’s Encrypt. После установки certbot’а говорим:
1 |
certbot --standalone certonly -d mail.example.com |
Теперь актуальный ключ и сертификат всегда будут лежать в:
/etc/letsencrypt/live/example.com/fullchain.pem
/etc/letsencrypt/live/example.com/privkey.pem
Правим /etc/postfix/main.cf:
1 2 3 4 5 6 7 |
smtpd_use_tls=yes smtpd_tls_auth_only = yes smtpd_tls_cert_file=/etc/letsencrypt/live/example.com/fullchain.pem smtpd_tls_key_file=/etc/letsencrypt/live/example.com/privkey.pem # Эта настройка говорит по возможности слать исходящую почту по TLS # Без нее GMail будет помечать письма как "незашифрованные" smtp_tls_security_level=may |
Затем редактируем /etc/dovecot/conf.d/10-ssl.conf
1 2 3 4 |
ssl = required # символы < перед путями к файлам - не опечатка ssl_cert = </etc/letsencrypt/live/example.com/fullchain.pem ssl_key = </etc/letsencrypt/live/example.com/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, в продолжение.