Self-hosted почта на arch linux, postfix, dovecot и let’s encrypt

—

от автора

В этой статье я покажу, как настроить свой почтовый сервер для аккаунтов локальных пользователей без веб-морд, docker-ов, телеграм-помоек и LLM-высеров.

Жалкие отп^W^W Дисклеймер: я — админ локалхоста. В статье полно англицизмов и недопереведённых терминов.

Что происходит? Где я? Помогите!

Эта статья — перевод моего же поста, по сути копии вот этого немного устаревшего поста в другом блоге (архивная копия) (далее — «оригинальный гайд»), на который мне в своё время очень повезло наткнуться.

Будем настраивать почтовый сервер так, чтобы у каждого пользователя ОС была своя почта, а письма хранились в ~/Maildir.

Индигриенты ©

Понадобятся нам, собственно, сервер на arch linux с белым IP, доменное имя, сертификат и, желательно, reverse DNS.

Сервер должен быть исключительно и только на arch, на других дистрибутивах поднять почтовый сервер принципиально невозможно.

Reverse DNS нас интересует только тем, что позволяет по IP-адресу получить доменное имя, на этот адрес указывающее, а нужен он нам затем, чтобы у почтовых серверов, с которыми будет общаться наш сервер, была yet another проверка, уменьшающая вероятность попадания нашего сервера в спам-листы.

На самом по себе попадании в спам-листы мои полномочия всё, но для выхода из одного того, в который попадал я, достаточно было ткнуть мышкой одну кнопку на сайте спам-листа.

Вычитать reverse DNS для, например, 8.8.8.8 можно вот так (указывает оно на dns.google, точка в конце нас сейчас не интересует):

$ dig -x 8.8.8.8 | grep -vE "^$|^;"8.8.8.8.in-addr.arpa.75882INPTRdns.google.

Выставить reverse DNS можно либо в админке вашего домашнего провайдера или хостера, либо, как сделал я, написав e-mail в поддержку провайдера и попросив выставить нужное значение reverse DNS для вашего IP-адреса. ИЧСХ, мне сделали это за 15 минут без лишних вопросов, я сильно удивился.

Оригинальный гайд использует self-signed сертификат, я использую let’s encrypt, потому что мне даже думать лень о проблемах, связанных с самоподписными сертификатами. Когда-нибудь, думаю, подумаю о проблемах с let’s encrypt, но Леонид Каневский.

Перед тем, как отправлять письма со своего почтового сервера на реальные адреса внешних серверов прямо в процессе настройки своего сервера с мыслью «я, конечно, гайд не дочитал, но а вдруг оно уже работает», потренируйтесь на кошках, иначе есть риск загреметь в спам-листы.

После того как у вас всё заработает, или после последующих изменений конфигов, делайте бекапы. По крайней мере, dovecot не так давно сломал обратную совместимость конфигов. Если у вас под рукой есть бекап конфигов, вы можете откатить версию postfix/dovecot/whatever из /var/cache/pacman/pkg/, а уже потом, имея рабочую почту, спокойно разбираться с новой версией сломанного софта.

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

Что вообще делать со всем нижеизложенным? В каждой главе накатывать указанный софт, потом grep-ать по /etc/<tool-name>, в каких конфигах у вас лежит что-то похожее, и доводить эти конфиги до нужной кондиции.

Сертификаты

$ pacman -S certbot$ certbot -d mydomain.name 

Если у вас это не работает или у вас нет веб-сервера, добро пожаловать в вики: https://wiki.archlinux.org/title/Certbot

Dovecot

https://wiki.archlinux.org/title/Dovecot

Установка

pacman -S dovecot

Настройка

Тип и расположение почты, «папки»

doveconf -n mail_path mail_driver namespace inbox

Вывод:

mail_path = ~/Maildirmail_driver = maildirnamespace inbox {  inbox = yes  separator = /  mailbox Drafts {    special_use = "\\Drafts"  }  mailbox Junk {    special_use = "\\Junk"  }  mailbox Trash {    special_use = "\\Trash"  }  mailbox Sent {    special_use = "\\Sent"  }  mailbox "Sent Messages" {    special_use = "\\Sent"  }}

Добавляем юзера dovecot в группу mail

usermod -aG mail dovecotid dovecot

Вывод:

uid=76(dovecot) gid=76(dovecot) groups=76(dovecot),12(mail)

SSL-сертификаты

SSL

doveconf ssl ssl_server_cert_file ssl_server_key_file ssl_server_dh_file

Вывод:

ssl = yesssl_server_cert_file = /etc/letsencrypt/live/kostovsky.me/fullchain.pemssl_server_key_file = /etc/letsencrypt/live/kostovsky.me/privkey.pemssl_server_dh_file = /etc/dovecot/dh.pem

Аутентификация

doveconf -n userdb passdb

Вывод (имена секций здесь выбраны случайно: с некоторой версии dovecot потребовал их, имена, добавить, я и добавил):

userdb fuck_dovecot {  driver = passwd}passdb fuck_dovecot {  driver = pam}
cat /etc/pam.d/dovecot

Вывод:

#%PAM-1.0auth include system-authaccount include system-authsession include system-authpassword include system-auth

Создаём юзера

Если вдруг у вас его ещё нет. Его логин и будет использоваться в почтовом адресе. У каждого «нормального» пользователя в системе будет свой почтовый ящик, а для логина в почту будет использоваться пароль этого пользователя в ОС.

useradd nikita -mpasswd nikita

Весь итоговый конфиг

Спрятал под спойлер
doveconf -n

Output:

## 2.4.4 (8b687aa65c): /etc/dovecot/dovecot.conf## OS: Linux 7.1.5-arch1-2 x86_64  ## Hostname: home## 29 default setting changes since version 2.4.1dovecot_config_version = 2.4.1auth_mechanisms = plaindovecot_storage_version = 2.4.1mail_driver = maildirmail_path = ~/Maildirprotocols {  imap = yes  lmtp = yes}passdb fuck_dovecot {  driver = pam}userdb fuck_dovecot {  driver = passwd}service director {  listen = * ::  unix_listener login/director {  }  fifo_listener login/proxy-notify {  }  unix_listener director-userdb {  }}service imap-login {  inet_listener imap {  }  inet_listener imaps {  }}service pop3-login {  inet_listener pop3 {  }  inet_listener pop3s {  }}service submission-login {  inet_listener submission {  }  inet_listener submissions {  }}namespace inbox {  inbox = yes  separator = /  mailbox Drafts {    special_use = "\\Drafts"  }  mailbox Junk {    special_use = "\\Junk"  }  mailbox Trash {    special_use = "\\Trash"  }  mailbox Sent {    special_use = "\\Sent"  }  mailbox "Sent Messages" {    special_use = "\\Sent"  }}service lmtp {  unix_listener lmtp {  }}service imap {}service pop3 {}service submission {}service auth {  unix_listener /var/spool/postfix/private/auth {    group = postfix    mode = 0666    user = postfix  }}service auth-worker {}service dict {  unix_listener dict {  }}ssl_server {  cert_file = /etc/letsencrypt/live/kostovsky.me/fullchain.pem  dh_file = /etc/dovecot/dh.pem  key_file = /etc/letsencrypt/live/kostovsky.me/privkey.pem}

Сервис

systemctl enable --now dovecot.service

Если вы используете ufw, загляните в оригинальный гайд, там есть дополнительные настройки и комментарии.

Инструментарий для тестирования

Postfix

https://wiki.archlinux.org/title/Postfix

Установка

pacman -S postfix

Каталоги

postconf -n | grep -E "directory\s"

Вывод:

command_directory = /usr/bindaemon_directory = /usr/lib/postfix/bindata_directory = /var/lib/postfixhtml_directory = nomanpage_directory = /usr/share/manmeta_directory = /etc/postfixqueue_directory = /var/spool/postfixreadme_directory = /usr/share/doc/postfixsample_directory = /etc/postfixshlib_directory = /usr/lib/postfix

Домен

postconf -n | grep ^my

Output:

mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain, mail.$mydomainmydomain = kostovsky.memyhostname = kostovsky.memyorigin = $mydomain

Aliases

postconf -n | grep -E "^alias|newaliases"

Вывод:

alias_database = $alias_mapsalias_maps = lmdb:/etc/postfix/aliasesnewaliases_path = /usr/bin/newaliases

Catch-all email

«Всеперехватывающий»(?) адрес. Здесь автор оригинального гайда указал пользователя, который будет получать почту (в смысле спам), адресованную несуществующим в системе пользователям. У меня здесь пусто.

postconf -n luser_relay local_recipient_maps

Output:

local_recipient_maps =

Шифруемся с помощью TLS

Получение почты:

postconf -n | grep smtpd_ | grep tls

Вывод:

smtpd_sasl_tls_security_options = noanonymoussmtpd_tls_auth_only = yessmtpd_tls_cert_file = /etc/letsencrypt/live/kostovsky.me/fullchain.pemsmtpd_tls_key_file = /etc/letsencrypt/live/kostovsky.me/privkey.pemsmtpd_use_tls = yes

Отправка почты:

postconf -n | grep smtp_ | grep tls

Вывод:

smtp_tls_security_level = may

Аутентификация/авторизация

Конфиг аутентификации postfix:

postconf -n | grep ^smtpd_sasl

Вывод:

smtpd_sasl_auth_enable = yessmtpd_sasl_local_domain = $mydomainsmtpd_sasl_path = private/authsmtpd_sasl_security_options = noanonymous, noplaintextsmtpd_sasl_tls_security_options = noanonymoussmtpd_sasl_type = dovecot

Интеграция с аутентификацией dovecot

doveconf -n service/auth

Вывод:

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

Relay (шлюз?) и ограничения

postconf -n | grep -E "helo|relay"

Вывод:

smtpd_helo_required = yessmtpd_helo_restrictions = reject_invalid_helo_hostname, reject_non_fqdn_helo_hostnamesmtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination

Mail submission

Я не знаю, как и есть ли смысл переводить некоторые словосочетания, но перевод “mail submission” не так уж и необходим для настройки сервера.

postconf -M submission

Вывод:

submission inet  n       -       n       -       -       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_reject_unlisted_recipient=no -o smtpd_relay_restrictions= -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING

DNS-запись TXT

drill -Q kostovsky.me TXTdrill -Q smtp.kostovsky.me TXT

Вывод:

"v=spf1 a mx ip4:195.234.21.24 ~all""v=spf1 a mx ip4:195.234.21.24 ~all"

Запись reverse DNS

drill -Q 195.234.21.24 -x

Вывод:

kostovsky.me.

Весь итоговый конфиг

Спрятал под спойлер
postconf -n

Вывод:

alias_database = $alias_mapsalias_maps = lmdb:/etc/postfix/aliasescommand_directory = /usr/bincompatibility_level = 3.11daemon_directory = /usr/lib/postfix/bindata_directory = /var/lib/postfixdebug_peer_level = 2debugger_command = PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin ddd $daemon_directory/$process_name $process_id & sleep 5home_mailbox = Maildir/html_directory = noinet_protocols = ipv4local_recipient_maps =mail_owner = postfixmailbox_size_limit = 512000000mailq_path = /usr/bin/mailqmanpage_directory = /usr/share/manmessage_size_limit = 512000000meta_directory = /etc/postfixmilter_default_action = acceptmydestination = $myhostname, localhost.$mydomain, localhost, $mydomain, mail.$mydomainmydomain = kostovsky.memyhostname = kostovsky.memynetworks = 10.66.66.0/24myorigin = $mydomainnewaliases_path = /usr/bin/newaliasesnon_smtpd_milters = $smtpd_miltersqueue_directory = /var/spool/postfixreadme_directory = /usr/share/doc/postfixsample_directory = /etc/postfixsendmail_path = /usr/bin/sendmailsetgid_group = postdropshlib_directory = /usr/lib/postfixsmtp_header_checks = regexp:/etc/postfix/smtp_header_checkssmtp_tls_security_level = maysmtpd_banner = eximsmtpd_helo_required = yessmtpd_helo_restrictions = reject_invalid_helo_hostname, reject_non_fqdn_helo_hostnamesmtpd_milters = inet:localhost:8891, inet:localhost:8893smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destinationsmtpd_sasl_auth_enable = yessmtpd_sasl_local_domain = $mydomainsmtpd_sasl_path = private/authsmtpd_sasl_security_options = noanonymous, noplaintextsmtpd_sasl_tls_security_options = noanonymoussmtpd_sasl_type = dovecotsmtpd_tls_auth_only = yessmtpd_tls_cert_file = /etc/letsencrypt/live/kostovsky.me/fullchain.pemsmtpd_tls_key_file = /etc/letsencrypt/live/kostovsky.me/privkey.pemsmtpd_use_tls = yesunknown_local_recipient_reject_code = 550

Сервис

systemctl enable --now postfix.service

Если вы используете ufw, загляните в оригинальный гайд, там есть настройки и комментарии.

Инструментарий для тестирования

Особо упоротые могут быстренько проверить SMTP с помощью openssl:

openssl s_client -connect kostovsky.me:25 -starttls smtp

DomainKeys Identified Mail — DKIM

Установка

https://wiki.archlinux.org/title/OpenDKIM

pacman -S opendkim

Настройка

Минимальный конфиг

grep -v -e '^#' -e '^[[:space:]]*$' /etc/opendkim/opendkim.conf

Вывод:

Canonicalization  relaxed/simpleDomain  kostovsky.meKeyFile  /etc/opendkim/rig.privateSelector  rigSocket                    inet:8891@localhostSyslog  YesUserID                    opendkim:postfix

Генерация файлов ключей

Generate rig.private and rig.txt files.

opendkim-genkey --restrict --selector rig --domain kostovsky.me --directory /etc/opendkim

Интеграция с postfix

postconf -n | grep milter

Вывод:

milter_default_action = acceptnon_smtpd_milters = $smtpd_milterssmtpd_milters = inet:localhost:8891, inet:localhost:8893

Общаться с postfix оно будет через сокет inet:localhost:8891.

DNS-запись TXT

cat /etc/opendkim/rig.txt

Вывод:

rig._domainkeyINTXT( "v=DKIM1; k=rsa; s=email; "          "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA8dfa8T7Hhn5/nWVivUpeBEs339fa9bCUHN7tqWxchzy5vBw/8Z3/9Pp8XIXo/0GnpOCu0Fh4P27tMnIdH5N4Sy3E/XcNHL7cRAB7gqKjEMuT2S49L7j3g19Dns7qN8rbArC7Krzq5mdHPHk1EqGsytGlv9CMD5gegpUsM7wd3QIDAQAB" )  ; ----- DKIM key rig for kostovsky.me
drill -Q rig._domainkey.kostovsky.me TXT

Вывод:

"v=DKIM1; k=rsa; s=email; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA8dfa8T7Hhn5/nWVivUpeBEs339fa9bCUHN7tqWxchzy5vBw/8Z3/9Pp8XIXo/0GnpOCu0Fh4P27tMnIdH5N4Sy3E/XcNHL7cRAB7gqKjEMuT2S49L7j3g19Dns7qN8rbArC7Krzq5mdHPHk1EqGsytGlv9CMD5gegpUsM7wd3QIDAQAB"

Сервис

systemctl enable --now opendkim.service

Инструментарий для тестирования

Domain-based Message Authentication, Reporting and Conformance — DMARC

https://wiki.archlinux.org/title/OpenDMARC

Установка

pacman -S opendmarc

Настройка

Минимальный конфиг

grep -vE "^#|^\s*$" /etc/opendmarc/opendmarc.conf

Вывод:

AuthservID HOSTNAMEIgnoreAuthenticatedClients trueSocket inet:8893@localhostSPFSelfValidate trueUMask 002

Интеграция с postfix

postconf -n | grep milter

Вывод:

milter_default_action = acceptnon_smtpd_milters = $smtpd_milterssmtpd_milters = inet:localhost:8891, inet:localhost:8893

Общаться с postfix оно будет через сокет inet:localhost:8893.

DNS-запись TXT

drill -Q _dmarc.kostovsky.me TXT

Вывод:

"v=DMARC1; p=quarantine; rua=mailto:postmaster@kostovsky.me; ruf=mailto:forensic@kostovsky.me; adkim=s; aspf=s; fo=1; pct=25"

Сервис

systemctl enable --now opendmarc.service

Инструментарий для тестирования

Настройка Thunderbird

У меня весь гуй везде на английском, так что прошу извинить.

Outgoing server

“Account Settings”->“Edit outgoing server…”

  • Server Name: kostovsky.me

  • Port: 587

  • Connection security: STARTTLS

  • Authentication method: Normal password

  • User Name: nikita

Incoming server

“Server settings” section

  • Server Type: IMAP Mail Server

  • Server Name: kostovsky.me

  • Port: 993

  • User Name: nikita

  • Connection security: SSL/TLS

  • Authentication method: Normal password

Вот, вроде бы, всё и готово, но, пожалуйста, без резких движений. Шуруйте на mail-tester или подобный сервис и добивайтесь всех (значимых, содержимое письма не в счёт) зелёных галочек из всех, прежде чем отправить своё первое письмо на реальный внешний почтовый адрес.

ссылка на оригинал статьи https://habr.com/ru/articles/1070196/