11 ноября 2011 г.

Почтовый сервер Exim4 + Dovecot + passwd

Недавно я помнится настраивал связку Exim4 + DBMail. Если честно, то DBMail мне не понравился, какой-то он получился долгий. В общем сегодня решил настроить другую связку — Exim4 + Dovecot.

Статей по настройке этой связки я прочитал не мало перед тем как начать. Сразу же бросилось в глаза разнообразие и гибкость Dovecot, а про Exim4 тут и говорить не стоит. Так как сервер заводится для конкретных целей и учетных записей пользователей там будет не так уж и много, то было принято решение хранить пользователей в passwd-файлах, да и авторизация так проходит быстрее (при не большом количестве пользователей). Но, независимо от количества пользователей сервер должен быть полноценным, т.е. на нем должны легко создаваться пользователи и он должен поддерживать столько доменов, сколько будет необходимо.
В общем, из исходных «материалов» как обычно имеем сервер с девственно чистым Debian Squeeze и немереное желание все это сделать побыстрей.
Для начала, нам нужно установить необходимы пакеты:

# apt-get install exim4 exim4-daemon-heavy dovecot-imapd dovecot-pop3d

После остановки оба сервиса (exim4 и dovecot) стартуют автоматом, останавливаем их:

# service exim4 stop
# service dovecot stop

Редактируем (или создаем) файл /etc/exim4/exim4.conf. Тут следует оговорится, я специально весь конфиг создаю в одном большом файле, как-то я уже использовал сплит на маленькие файлы, которые хранятся в каталоге /etc/exim4/conf.d/, но мне это показалось дико неудобным. Итак, пишем конфигурацию exim4.conf:

log_selector = \
       +all_parents \
 +lost_incoming_connection \
 +received_sender \
 +received_recipients \
 +tls_cipher +tls_peerdn \
 +smtp_confirmation \
 +smtp_syntax_error \
 +smtp_protocol_error
 
domainlist local_domains  = lsearch;/etc/exim4/domains
hostlist relay_from_hosts  = 127.0.0.1
 
local_interfaces   = 0.0.0.0
 
domainlist relay_to_domains  = lsearch;/etc/exim4/domains
exim_user    = Debian-exim
exim_group    = Debian-exim
trusted_users    = www-data
 
never_users    = root
host_lookup    = *
rfc1413_hosts    = *
rfc1413_query_timeout   = 0s
ignore_bounce_errors_after  = 1d
timeout_frozen_after   = 1d
smtp_accept_max   = 500
acl_smtp_rcpt   = acl_check_rcpt
acl_smtp_data   = acl_check_data
acl_smtp_mail   = acl_check_sender
 
begin acl
 acl_check_rcpt:
  accept hosts = :
 
  deny message  = Restricted characters in address
   domains  = +local_domains
   local_parts = ^[.]:^.*[@%!/|]
 
  deny message  = Restricted characters in address
   domains  = !+local_domains
   local_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
 
  accept local_parts = postmaster
   verify  = recipient
   domains  = +local_domains
  require verify  = sender
 
  accept  hosts  = +relay_from_hosts
   control  = submission
 
  accept authenticated = *
   condition = ${if eq{${extract{5}{:}{${lookup{$authenticated_id}lsearch{/etc/exim4/passwd}}}}}{no} {yes}{no}}
   condition = ${if eq{${extract{3}{:}{${lookup{${domain:$authenticated_id}}lsearch{/etc/exim4/domains}}}}}{no} {yes}{no}}
   control  = submission/domain=
 
  deny message  = Rejected because $sender_host_addres is in a black list at $dnslist_domain\n$dnslist_text
   dnslists = ${readfile {/etc/exim4/dnsblist}{:}}
 
  require message  = Relay not permited
   domains  = +local_domains : +relay_to_domains
 
  require verify  = recipient
 
  accept
 
 acl_check_data:
  accept
 
 acl_check_sender:
  accept
 
begin routers
 dnslookup:
  driver   = dnslookup
  #domains  = ! +local_domains
  transport   = remote_smtp
  ignore_target_hosts  = 0.0.0.0 : 127.0.0.0/8
  self    = pass
  no_more
 
 disabled_domains:
  driver   = redirect
  condition  = ${extract{3}{:}{${lookup{$domain}lsearch{/etc/exim4/domains}}}}
  allow_fail  = yes
  data   = :fail: Domain disabled
  no_more
 
 disabled_users:
  driver   = redirect
  condition  = ${extract{5}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/passwd}}}}
  allow_fail  = yes
  data   = :fail: User disabled
  no_more
 
 local_domains:
  driver   = redirect
  data   = ${quote_local_part:$local_part}@${extract{1}{:}{${lookup{$domain}lsearch{/etc/exim4/domains}}}}
  cannot_route_message = Unknown user
  no_more
 
 group_aliases:
  driver   = redirect
  data   = ${extract{1}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/aliases}}}}
  condition  = ${if and{\
      {exists{/etc/exim4/aliases}}\
      {eq {${extract{2}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/aliases}}}}} {group} }\
        } {yes} {no} }
  redirect_router  = a_dnslookup
 
 aliases:
  driver   = redirect
  data   = ${extract{1}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/aliases}}}}
  condition  = ${if exists{/etc/exim4/aliases} {yes} {no} }
 
 aliases_pipe:
  driver   = accept
  transport  = aliases_pipe
  condition  = ${lookup {$local_part@$domain} lsearch {/etc/exim4/pipe-aliases} {yes} {no} }
 
 local_users:
  driver   = redirect
  condition  = ${lookup {$local_part@$domain} lsearch {/etc/exim4/passwd} {yes} {no} }
  data   = $local_part@$domain
  redirect_router  = autoreplay
 
 catchall_for_domains:
  driver   = redirect
  headers_add  = X-redirected: yes
  data   = ${extract{2}{:}{${lookup{$domain}lsearch{/etc/exim4/domains}}}}
  file_transport  = local_delivery
 
 unknown_users:
  driver   = redirect
  allow_fail  = yes
  data   = :fail: Unknown user
  no_more
 
 autoreplay:
  driver   = accept
  condition  = ${if exists{${extract{4}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/passwd}}}}/message.txt} {yes} {no}}
  retry_use_local_part
  transport  = address_reply
  unseen
 
 localuser:
  driver   = accept
  #condition  = ${lookup {$local_part@$domain} lsearch {/etc/exim4/passwd} {yes} {no} }
  transport  = local_delivery
  #cannot_route_message = Unknown user
 
 
# Маршрутизаторы без autoreplay
 
 a_dnslookup:
  driver   = dnslookup
  transport  = remote_smtp
  ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
  self   = pass
  no_more
 
 a_disabled_domains:
  driver   = redirect
  condition  = ${extract{3}{:}{${lookup{$domain}lsearch{/etc/exim4/domains}}}}
  allow_fail  = yes
  data   = :fail: Domain disabled
  no_more
 
 a_local_domains:
  driver   = redirect
  data   = ${quote_local_part:$local_part}@${extract{1}{:}{${lookup{$domain}lsearch{/etc/exim4/domains}}}}
  cannot_route_message = Unknown user
  redirect_router  = a_dnslookup
  no_more
 
 a_aliases:
  driver   = redirect
  data   = ${extract{1}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/aliases}}}}
  condition  = ${if exists{/etc/exim4/aliases} {yes} {no} }
  redirect_router  = a_dnslookup
 
 a_aliases_pipe:
  driver   = accept
  transport  = aliases_pipe
  condition  = ${lookup {$local_part@$domain} lsearch {/etc/exim4/pipe-aliases} {yes} {no} }
 
 a_local_users:
  driver   = accept
  transport  = local_delivery
  condition  = ${lookup {$local_part@$domain} lsearch {/etc/exim4/passwd} {yes} {no} }
 
 a_catchall_for_domains:
  driver   = redirect
  headers_add  = X-redirected: yes
  data   = ${extract{2}{:}{${lookup{$domain}lsearch{/etc/exim4/domains}}}}
  file_transport  = local_delivery
  redirect_router  = a_dnslookup
 
begin transport
 remote_smtp:
  driver   = smtp
 
 local_delivery:
  driver   = appendfile
  file   = ${extract{4}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/passwd}}}}/mbox
  #maildir_format
  #maildir_use_size_file
  #create_directory = true
  delivery_date_add
  envelope_to_add
  return_path_add
  mode   = 0660
  quota   = ${extract{3}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/passwd}}}}M
  quota_warn_threshold = 75%
  use_lockfile  = no
  no_mode_fail_narrower
  user   = ${extract{1}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/passwd}}}}
  group   = ${extract{2}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/passwd}}}}
 
 address_pipe:
  driver    = pipe
  return_output
 
 aliases_pipe:
  driver   = pipe
  command   = ${extract{1}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/pipe-aliases}}}}
  use_shell
 
 address_reply:
  driver   = autoreply
  headers   = ${readfile{${extract{4}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/passwd}}}}/message.txt}}
  to   = $sender_address
 
begin retry
* * F,2h,15m; G,16h,1h,1.5; F,4d,6h
 
begin rewrite
 
begin authenticators
 
 dovecot_login:
  driver   = dovecot
  public_name  = LOGIN
  server_socket  = /var/run/dovecot/auth-client
  server_set_id  = $1
 
 dovecot_plain:
  driver   = dovecot
  public_name  = PLAIN
  server_socket  = /var/run/dovecot/auth-client
  server_set_id  = $auth1
 
 cram_md5:
  driver   = dovecot
  public_name  = CRAM-MD5
  server_socket  = /var/run/dovecot/auth-client
  server_set_id  = $1

Далее необходимо создать следующие файлы:
# touch /etc/exim4/blacklist
# touch /etc/exim4/dnsblists
# touch /etc/exim4/domains
# touch /etc/exim4/passwd
# touch /etc/exim4/aliases
# touch /etc/exim4/pipe-aliases

Далее переходим к настройке Dovecot. Переименовываем стандартный файл настройки:
# mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.default

И создаем свой файл настроек /etc/dovecot/dovecot.conf:
log_path   = /var/log/dovecot.log
login_greeting   = pop3/imap service.
protocol imap {
}
protocol pop3 {
}
pop3_uidl_format   = %08Xu%08Xv
protocol lda {
 postmaster_address  = postmaster@appsruel.com
 mail_plugin_dir  = /usr/lib/dovecot/lda
}
 
auth default {
 mechanisms  = plain login cram-md5 digest-md5
 passdb passwd-file {
   args  = /etc/dovecot/dovecot.passwd
 }
 userdb passwd-file {
   args = /etc/dovecot/dovecot.passwd
 }
 user   = root
 socket listen {
  client {
   path  = /var/run/dovecot/auth-client
   mode = 0660
   user = Debian-exim
   group = Debian-exim
  }
 }
}
dict {
}
plugin {
}
#protocols   = pop3 pop3s imap imaps
protocols   = pop3 imap
disable_plaintext_auth  = no
mail_privileged_group  = mail
first_valid_uid   = 93

Создаем файл с паролями пользователей:
# touch /etc/dovecot/dovecot.passwd

А теперь создаем скрипт для удобства создания учетных записей пользователей, положить этот скрипт можно куда угодно, у меня лично он находится в /root/addmail.sh:
#!/bin/sh                                                  
if [ "$(whoami)" != 'root' ]; then          
    echo ""         
    echo "You have no permission to run `basename $0` as non-root user."
    echo ""                                 
    exit 1;                                 
fi
if [ $# -lt 2 ]; then
    echo ""
    echo "Usage: `basename $0` 
 mailbox@example.com password"
    echo ""
    exit 0
fi
mailuser=$1
pass=$2
hash=`dovecotpw -s MD5 -p $pass`
user=`echo $mailuser |cut -d'@' -f1`
domain=`echo $mailuser |cut -d'@' -f2`
mkdir -p /var/mail/$domain/$user
touch /var/mail/$domain/$user/mbox
chown -R Debian-exim:Debian-exim /var/mail/$domain
if ! grep $domain /etc/exim4/domains >/dev/null
then
echo "$domain:$domain::no" >>/etc/exim4/domains
fi
uid=`cat /etc/passwd |grep "Debian-exim"|awk -F : '{ print $3 }'`
echo "$mailuser:$uid:$uid:0:/var/mail/$domain/$user:no:" >>/etc/exim4/passwd
echo "$mailuser:$hash:$uid:$uid::/var/mail/$domain/$user:::/var/mail/$domain/$user/mbox" >>/etc/dovecot/dovecot.passwd

Делаем его исполняемым:
# chmod +x /root/addmail.sh

Запускаем наши сервера:
# service exim4 start
# service dovecot start

И создаем пользователя:
# sh /root/addmail.sh postmaster@domain.com PaSSwoRD

PaSSwoRD — это пароль учетной записи postmaster@domain.com. При настройке почтовых клиентов имя пользователя нужно указывать полностью, вместе с именем домена. Exim4 складывает почту в /var/mail/$domain/$user, т.е. для нашего пользователя вся почта будет хранится в /var/mail/domain.com/postmaster.
Удалять пользователей придется в ручную путем правки файлов /etc/exim4/passwd и /etc/dovecot/dovecot.passwd и естественно удаляя каталог, хотя можно написать и отдельный скрипт для этого — мне лень этим заниматься :)
Ну вот и все. Осталось добавить по вкусу SpamAssassin и приправит все это ClamAV'ом, но это уже совсем другая история :)
Удачи!

1 комментарий:

  1. 4 часа пытался читать официальную документацию, но в итоге нашел эту страницу и сделал все за 20 минут. Большое спасибо!

    + Нынче используется:
    hash=`doveadm pw -s MD5 -p $pass`

    + dovecot 2 при авторизации отказывал с сообщением:
    -ERR [IN-USE] Internal error occurred. Refer to server log for more information.

    В логах при этом:
    pop3(mail@example.ru): Error: user mail@example.ru: Initialization failed: Initializing mail storage from mail_location setting failed: Ambiguous mail location setting, don't know what to do with it: /var/mail/example.ru/mail/mbox (try prefixing it with mbox: or maildir:)

    Соответственно, как в сообщение и сказано, в dovecot.passwd нужно было использовать вместо этого:
    echo "$mailuser:$hash:$uid:$uid::/var/mail/$domain/$user:::/var/mail/$domain/$user/mbox" >>/etc/dovecot/dovecot.passwd

    это:
    echo "$mailuser:$hash:$uid:$uid::/var/mail/$domain/$user:::mbox:/var/mail/$domain/$user" >>/etc/dovecot/dovecot.passwd

    ОтветитьУдалить