воскресенье, 21 ноября 2010 г.

Настраиваем IMAP-сервер Dovecot и fetchmail на сбор почты и доставку через deliver (без полноценного MDA)

Задача: установить на машине в локальной сети IMAP-сервер, который будет забирать почту с внешнего IMAP-сервера, удаляя письма оттуда. Никакие антиспам-фильтры или антивирусы нам не нужны, за нас это сделает провайдер почтового сервиса. В качестве пользователей должен использоваться отдельный список, пользователи системы нам не подходят. Желательно всё это с минимальными телодвижениями и с минимальным количеством задействованного софта, т.к. по-моему чем больше в системе компонентов, тем больше у нее шансов сломаться.

Выбранный софт:
  • Dovecot - простой в настройке, быстрый IMAP-сервер (есть вариант и POP-сервера)
  • Fetchmail - программа для сбора почты и пересылки ее локальному агенту доставки сообщений
  • Imapsync - программа для синхронизации и переноса IMAP-ящиков с одного сервера на другой, нужна один раз. Авторы теперь хотят за нее денег, но она есть в любом нормальном Linux-дистрибутиве, так что покупать ее не придется
Обычно в статьях к этому списку добавляют MDA, который и будет доставлять почту локальным пользователям, но мы воспользуемся программой deliver, идущей в комплекте с Dovecot, тем самым исключив дополнительный компонент.

Для примеров будем использовать следующие параметры:
  • imap.external.com - внешний сервер, с которого нужно забирать почту
  • imap.localserv.net - сервер в локальной сети, на котором будут работать Dovecot и fetchmail
  • joe - имя пользователя, для которого мы будем настраивать ящик

1. Настраиваем Dovecot.
Для начала создадим нового пользователя от имени которого будут работать сессии пользователей при обращении к ящикам.
# adduser --system --group vmail
Утилита любезно создаст нам домашнюю папку, в которой мы и будем хранить почту всех пользователей (/home/vmail)

Далее создаем нашу базу пользователей в файле /etc/dovecot/passwd Файл имеет формат
username[@localserv.net]:{SCHEMA}password
Домен указывать не обязательно. Схемы аутентификации - это формат хранения пароля. Для тестов можно использовать PLAIN - пароль нужно вписывать открытым текстом. Для полноценного использования подойдет схема SSHA. Для получения хэша пароля в этом формате есть утилита dovecotpw:
# dovecotpw -s ssha
Она попросит 2 раза ввести пароль, а в ответ выдаст хэш вместе со схемой, это и нужно вставить в файл. Приведу простой пример файла:
test:{PLAIN}pass
joe:{SSHA}DNODS3ZrOq1bu2MasNk79LxHhlU9iI03
Далее нужно сделать этот файл доступным на чтение только пользователю dovecot, от имени которого запускается демон:
# chown dovecot:dovecot /etc/dovecot/passwd
# chmod go-rwx /etc/dovecot/passwd
Теперь пишем основной конфиг /etc/dovecot/dovecot.conf

Буду приводить только изменения относительно конфига по-умолчанию в Debian.

Включаем поддержку IMAP с шифрованием. Если нужно без шифрования, то используем imap. Можно указать оба способа через пробел.
protocols = imaps
Пишем журнал в отдельные файлы. Если нужно использовать syslog, необходимо убрать пути к файлам (задать пустые параметры).
log_path = /var/log/dovecot.log
info_log_path = /var/log/dovecot-info.log
Задаем формат хранения почты maildir:
mail_location = maildir:~/Maildir
Далее нам нужно узнать uid нашего пользователя vmail. Для этого запускаем команду:
# id -u vmail
Она и покажет uid указанного пользователя, в моем случае он равен 113. Теперь в конфиге задаем минимальный и максимальный uid, под которыми могут работать пользовательские сессии:
first_valid_uid = 113
last_valid_uid = 113
Далее нужно добавить секцию с настройками протокола LDA (Local Delivery Agent), т.е. это настройки программы deliver из состава Dovecot. Что указывать в качестве параметра postmaster - понятия не имею, указал первого попавшегося локального пользователя. Думаю, этот ящик в нашей конфигурации использоваться не будет, т.к. на него должны отправляться "отвергнутые" письма, которых у нас не будет за неимением анти-спам и анти-вирусных фильтров. В качестве hostname нужно указать доменное имя вашего сервера. auth_socket_path - путь к сокету аутентификации, через него deliver будет подключаться к основному процессу Dovecot для получения привилегий. Здесь же указываем отдельные файлы для журналов deliver. По аналогии с основными журналами, можно воспользоваться syslog, задав параметры пустыми значениями. Вот как будет выглядеть вся секция:
protocol lda {
  postmaster_address = user1@example.com
  hostname = imap.localserv.net
  auth_socket_path = /var/run/dovecot/auth-master
  log_path = /var/log/fetchmail/dovecot-deliver.log
  info_log_path = /var/log/fetchmail/dovecot-deliver-info.log
}
Для более детального журналирования процесса аутентификации можно на этапе отладки включить следующую опцию (после тестирования ее желательно убрать):
auth_verbose = yes
Все дальнейшие изменения будут производиться в секции auth default {...}.

Первым делом выключаем аутентификацию через PAM и базу пользователей по-умолчанию, закомментировав всё в подсекциях passdb pam {...} и userdb passwd {...}.

Далее подключаем базу паролей из нашего файла:
passdb passwd-file {
  args = /etc/dovecot/passwd
}
Для сессий работы с почтой указываем системного пользователя и папку под почту:
userdb static {
  args = uid=vmail gid=vmail home=/home/vmail/%u
}
Комментируем строчку, которая запускает один из процессов от root'а. Судя по описанию, нам это не нужно.
#user = root
И наконец, создаем сокет, чтобы deliver смог подключиться к основному процессу для получения привилегий:
socket listen {
  master {
    path = /var/run/dovecot/auth-master
    mode = 0600
    user = vmail
    group = vmail
  }
}
Сохраняем конфиг. Перезагружаем Dovecot:
# /etc/init.d/dovecot restart
2. Настраиваем Fetchmail
Нормальную документацию по написанию конфигов для этой программы я так и не нашел, всё взято из примеров на форумах, в блогах и списках рассылки. Ее можно запускать как общесистемного демона или в сессии пользователя, нас конечно же интересует первый вариант.

Конфиг лежит в файле /etc/fetchmailrc Здесь я сразу приведу пример всего конфига. Настроен демон будет на получение новых писем каждые 2 минуты (на самом деле, это очень часто, лучше поставить 5-10 минут). Журнал будет записываться в отдельный файл (хотя, опять же, можно использовать syslog). C postmaster та же история, что и для deliver, - в случае проблем с доставкой письмо просто не удаляется с внешнего сервера и, по видимому, в ящике postmaster нет необходиимости, но всё же укажем нашего системного пользователя.

Настройки аккаунтов представляют собой этакие предложения, для удобства записал их в несколько строчек. Разберем на примере:
  • poll imap.external.com protocol imap
    здесь указываем адрес внешнего сервера и протокол по которому нужно проверять новые письма

  • user "joe" there with password "joe-password"
    указываем пользователя на внешнем сервере и его пароль там

  • options ssl
    указываем опции через пробел, ssl говорит о том, что нужно использовать шифрованный канал (в соответствии с этой опцией и указанным протоколом, fetchmail автоматически выбирает порт для соединения); для тестирования будет полезна опция keep, позволяющая оставлять письма на сервере
     
  • sslcertpath /home/vmail/.certs
    отдельная история, опишу ее после конфига

  • mda "/usr/lib/dovecot/deliver -d joe";
    здесь мы указываем программу доставки сообщений, причем для deliver нужно указать через параметр -d имя пользователя, в ящик которого придут письма с этого внешнего аккаунта
А теперь полностью пример конфига для двух пользователей:
set daemon 120       # Poll every 2 minutes
set no syslog        # Alternate log
set logfile /var/log/fetchmail/fetchmail.log
set postmaster user1   # In case of errors mails are delivered here

set no bouncemail    # avoid loss on 4xx errors
                     # on the other hand, 5xx errors get more dangerous

# Defaults
defaults:
timeout 60
batchlimit 100

# Accounts to poll
## test@external.com ##
poll imap.external.com protocol imap
user "test" there with password "secret-external-server-password"
options ssl
sslcertpath /home/vmail/.certs
mda "/usr/lib/dovecot/deliver -d test";

## joe@external.com ##
poll imap.external.com protocol imap
user "joe" there with password "joe-password"
options ssl
sslcertpath /home/vmail/.certs
mda "/usr/lib/dovecot/deliver -d joe";
А теперь одна особенность внешнего сервера, с которым мне пришлось работать. Они используют сертификаты, подписанные своим центром сертификации, поэтому пришлось скачать их корневой сертификат, положить его в папку /home/vmail/.certs и сменить ему расширение на ".pem". После этого нужно обновить индексы в папке с сертификатами, для этого запускаем:
# c_rehash /home/vmail/.certs
Сертификаты готовы к использованию.

Если мы попробуем запустить демона fetchmail от одноименного пользователя (как настроено по-умолчанию в Debian), у нас ничего не выйдет - deliver будет ругаться на отсутствие прав и невозможность сохранить письмо.

Скорее всего, в ближайшем будущем найду решение без этого шага, но пока работает только так. Нужно сменить пользователя от имени которого запускается fetchmail. Мы будем запускать ее от имени vmail, чтобы порожденный ею процесс deliver смог сохранить письма в папки виртуальных пользователей. Для этого в файле /etc/default/fetchmail вносим следующие изменения (заодно включим запуск fetchmail в качестве демона при старте системы):
START_DAEMON=yes
USER=vmail
Сохраняем файл. И пока не запускаем fetchmail, т.к. есть еще один шаг, если вы настраиваете систему для не новых ящиков и в папках на внешнем сервере уже лежат письма.

3. Миграция IMAP-ящиков с помощью imapsync
Ваши пользователи наверняка захотят, чтобы все их пометки, папки и другие данные с IMAP-ящиков внешнего сервера полностью перенеслись на локальный сервер.

Чтобы не светить пароли в списке процессов, создаем для каждого пользователя по 2 файла, содержащие пароли от внешнего и локального ящиков. Сначала подготовим папку для них:
# mkdir /home/vmail/.pass
# cd /home/vmail/.pass
Эти процедуры нужно повторить для каждого перемещаемого пользователя:
# touch joe.remote joe.local
# chown root joe.remote joe.local
# chmod 0600 joe.remote joe.local
И затем вписать в созданные файлы соответствующие пароли с помощью вашего любимого текстового редактора.

Далее начинается самое веселье. Нужно методом поиска в интернете, чтения невнятного мануала к imapsync и других магических манипуляций подобрать опции для каждого из IMAP-серверов.  Опишу опции, которые пришлось использовать мне. Большинство опций имеют на конце цифру 1 - сервер, с которого будут переноситься письма, или 2 - сервер, на который они будут переноситься. Итак, опции (те, что имеют вариант для каждого из серверов приведены с 1 на конце):
  • --host1 imap.external.com
    имя сервера

  • --port1 993
    порт для подключения

  • --user1 "joe"
    имя пользователя для аутентификации

  • --passfile1 /home/vmail/.pass/joe.remote
    путь к файлу с паролем

  • --ssl1
    использовать ли шифроввание при подключении к серверу

  • --noauthmd5
    общая опция (одна и работает сразу для обоих серверов), отключает использование аутентификации по MD5; нужна, если программа при запуске выдаст ошибку о невозможности использования такого метода аутентификации

  • --sep1 "."
    --prefix1 ""
    префикс и разделитель в именах папок, они нужны если imapsync не может определить их автоматически и явно просит указать одну из них, или возникают проблемы с недопустимыми именами при создании папок в процессе синхронизации; как их определять - расскажу ниже

  • --delete
    --expunge1
    после первой удачной синхронизации нужно добавить эти опции и запустить imapsync еще раз для удаления писем с внешнего сервера; имейте ввиду, что --expunge2 указывать не нужно
Итак, в самом простом случае для каждого аккаунта нужно запустить imapsync 2 раза. Второй раз - только убедившись, что всё перенеслось как следует, для очистки ящика на внешнем сервере. Переносим почту:
# imapsync --ssl1 --ssl2 --noauthmd5 --host1 imap.external.com --port1 993 --host2 imap.localserv.net --port2 993 --user1 "joe" --passfile1 /home/vmail/.pass/joe.remote --user2 joe --passfile2 /home/vmail/.pass/joe.local
Второй раз запускаем уже с опциями удаления:
# imapsync --ssl1 --ssl2 --noauthmd5 --host1 imap.external.com --port1 993 --host2 imap.localserv.net --port2 993 --user1 "joe" --passfile1 /home/vmail/.pass/joe.remote --user2 joe --passfile2 /home/vmail/.pass/joe.local --delete --expunge1
Теперь самое веселое, если imapsync не может определить префиксы и разделители пути на серверах, нужно соединиться с сервером (мы будем использоовать защищенное соединение), вручную залогиниться и запросить перечисление папок. Тогда мы увидим как он представляет папки и сможем это объяснить imapsync.

Соединяемся с сервером:
$ openssl s_client -connect imap.external.com:993
если видим в конце ответа
* OK IMAP4 ready
значит всё в порядке, можно разговаривать с сервером. Проходим аутентификацию:
1 login joe joe-password
видим
1 OK LOGIN Ok.
далее набираем по очереди 2 команды и анализируем их результат:
2 list "*" ""
3 list "" "*"
результат будет иметь вид, похожий на следующее:
* LIST (\HasNoChildren) "." "INBOX.Archive"
* LIST (\HasNoChildren) "." "INBOX.Sent"
* LIST (\HasNoChildren) "." "INBOX.Draft"
Это означает, что префикса у пути нет, а разделитель папок - точка. В результате параметры будут
--prefix1 "" --sep1 "."
То же самое нужно повторить и для локального сервера.

4. Контрольный запуск и исправление ошибок.
После того, как все письма перенесены на локальный сервер, можно запускать демона fetchmail и тестировать его работу:
# /etc/init.d/fetchmail start
Т.к. эта статья пишется "по горячим следам" после настройки сервера и переноса ящиков, скорее всего я забыл про какие-нибудь права на папки и файлы (например, файлы журнала). Внимательно читаем сообщения об ошибках при старте демонов или в логах, думаем головой, исправляем их и не забываем упомянуть об этом в комментариях к статье.

5 комментариев:

Анонимный комментирует...

имхо немного некорректное название поста, без mda пользователи не получили бы почты.. в данном случае используется родной dovecot-овский...(пруф -> http://wiki.dovecot.org/MDA )

Dmitriy.Trt комментирует...

@Анонимный: согласен, deliver - это всё же почти MDA (в Wiki Dovecot они его называют Local Delivery Agent, LDA). Поправил название поста.

Анонимный комментирует...

Гораздо удобнее находить id любого пользователя системы одноименной командой id, которая есть в любом дистрибутиве unix-like системы.
[13:24]%> id operator
uid=2(operator) gid=5(operator) groups=5(operator)

Dmitriy.Trt комментирует...

@Анонимный: спасибо, поправил пост.

Maxim Smirnov комментирует...

Скорее всего, в ближайшем будущем найду решение без этого шага, но пока работает только так. Нужно сменить пользователя от имени которого запускается fetchmail.

Для решения этой проблему нужно следующее. В конфиге dovecot 10-master.conf в блоке service auth прописать:
unix_listner auth-userdb {
mode = 0600
user = test
group test
}

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