Настраиваем Dovecot
Устанавливаем пакет dovecot-postfix который автоматически установит dovecot и настроит postfix на использование SASL. Также этот пакет настроит dovecot для IMAP, IMAPS, POP3, и POP3S.
apt-get install dovecot-postfix
Приступаем к настройке dovecot.
Создадим пользователя для почты
useradd -d /bin/false vmail
Создадим папку для почты и установим на неё права
mkdir /home/mail && chown vmail:mail /home/mail
Зайдём в папку dovecot
cd /etc/dovecot
На данный момент dovecot не настроен на использование виртуальных пользователей из ldap, а так же пакет dovecot-postfix разделил конфигурацию dovecot на несколько файлов
dovecot.conf auth.d/01-dovecot-postfix.auth conf.d/01-dovecot-postfix.conf
лично мне это не удобно, поэтому я сделал копию текущего dovecot.conf
mv dovecot.conf dovecot.conf.bak1
и создал свой dovecot.conf
> dovecot.conf
следующего содержания
# Поддерживаемые протоколы protocols = imap pop3 imaps pop3s managesieve log_timestamp = "%Y-%m-%d %H:%M:%S " mail_privileged_group = mail # Отключаем plaintext аутентификацию disable_plaintext_auth = yes # Включаем ssl ssl = yes ssl_cert_file = /etc/ssl/certs/mydovecot.pem ssl_key_file = /etc/ssl/private/server.key ssl_ca_file = /etc/ssl/certs/cacert.pem ssl_cipher_list = ALL:!LOW:!SSLv2:ALL:!aNULL:!ADH:!eNULL:!EXP:RC4 RSA: HIGH: MEDIUM # Место нахождения почтовых папок mail_location = maildir:/home/mail/%d/%u # Символы используемые для аутентификации auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@ # Допустимый интервал UID для пользователей first_valid_uid = 1000 last_valid_uid = 50000 # Интервал для группы. Минимальный GID для группы у меня выставлен в 8, т.к. под этим номером у # меня находится группа mail. first_valid_gid = 8 last_valid_gid = 50000 # Пользователь и группа от которых будет работать dovecot с почтой mail_uid = vmail mail_gid = mail # Пути к логам dovecot log_path = /var/log/dovecot.log info_log_path = /var/log/dovecot_info.log # Конфигурация IMAP протокола protocol imap { mail_max_userip_connections = 10 imap_client_workarounds = outlook-idle delay-newmail mail_plugins = quota imap_quota } # Конфигурация POP3 протокола protocol pop3 { pop3_uidl_format = XuXv mail_max_userip_connections = 10 pop3_client_workarounds = outlook-no-nuls oe-ns-eoh mail_plugins = quota } # Конфигурация LDA протокола protocol lda { postmaster_address = [email protected] mail_plugins = sieve quota quota_full_tempfail = yes deliver_log_format = msgid=%m: %$ rejection_reason = Your message to <%t> was automatically rejected:%n%r } protocol managesieve { } auth default { # Механизмы аутентификации mechanisms = plain login # База паролей passdb ldap { args = /etc/dovecot/dovecot-ldap.conf } # База пользователей userdb ldap { args = /etc/dovecot/dovecot-ldap.conf } socket listen { master { path = /var/run/dovecot/auth-master mode = 0600 user = vmail group = mail } client { path = /var/spool/postfix/private/dovecot-auth mode = 0660 user = postfix group = postfix } } user = vmail } dict { } # Конфигурация плагинов plugin { sieve=/home/mail/%d/%u/.dovecot.sieve sieve_dir=/home/mail/%d/%u/sieve quota = maildir:User quota quota_rule = *:storage=0B quota_rule2 = Trash:ignore } # Эти опции включают отладочные сообщения, раскоментируйте их # на стадии тестирования, но потом их лучше отключить #mail_debug = yes #verbose_ssl = yes #auth_verbose = yes #auth_debug = yes #auth_debug_passwords = yes
Теперь необходимо настроить подключение к ldap, переименовываем файл настроек ldap
mv dovecot-ldap.conf dovecot-ldap-example.conf
и создаём свой dovecot-ldap.conf
> dovecot-ldap.conf
слеждующего содержания
# Хост на котором работает ldap uris = ldaps://ldap.example.com # Админ ldap и его пароль dn = cn=admin,dc=example,dc=com dnpass = secret # Пути к сертификатам для tls соединения tls_ca_cert_file = /etc/ssl/certs/ mail_server_ldap_ca.pem tls_ca_cert_dir = /etc/ssl/certs tls_cert_file = /etc/ssl/certs/mail_server_ldap_cert.pem tls_key_file = /etc/ssl/private/mail_server_ldap_key.pem # Отладочные сообщения при соединении с ldap, после окончания тестирования лучше отключить #debug_level = -1 # Поиск в ldap будет проходить не от пользователя проходящего аутентификацию auth_bind = no # Версия протокола ldap ldap_version = 3 # Где искать пользователя base = dc=example,dc=com deref = never scope = subtree # Соответствие ldpa и dovecot переменных (слева ldap, справа dovecot) pass_attrs = mail=user,userPassword=password # Фильтр для проверки паролей pass_filter = (&(objectClass=gosaMailAccount)(mail=%u)) # Здесь переменным home, uid, gid присваиваются фиксированные значения, а значение quota_rule # берётся в ldap из параметра gosaMailQuota, 1001 и 8 это uid пользователя vmail и gid группы mail user_attrs = =home=/home/mail/%d/%u, =uid=1001, =gid=8, gosaMailQuota=quota_rule=?:storage=%$B # Фильтр для выборки пользователей user_filter = (&(objectClass=gosaMailAccount)(mail=%u)) # Метод шифрования паролей в ldap default_pass_scheme = MD5
Не знаю с чем это связано но для того чтоб dovecot смог соединиться с ldap на другом сервере по tls, необходимо чтоб на сервере с dovecot присутствовал файл /etc/ldap/ldap.conf в котором находится строка
TLS_CACERT /etc/ssl/certs/mail_server_ldap_ca.pem
в ubuntu 10.04 этот файл присутствует, поэтому просто добавляем в него выше указанную строку.
echo "TLS_CACERT /etc/ssl/certs/mail_server_ldap_ca.pem" >> /etc/ldap/ldap.conf
Перезагружаем dovecot
/etc/init.d/dovecot restart
Настраиваем postfix
Конфигурируем main.cf
# Настраиваем tls и SASL postconf -e 'smtpd_tls_key_file = /etc/ssl/private/server.key' postconf -e 'smtpd_tls_cert_file = /etc/ssl/certs/postfix.pem' postconf -e 'smtpd_tls_CAfile = /etc/ssl/certs/cacert.pem' postconf -e 'smtpd_tls_loglevel = 1' postconf -e 'smtpd_tls_session_cache_timeout = 3600s' postconf -e 'smtp_tls_note_starttls_offer = yes' postconf -e 'smtpd_sasl_local_domain =' # Почта будет находится в каталоге /home/mail/domain/user_mail поэтому значение home_mailbox # должно быть пустым, mailbox_command выполняться не будет поэтому тоже пусто postconf -e 'home_mailbox =' postconf -e 'mailbox_command =' # Домен почтового сервера postconf -e 'mydomain = example.com' postconf -e 'myorigin = $mydomain' # Отклонять команду ETRN postconf -e 'smtpd_etrn_restrictions = reject' # Дополнительные ограничения, применяемые сервером Postfix в контексте команды MAIL FROM postconf -e 'smtpd_sender_restrictions = reject_sender_login_mismatch, reject_unlisted_sender, reject_unknown_sender_domain' # Дополнительные ограничения, применяемые сервером Postfix в контексте команды RCPT TO postconf -e 'smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_non_fqdn_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unverified_recipient, reject_invalid_hostname, reject_multi_recipient_bounce, reject_unknown_sender_domain, reject_unknown_recipient_domain, reject_unauth_pipelining, reject_unauth_destination' # Настройка виртуальных пользователей, здесь 1001 и 8 это uid и gid пользователя vmail и группы mail postconf -e 'virtual_mailbox_base = /home/mail' postconf -e 'virtual_mailbox_domains = ldap:/etc/postfix/ldap_virtual_domains_maps.cf' postconf -e 'virtual_mailbox_maps = ldap:/etc/postfix/ldap_virtual_mailbox_maps.cf' postconf -e 'virtual_alias_maps = ldap:/etc/postfix/ldap_virtual_alias_maps.cf' postconf -e 'virtual_uid_maps = static:1001' postconf -e 'virtual_gid_maps = static:8' postconf -e 'virtual_minimum_uid = 1000' # Устанавливаем dovecot в качестве транспорта postconf -e 'virtual_transport = dovecot' postconf -e 'mailbox_transport = dovecot' postconf -e 'dovecot_destination_recipient_limit = 1' # Настраиваем квоту postconf -e 'virtual_create_maildirsize = yes' postconf -e 'virtual_maildir_extended = yes' postconf -e 'virtual_mailbox_limit_override = yes' postconf -e 'virtual_overquota_bounce = yes' postconf -e 'virtual_mailbox_limit_maps = ldap:/etc/postfix/ldap_virtual_mailbox_limit_maps.cf' postconf -e 'virtual_maildir_limit_message = Sorry, the users mailbox is full, please try again later.' # Здесь к значениям по умолчанию добавляются $virtual_mailbox_limit_maps и # $smtpd_sender_login_maps postconf -e 'proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $sender_bcc_maps $recipient_bcc_maps $smtp_generic_maps $lmtp_generic_maps $virtual_mailbox_limit_maps $smtpd_sender_login_maps' # Не разрешает отправку сообщений от другого пользователя # Логин пользователя для отправки сообщений и MAIL FROM должны совпадать postconf -e 'smtpd_sender_login_maps = ldap:/etc/postfix/ldap_logins.cf' # Отключаем команду VRFY postconf -e 'disable_vrfy_command = yes' # Ставить исходящие сообщения в очередь postconf -e 'defer_transports=smtp'
Теперь заходим в файл /etc/postfix/master.cf, убираем комментарий со строк
smtps inet n - - - - smtpd -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes -o smtpd_client_restrictions=permit_sasl_authenticated,reject
и добавляем в конец файла строки
dovecot unix - n n - - pipe flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/deliver -d ${recipient}
Осталось создать файлы запросов к LDAP серверу
К сожалению мне не удалось подключиться к LDAP по защищённому соединению ldaps. При попытке подключения по ldaps или start_tls в логах появляются строки
warning: process /usr/lib/postfix/trivial-rewrite pid 1289 killed by signal 6 warning: /usr/lib/postfix/trivial-rewrite: bad command startup — throttling
и postfix наотрез отказывается принимать почту. В связи с эти файлы запросов соединяются с ldap через не защищённое соединение. Если кто решил данную проблему или знает с чем это связано, поделитесь пожалуйста буду очень признателен. Лично я перерыл весь инет но решение так и не нашёл.
И так создаём файлы запросов в папке /etc/postfix
Файл ldap_logins.cf
# адрес LDAP-сервера server_host = ldap://ldap_server_ip/ # где искать людей search_base = ou=Users,dc=example,dc=com # версия протокола version = 3 # какие записи отфильтровывать # брать только тех, у кого создан почтовый акаунт query_filter = (&(objectClass=gosaMailAccount)(|(mail=%s)(gosaMailAlternateAddress=%s))) # требуемый атрибут result_attribute = mail # DN-запись для подключения к LDAP bind_dn = cn=admin,dc=example,dc=com bind_pw = secret
Файл ldap_virtual_alias_maps.cf
# адрес LDAP-сервера server_host = ldap://ldap_server_ip/ # где искать людей search_base = ou=Users,dc=example,dc=com # версия протокола version = 3 # какие записи отфильтровывать # брать только тех, у кого создан почтовый акаунт query_filter = (&(objectClass=gosaMailAccount)(|(mail=%s)(gosaMailAlternateAddress=%s))) # требуемый атрибут - мы забираем mail result_attribute = mail # DN-запись для подключения к LDAP bind_dn = cn=admin,dc=example,dc=com bind_pw = secret
Файл ldap_virtual_domains_maps.cf
# адрес LDAP-сервера server_host = ldap://ldap_server_ip/ # где искать домены search_base = ou=servers,ou=systems,dc=example,dc=com # версия протокола version = 3 # какие записи отфильтровывать # брать только текущий почтовый сервер, ip указывается текущего почтового сервера query_filter = (&(objectClass=goMailServer)(ipHostNumber=192.168.0.2)(postfixMyDestinations=%s)) # требуемый атрибут - мы забираем список доменов result_attribute = postfixMyDestinations # DN-запись для подключения к LDAP bind_dn = cn=admin,dc=example,dc=com bind_pw = secret
Файл ldap_virtual_mailbox_limit_maps.cf
# адрес LDAP-сервера server_host = ldap://ldap_server_ip/ # где искать пользователей search_base = ou=Users,dc=example,dc=com # версия протокола version = 3 # какие записи отфильтровывать # брать только тех, у кого создан почтовый акаунт query_filter = (&(objectClass=gosaMailAccount)(|(mail=%s)(gosaMailAlternateAddress=%s))) # требуемый атрибут - мы забираем квоту result_attribute = gosaMailQuota # DN-запись для подключения к LDAP bind_dn = cn=admin,dc=example,dc=com bind_pw = secret
Файл ldap_virtual_mailbox_maps.cf
# адрес LDAP-сервера server_host = ldap://ldap_server_ip/ # где искать людей search_base = ou=Users,dc=example,dc=com # версия протокола version = 3 # какие записи отфильтровывать # брать только тех, у кого создан почтовый акаунт query_filter = (&(objectClass=gosaMailAccount)(mail=%s)) # требуемый атрибут - мы забираем mail и gosaMailForwardingAddress result_attribute = mail, gosaMailForwardingAddress # по каким путям будет создаваться папка для юзера и подпапки (%d/ будет создаваться подпапка с # доменом вида domain.dom/mail_adress/) result_format = %d/%s/ # DN-запись для подключения к LDAP bind_dn = cn=admin,dc=example,dc=com bind_pw = secret
Перезагружаем postfix
/etc/init.d/postfix restart
Разрешим группе mail писать логи в файлы dovecot.log и dovecot_info.log, если этого не сделать postfix не будет принимать почту
chown root:mail /var/log/dovecot* && chmod 660 /var/log/dovecot*
На этом настройка postfix и dovecot закончена.
Отправка писем из очереди
Всю почту отправляемую во внешний мир postfix ставит в очередь, для того чтоб письма из очереди доставлялись адресатам необходимо выполнить команду postfix flush. Добавим в crontab эту команду, так чтоб письма в очереди отправлялись каждую минуту
crontab -e (выбираем редактор)
и добавляем следующее
* * * * * /usr/sbin/postfix flush
в результате письма из очереди будут отправляться каждую минуту.
Всё почтовый сервер готов к использованию.
P.S. Лично мне не удобно использовать в качестве логина email пользователя. Мой почтовый сервер обслуживает один домен, поэтому я немного модифицировал запрос получения пароля из ldap в dovecot-ldap.conf, изменив в нём одну строку с
pass_filter = (&(objectClass=gosaMailAccount)(mail=%u))
на
pass_filter = (&(objectClass=gosaMailAccount)(mail=%n@*))
при таком варианте в качестве логина нужно использовать имя пользователя (к примеру если email пользователя [email protected] то в качестве логина нужно использовать test).
ВНИМАНИЕ!!! Данный вариант работает только если ваш сервер обслуживает один домен, на серверах где больше одного домена не тестировалось, скорей всего работать не будет так как на разных доменах могут быть одинаковые пользователи.
Итак почтовый сервер настроен и работает, хотелось бы чтоб почта приходящая на него проверялась на наличие вирусов и на спам. Для решения этой задачи существует множество способов, лично мне в качестве спам фильтра больше нравится Dspam, но возможности amavisd-new меня тоже устраивают, поэтому в следующей статье я попробую скрестить Dspam, Amavisd-new и ClamAV
Обсудить данную статью можно на форуме.
Base¶
LDAP base. %variables (see Config Variables) can be used here.
Example:
Debug_level¶
LDAP library debug level as specified by LDAP_DEBUG_* in ldap_log.h.
Value -1 means everything. You may need to recompile OpenLDAP with debugging enabled
to get enough output.
Deref¶
Specify dereference which is set as an LDAP option.
Dnpass¶
Password for LDAP server, used if dn is specified.
Dovecot
While Postfix serves as an smtp
server and relay, Dovecot
will serve as IMAP
server to retrieve the messages stored on the mail host. Dovecot also includes a SASL implementation which can be used by postfix to authenticate users.
Dovecot packages can be installed from the Debian repository.
root@mailhost:~# apt-get install dovecot-core dovecot-imapd dovecot-ldap
Hosts¶
A space separated list of LDAP hosts to connect to.
Configure either this setting or uris to specify
what LDAP server(s) to connect to.
You can also use host:port syntax to use different ports.
Example:
See also uris
Ldap — dovecot documentation
Both of these have their own advantages and disadvantages.
Ldap mapping
Before configuring postfix to deliver and receive mail, we create some LDAP lookup tables postfix will use to query the direcotry. The next table gives an overview on how information is queried.
Create a directory /etc/postfix/ldap
to keep all map definitions in one place. Since the files in this directory will contain your LDAP credentials, set its owner to postfix:postfix
and its mode to 0100
.
The connection information for your LDAP directory is common to all maps and can be copied to the top of all of them.
server_host = ldap://ldap.example.com start_tls = yes version = 3 tls_ca_cert_file = /etc/ldap/tls/CA.pem tls_require_cert = yes bind = yes bind_dn = cn=mailAccountReader,ou=Manager,dc=example,dc=com bind_pw = <Password for bind_dn> search_base = ou=Mail,dc=example,dc=com scope = sub
This will connect to the LDAP directory using TLS and check the validity of the certificate provided by the peer. This needs to be included into all files in /etc/postfix/ldap
listed next.
- virtual_alias_domains
query_filter = mailacceptinggeneralid=*@%s result_attribute = mailacceptinggeneralid result_format = %d
- virtual_alias_maps
query_filter = mailacceptinggeneralid=%s result_attribute = maildrop
- virtual_mailbox_maps
query_filter = maildrop=%s result_attribute = homeDirectory result_format = %s/mailbox/
- virtual_uid_maps
query_filter = maildrop=%s result_attribute = uidNumber
- smtpd_sender_login_maps
query_filter = (|(mailacceptinggeneralid=%s)(maildrop=%s)) result_attribute = uid
You can test the mapping with the postmap
command. Here is some sample output for the user created for testing.
root@mailhost:~# postmap -q hosted-domain.com ldap:/etc/postfix/ldap/virtual_alias_domains hosted-domain.com, hosted-domain.com root@mailhost:~# postmap -q [email protected] ldap:/etc/postfix/ldap/virtual_mailbox_maps /home/mail/mail000/mailbox/ root@mailhost:~# postmap -q [email protected] ldap:/etc/postfix/ldap/virtual_uid_maps 20000 root@mailhost:~# postmap -q [email protected] ldap:/etc/postfix/ldap/smtpd_sender_login mail000
If lookups don’t work as expected, set debuglevel = -1
in the map definition and review the output when running postmap
.
Since the files contain credentials for binding to the directory make sure to set proper file permissions.
root@mailhost:~# chown postfix:postfix /etc/postfix/ldap/* root@mailhost:~# chmod 400 /etc/postfix/ldap/*
Another problem to solve is that postfix will run in a chrooted environment (/var/spool/postfix
) and will not be conscious about the CA certificate /etc/ldap/tls/CA.pem
needed to validate the server’s certificate. To counter this problem, create /var/spool/postfix/etc/ldap/tls/
and either copy /etc/ldap/tls/CA.pem
to this directory, or create a bind mount to make the CA certificate available in both locations.
root@mailhost:~# mkdir -p /var/spool/postfix/etc/ldap/tls root@mailhost:~# touch /var/spool/postfix/etc/ldap/tls/CA.pem root@mailhost:~# mount --bind /etc/ldap/tls/CA.pem /var/spool/postfix/etc/ldap/tls/CA.pem
Be aware that this won’t persist through reboots, so make sure to bind the directory before postfix is started. This can be achieved with a systemd
mount unit. Create /etc/systemd/system/var-spool-postfix-etc-ldap-tls-CA.pem.mount
with following content.
- var-spool-postfix-etc-ldap-tls-CA.pem.mount
[Unit] Description=Bind /etc/ldap/tls/CA.pem to /var/spool/postfix/etc/ldap/tls/CA.pem Before=postfix.service [Mount] What=/etc/ldap/tls/CA.pem Where=/var/spool/postfix/etc/ldap/tls/CA.pem Type=none Options=bind [Install] WantedBy=postfix.service
Reload systemd
and start the unit.
root@mailhost:~# systemctl daemon-reload root@mailhost:~# systemctl start var-spool-postfix-etc-ldap-tls-CA.pem.mount root@mailhost:~# mount | grep CA
Check the output of mount
to see if the bind was successful and enable the bind mount to be set up before postfix on boot.
root@mailhost:~# systemctl enable var-spool-postfix-etc-ldap-tls-CA.pem.mount Created symlink from /etc/systemd/system/postfix.service.wants/var-spool-postfix-etc-ldap-tls-CA.pem.mount to /etc/systemd/system/var-spool-postfix-etc-ldap-tls-CA.pem.mount.
Reboot the host to see if the bind is created during boot.
Ldap_version¶
LDAP protocol version to use. Likely 2 or 3.
Ldaprc_path¶
If a non-empty value is set, it will be set to the LDAPRC environment variable.
Sasl_bind¶
Set yes to use SASL binding instead of the simple binding. Note that this changes
ldap_version automatically to be 3 if it’s lower.
Sasl_mech¶
SASL mechanism names (a space-separated list of candidate mechanisms) to use.
Sasl_realm¶
SASL realm to use.
Scope¶
This specifies the search scope.
The hostname
The very first parameter to configure is the myhostname
directive. This is the hostname of the mail server, and should be the same as the MX
record of the domains this server will receive mails for. It also should be set as PTR record for the IP address this hostname resolves to, since it is common to block mail from hosts where this is not the case. To check this out perform a reverse lookup with dig -x <IP address>
.
- main.cf
myhostname = mail.example.com
The mailboxes
Postfix implements different methods to deliver mail to the recipient. In this setup we will make use of the virtual alias domain class and the virtual mailbox domain class. Each final mailbox is associated with a definite address <username>@$myhostname
. $myhostname
contains the hostname set in /etc/postfix/main.cf
and will be listed in virtual_mailbox_domains
. All hosted domains are treated as virtual alias domains, and will be listed in virtual_alias_domains
with the LDAP map defined earlier and mapped to the address of the final mailbox.
The testuser mail000
as created in the LDAP section contains the adresses [email protected]
and [email protected]
as mailacceptinggeneralid
. When a mail is received for one of these addresses, postfix will look for the corresponding maildrop
attribute, which could either be a remote address (e.g. to just forward to a Gmail address), or an address with a domain listed in virtual_mailbox_domains
, e.g. [email protected]
. Mails to domains listed in virtual_mailbox_domains
will be stored in the user’s mailbox. Information on where and how to create the mailbox is also retrieved from LDAP, using the mailbox address.
- /etc/postfix/main.cf
myhostname = mail.example.com virtual_alias_domains = ldap:/etc/postfix/ldap/virtual_alias_domains virtual_mailbox_domains = $myhostname virtual_alias_maps = ldap:/etc/postfix/ldap/virtual_alias_maps virtual_mailbox_base = / virtual_mailbox_maps = ldap:/etc/postfix/ldap/virtual_mailbox_maps virtual_uid_maps = ldap:/etc/postfix/ldap/virtual_uid_maps virtual_gid_maps = ldap:/etc/postfix/ldap/virtual_uid_maps smtpd_sender_login_maps = ldap:/etc/postfix/ldap/smtpd_sender_login_maps
It is very important to list each domain only once. E.g. do not list $myhostname
in mydestination
or virtual_alias_domains
when already listed in virtual_mailbox_domains
.
virtual_alias_domains
will expand to all domains used in addresses given in any mailacceptinggeneralid
attribute in the ou=Mail,dc=example,dc=com
subtree.
The mailboxes will be stored in maildir format if the value returned by the virtual_mailbox_maps
map ends with /
. The value returned will be appended to virtual_mailbox_base
. The map used in this setup will return the path stored in the user’s homedirectory
attribute, with /mailbox/
appended. So for the testuser created earlier, mail to [email protected]
and [email protected]
will first be redirected to [email protected]
and then stored to /home/mail/mail000/mailbox/
in maildir format.
The directory /home/mail
containing the user homes must be created in advance and must be writeable by all potential mail users. To achieve this, either use the same GID
across all mail users and set group ownership to that GID
, or make the directory world writable.
root@mailhost:~# mkdir -p /home/mail root@mailhost:~# chmod o w /home/mail # Make world writable or root@mailhost:~# chown :<common GID> /home/mail && chmod g w /home/mail # use common group
The user specific directories will be created with the user’s UID
and GID
and minimal permissions by postix when mail is received.
Reload postfix and try to send a test mail to your new server.
root@mailhost:~# systemctl reload postfix root@mailhost:~# tail -f /var/log/mail.info
When the mail is received, the logs should contain something like
.../smtpd[6693]: connect from unknown[xxxx:...] .../smtpd[6693]: A7D1665808DE: client=unknown[xxxx:...] .../cleanup[6697]: A7D1665808DE: message-id=<[email protected]> .../qmgr[5561]: A7D1665808DE: from=<[email protected]>, size=892, nrcpt=1 (queue active) .../smtpd[6693]: disconnect from unknown[xxx:...] .../virtual[6698]: A7D1665808DE: to=<[email protected]>, orig_to=<[email protected]>, relay=virtual, delay=0.42, delays=0.31/0.01/0/0.1, dsn=2.0.0, status=sent (delivered to maildir) .../qmgr[5561]: A7D1665808DE: removed
then check if the maildir got created
root@mailhost:~# tree -pug /home/mail/mail000/ /home/mail/mail000/ └── [drwx------ 20000 20000 ] mailbox ├── [drwx------ 20000 20000 ] cur ├── [drwx------ 20000 20000 ] new │ └── [-rw------- 20000 20000 ] 1458124575.V902I1b800feM892045.mx0 └── [drwx------ 20000 20000 ] tmp
Tls and submission service
To avoid sniffing of the data exchanged with postfix, TLS
needs to be enabled and configured properly. It is recommended to at least use a keylength of 2048 bit for the RSA key, and to provide a valid certificate with a correct common name (CN
), signed by a well-known certificate authority. If you don’t want to pay any money, consider Let’s Encrypt as a free alternative. It is also advised to generate your own Diffie-Hellman groups with at least 2048 bit due to some weaknesses found with the commonly and widely used Diffie-Hellman groups.
To generate a group with 4096 bit, run
root@mailhost:~# openssl dhparam 4096 > /etc/postfix/dhparam/dh4096.pem
Generating a new group once in a while will increase security.
TLS support needs to be configured for the server side (smtpd_tls_*
) of postfix, to encrypt and authenticate the connection when receiving mail as well as the client side (smtp_tls_*
) for securing delivery to external MTAs.
- main.cf
smtpd_tls_cert_file = /etc/postfix/tls/server.crt smtpd_tls_key_file = /etc/postfix/tls/server.key smtpd_tls_loglevel = 1 smtpd_tls_received_header = yes smtpd_tls_security_level = may smtpd_tls_auth_only = yes smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3 #tls_preempt_cipherlist = yes tls_disable_workarounds = 0xFFFFFFFFFFFFFFFF smtpd_tls_mandatory_ciphers = high smtpd_tls_exclude_ciphers = aNULL, eNULL, EXPORT, DES, RC4, MD5, PSK, aECDH, EDH-DSS-DES-CBC3-SHA, EDH-RSA-DES-CDB3-SHA, KRB5-DES, CBC3-SHA smtpd_tls_dh1024_param_file = /etc/postfix/dhparam/dh4096.pem smtpd_tls_eecdh_grade = ultra
This configuration for the smtpd
side is quite secure but restrctive and might not work with all MTAs.
smtpd_tls_mandatory_ciphers
sets the ciphersuite allowed to be used and is set to high
. To see what ciphers belong to this group run postconf tls_high_cipherlist
.
smtpd_tls_exclude_ciphers
contains a list of insecure ciphers and is recommended by the research group mentioned above.
tls_preempt_cipherlist
enables server cipher preferences when set to yes
. This means that instead of the client, postfix will select the cipher used for communication. This might cause some interoperability issues, see the postfix documentation for more information.
tls_disable_workarounds
set to 0xFFFFFFFFFFFFFFFF
disables all OpenSSL bug work-arounds on a 64 bit system since they can create unexpected security issues.
smtpd_tls_security_level
is set to may
which means that encryption is optional. Changing this to encrypt
will enforce the use of TLS
but has the side effect that MTAs without TLS capability won’t be able to deliver mail to your server.
smtpd_tls_auth_only
enforces encryption during authentication independently from smtpd_tls_security_level
.
smtpd_tls_dh1024_param_file
sets the path to the Diffie-Hellman group and despite the name can (and should!) be larger than 1024 bit.
smtpd_tls_eecdh_grade
selects the curves used by postfix for ephemeral ECDH key exchange. ultra
selects the curve set in tls_eecdh_ultra_curve
(see postconf tls_eecdh_ultra_curve
) and is the strongest setting available, but needs approximately twice the computational cost of the strong
setting.
To debug TLS connections smtpd_tls_loglevel
is set to at least 1
.
smtpd_tls_received_header
set to yes
will add information about the ciphers used during transfer to the message headers.
- main.cf
smtp_tls_security_level = verify smtp_tls_CApath = /etc/ssl/certs smtp_tls_loglevel = $smtpd_tls_loglevel smtp_tls_mandatory_protocols = $smtpd_tls_mandatory_protocols smtp_tls_mandatory_ciphers = $smtpd_tls_mandatory_ciphers smtp_tls_exclude_ciphers = $smtpd_tls_exclude_ciphers
For the smtp
side, smtp_tls_loglevel
, smtp_tls_mandatory_protocols
, smtp_tls_mandatory_ciphers
and smtp_tls_exclude_ciphers
are set to the same values as their smtpd
counterparts. smtp_tls_security_level
set to verify
enforces encryption when delivering mail. The connection to the external MTA will fail if TLS is not supported or the certificate of the remote site can’t be verified. To verify the certificate the CA certificates in smtp_tls_CApath
are used. This can cause mail to be deferred if the peer certificate was self signed or expired. To handle this issue, either use the less secure encrypt
option or set delay_warning_time
to a suitable value to get a notification if your mail was deferred.
If you set smtpd_tls_security_level
to may
or tls_preempt_cipherlist
to no
, it is good practice to provide a second instance of smtpd
listening on port 587
with smtpd_tls_security_level
set to encrypt
and tls_preempt_cipherlist
set to yes
. This instance should then be used by users to submit mails for delivery (outgoing SMTP server).
To enable the submission service edit /etc/postfix/master.cf
and uncomment the relevant lines.
- master.cf
... submission inet n - - - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o tls_preempt_cipherlist=yes
Reload postfix, and check /var/log/mail.*
for any errors. Also check if the submission service is listening on port 587.
root@mailhost:~# systemctl reload postfix root@mailhost:~# netstat -pltn | grep master
Tls_ca_cert_dir¶
Specify a value for TLS tls_ca_cert_dir option.
Currently supported only with OpenLDAP.
Tls_ca_cert_file¶
Specify a value for TLS tls_ca_cert_file option.
Currently supported only with OpenLDAP.
Tls_cert_file¶
Specify a value for TLS tls_cert_file option.
Currently supported only with OpenLDAP.
Tls_cipher_suite¶
Specify a value for TLS tls_cipher_suite option.
Currently supported only with OpenLDAP.
Tls_key_file¶
Specify a value for TLS tls_key_file option.
Currently supported only with OpenLDAP.
Tls_require_cert¶
Specify a value for TLS tls_require_cert option.
Currently supported only with OpenLDAP.
Uris¶
LDAP URIs to use.
Configure either this setting or hosts to specify
what LDAP server(s) to connect to.
Note that this setting isn’t supported by all LDAP libraries.
The URIs are in syntax protocol://host:port.
Example:
See also hosts
Расширенная настройка exim и dovecot с привязкой к openldap
CONFIG_PREFIX=/etc/exim
ACL_PREFIX=CONFIG_PREFIX/acls #здесь хранятся все ACL конфиги
DB_PREFIX=/var/spool/exim/db #для увеличения быстродействия желательно использовать tmpfs
# Шаблоны являются сильной стороной Exim и позволяют легко заменить длинную строку коротким словом.
# Определяем шаблоны для mailman
MM_HOME=/var/lib/mailman
MM_UID=mailman
MM_GID=mailman
MM_WRAP=/usr/lib/mailman/mail/mailman
MM_LISTCHK=MM_HOME/lists/${lc::$local_part}/config.pck
ldap_default_servers = /var/run/openldap/slapd.sock: 192.168.0.1 # Указываем как соединяться к лдап-серверам, второй сервер будет использоваться как fallback.
INTERFACE = your_external_ip # Указываем внешний айпи, на котором будет висеть exim
BASEDN = dc=domain,dc=com # basedn лдап сервера
# В этой секции указаны самые важные темплейты, задающие логику работы Exim
# Проверка альяса, соответствует ли адрес альяса значению атрибута mail в контейнере aliases, альяс также должен принадлежать классу VirtualMailAlias и иметь значение TRUE для атрибута accountActive
CHECK_1 = ${lookup ldap {user=«uid=exim,ou=services,dc=domain,dc=com» pass=*** ldap:///ou=aliases,dc=domain,dc=com?mail?sub?(&(objectClass=VirtualMailAlias)(accountActive=TRUE)(mail=${quote_ldap:$local_part@$domain}))} }
# Проверка аккаунта, соответствует ли адрес получателя значению атрибута mail в контейнере people, аккаунт также должен принадлежать к классу VirtualMailAccount и иметь значение TRUE для атрибута accountActive
CHECK_2 = ${lookup ldap {user=«uid=exim,ou=services,dc=domain,dc=com» pass=*** ldap:///ou=people,dc=domain,dc=com?mail?sub?(&(objectClass=VirtualMailAccount)(accountActive=TRUE)(mail=${quote_ldap:$local_part@$domain}))} }
#Проверка suspended аккаунта, аккаунт не может получать почту, но остается в системе (актуально для сотрудниц в материнском отпуске)
CHECK_3 = ${lookup ldap {user=«uid=exim,ou=services,dc=domain,dc=com» pass=*** ldap:///ou=people,dc=domain,dc=com?mail?sub?(&(objectClass=VirtualMailAccount)(accountActive=TRUE)(accountSuspend=TRUE)(mail=${quote_ldap:$local_part@$domain}))} }
# Список участников альяса, кому пересылать почту, значение аттрибута maildrop
CHECK_DATA = ${lookup ldapm {user=«uid=exim,ou=services,dc=domain,dc=com» pass=*** ldap:///ou=aliases,dc=domain,dc=com?maildrop?sub?(&(objectClass=VirtualMailAlias)(mail=${quote_ldap:$local_part@$domain}))}}
# Путь к почтовому ящику, значение аттрибута mailbox
CHECK_MAILDIR = ${lookup ldap {user=«uid=exim,ou=services,dc=domain,dc=com» pass=*** ldap:///ou=people,dc=domain,dc=com?mailbox?sub?(&(objectClass=VirtualMailAccount)(accountActive=TRUE)(mail=${quote_ldap:$local_part@$domain}))} }
# Текст OoO сообщения, значение аттрибута vacationInfo
CHECK_VACATION = ${lookup ldap {user=«uid=exim,ou=services,dc=domain,dc=com» pass=*** ldap:///ou=people,dc=domain,dc=com?vacationInfo?sub?(&(objectClass=VirtualMailAccount)(vacationActive=TRUE)(mail=${quote_ldap:$local_part@$domain}))}}
#Hack for double commas in OoO message, exim’s bug 660 — кажется так и не исправили
VACATION = ${sg{ ${lookup ldap {user=«uid=exim,ou=services,dc=domain,dc=com» pass=*** ldap:///ou=people,dc=domain,dc=com?vacationInfo?sub?(&(objectClass=VirtualMailAccount)(vacationActive=TRUE)(mail=${quote_ldap:$local_part@$domain}))}} }{,,}{,}}
domainlist_cache virt_domains = domain.com # Так как у нас только один домен, то указываем его. Если используется множество доменов, то нужно создать темплейт выборки доменов из лдап базы.
domainlist_cache local_domains = localhost: mail.domain.com
hostlist relay_from_hosts = 127.0.0.1: 192.168.0.0/16
addresslist noautoreply_senders = DB_PREFIX/autoreply.noanswer.db
sender_unqualified_hosts = 127.0.0.1: 192.168.0.0/16
recipient_unqualified_hosts = 127.0.0.1: 192.168.0.0/16
local_interfaces = 0.0.0.0.25: 0.0.0.0.26: 0.0.0.0.465: 0.0.0.0.587: 127.0.0.1.10025
tls_on_connect_ports = 465
acl_smtp_connect = acl_check_connect
acl_smtp_helo = acl_check_helo
acl_smtp_mail = acl_check_mail
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data
acl_smtp_dkim = acl_check_dkim
accept_8bitmime
auth_advertise_hosts = !127.0.0.1 # Не предлагать SMTP AUTH локалхосту
bounce_message_file = CONFIG_PREFIX/bounce.msg # Указываем формат bounce сообщения, у меня так:
bounce_return_size_limit = 100K
delay_warning = 15m:1h:99d
deliver_queue_load_max = 40
disable_ipv6
exim_group = vmail # Желательно чтобы все почтовые сервисы (dovecot, spamassassin, clamav и тд) работали под одним gid
exim_user = vmail # Желательно чтобы все почтовые сервисы (dovecot, spamassassin, clamav и тд) работали под одним uid
headers_charset = UTF-8 # Желательно включить
ignore_bounce_errors_after = 0s
local_scan_timeout = 0s
message_size_limit = 50M
never_users = root
no_message_logs
no_smtp_enforce_sync
no_syslog_duplication
primary_hostname = mail.domain.com
qualify_domain = domain.com
queue_only_load = 12
queue_run_max = 5
recipients_max = 500
recipients_max_reject
remote_max_parallel = 2
return_size_limit = 10000
rfc1413_query_timeout = 0s
smtp_accept_max = 500
smtp_accept_max_per_host = 500
smtp_accept_queue = 500
smtp_accept_queue_per_connection = 1000
smtp_accept_reserve = 15
smtp_banner = $primary_hostname ESMTP ready $tod_full
smtp_connect_backlog = 40
smtp_load_reserve = 20
smtp_return_error_details
split_spool_directory
strip_excess_angle_brackets
strip_trailing_dot
syslog_facility = mail # Логи отсылаются syslog сервису
syslog_processname = exim
system_filter = DB_PREFIX/exim.filter # Глобальный exim фильтер, у меня в основном не используется
timeout_frozen_after = 7d
tls_advertise_hosts = !127.0.0.1 # Не предлагать TLS локалхосту
# Указываем пути к сертификатам
tls_certificate = /etc/exim/ssl/mail_crt_new.pem
tls_privatekey = /etc/exim/ssl/mail_key_new.pem
tls_verify_certificates = /etc/exim/ssl/ca.pem
# Определяем формат заголовка письма
received_header_text = «Received:
${if def:sender_rcvhost {from INTERFACEnt}
{${if def:sender_ident {from relay }}
${if def:sender_helo_name {(helo=${sender_helo_name})nt}}}}
by ${qualify_domain}
id ${message_id}
${if def:received_for {ntfor <$received_for>}}»
# Подключаем антивирус и антиспам напрямую, так как LDAP здесь не используется, то все стандартно, поэтому опускаем настройку.
# av_scanner = clamd:/tmp/clamd
# spamd_address = 127.0.0.1 783
begin acl
# Подключаем наш ACL конфиг (см ниже)
.include ACL_PREFIX/acl_smtp
# Создаем роутеры
begin routers
# Роутер для исходящей почты
dnslookup:
driver = dnslookup
domains = ! local_domains: ! virt_domains
transport = remote_smtp
ignore_target_hosts = 0.0.0.0: 127.0.0.0/8
no_more
# Роутеры для входящей почты
#Опицональный транспорт для amavis (сделаем одно исключение перлу 🙂 )
#amavis:
# driver = manualroute
# condition = ${if or {
# {eq{$interface_port}{10025}}
# {eq{$received_protocol}{spam-scanned}}
# {eq{$sender_address}{}}
# {eq{$sender_address_domain}{domain.com}}
# {eq{$sender_address_domain}{kaspersky.com}}
# {eq{${lc:$dkim_verify_status}}{pass}}
# {match{$sender_address_local_part}{-bounces}}
# }{0}{1}}
# domains = virt_domains
# senders =!: !postmaster@*: !mailer-daemon@*: !nagios@*: !monit@*
# no_verify
# no_expn
# transport = amavis
# route_list = “* localhost byname”
# self = send
autorespond:
driver = accept
domains = virt_domains
senders =!: ! noautoreply_senders # Не отвечать локалхосту и отправителям, указанным в autoreply.noanswer.db
condition = ${if and {
{!eq{CHECK_VACATION}{}} # Наш шаблон
{!match{$h_precedence:}{junk|bulk|list}} # Не отвечать рассылкам
{!def:header_Auto-Submitted:}
{!def:header_List-Id:}
}}
no_verify
no_expn
unseen
transport = auto_responder
# Приостановленные аккаунты, вся приходящая почта для suspended аккаунта отправляется в «черную дыру»
suspended:
driver = redirect
domains = virt_domains
condition = CHECK_3
forbid_file
forbid_pipe
forbid_filter_reply = true
data = :blackhole:
no_more
# Виртуальные альясы
aliases:
driver = redirect
domains = ! local_domains
condition = CHECK_1 # Тут происходит двойная проверка (первая в acl_smtp), если действующий аккаунт имеет еще и альяс, ничего лучше не придумал
forbid_file
forbid_pipe
forbid_filter_reply = true
data = CHECK_DATA # Кому пересылать письма
allow_fail
allow_defer
mailman_router:
driver = accept
domains = domain.com
require_files = MM_LISTCHK # Вместо проверки по файлу, можно сделать поверку по значению атрибута aliasType=DL, например
local_part_suffix_optional
local_part_suffix = -admin:
-bounces: -bounces *:
-confirm: -confirm *:
-join: -leave:
-owner: -request:
-subscribe: -unsubscribe
transport = mailman_transport
system_aliases:
driver = redirect
domains = local_domains
errors_to =
no_verify
data = ${lookup{$local_part}partial0-dbm{DB_PREFIX/aliases.db}{$value}fail}
file_transport = address_file
pipe_transport = address_pipe
allow_fail
allow_defer
localuser:
driver = accept
domains = local_domains: virt_domains
check_local_user
transport = dovecot_lda # Перекладываем доставку письма в почтовый ящик на плечи dovecot lda
cannot_route_message = Unknown account # Dovecot ответил нет, сдаемся
no_more
###############################################################
begin transports
###############################################################
remote_smtp:
driver = smtp
helo_data = mail.domain.com
max_rcpt = 500
#подключаем DKIM
dkim_domain = domain.com
dkim_selector = dkim
dkim_private_key = DB_PREFIX/dkim.private.key
dkim_canon = relaxed
auto_responder:
driver = autoreply
from = “${local_part}@${domain}”
to = “${reply_address}”
once = “/var/spool/exim/autoreply/${local_part}@${domain}”
once_repeat = 1d # Отвечать отправителю один раз в день, хотя можно логику перенести также в LDAP (см. phamm-vacation.schema)
headers = «Content-Type: text/plain; charset=utf-8nContent-Transfer-Encoding: 8bit»
subject = ${rfc2047:Auto-Reply: $h_subject:}
text = VACATION # Наш шаблон с текстом OoO сообщения
body_only
no_return_message
# Тот самый транспорт для dovecot
dovecot_lda:
driver = pipe
command = /usr/libexec/dovecot/dovecot-lda -f “$sender_address” -d “$local_part@$domain”
home_directory = /home/$local_part
delivery_date_add
envelope_to_add
return_path_add
log_output
log_defer_output
return_fail_output
freeze_exec_fail
temp_errors = 64: 69: 70: 71: 72: 73: 74: 75: 78
address_pipe:
driver = pipe
return_output
address_file:
driver = appendfile
current_directory = SPOOL
home_directory = SPOOL
create_directory
directory_mode = 0700
maildir_format
user = vmail
group = vmail
mode = 0600
no_check_owner
no_mode_fail_narrower
address_reply:
driver = autoreply
maillist_pipe:
driver = pipe
group = mail
return_fail_output
user = vmail
mailman_transport:
driver = pipe
command = MM_WRAP
‘${if def:local_part_suffix
{${sg{$local_part_suffix}{-(\w )(\ .*)?}{$1}}}
{post}}’
$local_part
current_directory = MM_HOME
home_directory = MM_HOME
user = MM_UID
group = MM_GID
#amavis:
# driver = smtp
# port = 10024
# allow_localhost
begin retry
* quota
* rcpt_4xx senders=: F,1h,10m
* * F,2h,10m; G,16h,1h,1.5; F,4d,6h
# Все системные сообщения рутов отправляем на один ящик
begin rewrite
root@* [email protected] Ttbcr
# Аутенфикаторы SMTP AUTH
begin authenticators
plain:
driver = plaintext
public_name = PLAIN
server_prompts =:
server_condition = “${lookup ldap{user=uid=${quote_ldap_dn:$auth2},ou=people,BASEDN pass=${quote:$auth3}
ldap:///ou=people,BASEDN?uid?sub?(&(uid=$auth2)(objectClass=VirtualMailAccount)(accountActive=TRUE))}{yes}fail}”
server_set_id = $auth2
login:
driver = plaintext
public_name = LOGIN
server_prompts = «Username::: Password::»
server_condition = “${lookup ldap{user=uid=${quote_ldap_dn:$auth1},ou=people,BASEDN pass=${quote:$auth2}
ldap:///ou=people,BASEDN?uid?sub?(&(uid=$auth1)(objectClass=VirtualMailAccount)(accountActive=TRUE))}{yes}fail}”
server_set_id = $auth1
Ldap backend
Dovecot can use LDAP as a password database for authentication as well as a user database for information like the maildir location, and the UID
and GID
of the user. An overview is given in the Dovecot wiki.
To activate LDAP as a password and user database, enable it in /etc/dovecot/conf.d/10-auth.conf
and disable auth-system.conf.ext
.
- 10-auth.conf
#!include auth-system.conf.ext !include auth-ldap.conf.ext
/etc/dovecot/conf.d/auth-ldap.conf.ext
should contain the declaration for passdb
and userdb
.
- auth-ldap.conf.ext
passdb { driver = ldap args = /etc/dovecot/dovecot-ldap.conf.ext } userdb { driver = ldap args = /etc/dovecot/dovecot-ldap.conf.ext }
The file /etc/dovecot/dovecot-ldap.conf.ext
is used by both, passdb
and userdb
to configure the connection parameters to the LDAP directory.
- dovecot-ldap.conf.ext
uris = ldap://ldap.example.com dn = cn=mailAccountReader,ou=Manager,dc=example,dc=com dnpass = <dn bind password> tls = yes tls_ca_cert_file = /etc/ldap/tls/CA.pem tls_require_cert = hard debug_level = 0 auth_bind = yes auth_bind_userdn = uid=%u,ou=Mail,dc=example,dc=com ldap_version = 3 base = ou=Mail,dc=example,dc=com scope = subtree user_attrs = homeDirectory=home,uidNumber=uid,gidNumber=gid user_filter = (&(objectClass=posixAccount)(uid=%u))
This configuration auth_bind = yes
tries to bind to OpenLDAP with the DN of the authenticating IMAP user instead of checking the password directly. The advantage of this configuration is that the password stored in the directory does not need to be readable by Dovecot. When the auth_bind_userdn
template is defined, pass_attr
can be omitted. user_filter
sets the filter to find the LDAP entry using the login username. user_attrs
maps the LDAP attributes to Dovecot’s internal attributes. When retrieving the user information, Dovecot connects to the directory with the credentials set with the dn
and dnpass
directives. The other parameters are used to connect to OpenLDAP with TLS and are the same as in the postfix configuration.