Установка и настройка почтовой системы на базе Posfix


Posfix + PostgreSQL + Courier-Authlib + Courier-Imap + SqWebMail +
Maildrop + ClamAV + SpamAssassin + AWStats.

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

- Postfix (http://postfix.org) - MTA
- PostgreSQL (http://postgresql.org) - БД
- Courier-Authlib (http://www.courier-mta.org) - Демон и библиотека аутентификации
- Courier-Imap (тамже) - IMAP и POP демон
- Maildrop (тамже) - MDA
- SqWebMail (тамже) - Веб-интерфейс для работы с почтовыми ящиками
- ClamAV (http://www.clamav.net/) - Фриварный антивирус
- SpamAssassin (http://spamassassin.apache.org/) - Убийца и маркировщик спама
- AWStats (http://awstats.sourceforge.net/) - Генератор статистики.



Преамбула

После двух недель блуждания по далёким серверам и надоедания гуглу
вопросом как связать постгрю с сендмейлом без перестройки формата базы я
нашел патчик для связки с базой. http://blue-labs.org/software/sm-pgsql/
Принцип работы не понравился.

Это было тогда, а сейчас есть сервер на базе postfix'a с довольно таки
разросшейся базой пользователей, соответственно и возросшимся потоком
спама. Я уже было начал материться благим матом, но потом вспомнил про
такой замечательный сайт www.faqs.org который ни раз меня выручал ибо
там можно покурить замечательные маны, которые из-за содержания
тетраэрфэцэола называют RFC.

Помимо RFC 822, который многние горе-админы забывают читать, там есть
RFC 1123 (очень полезный документ) и 2505. Последний должен быть более
интересен администраторам небольших компаний т.к. на крупных серверах
идёт большой поток деловой корреспонденции с криво настроенных серверов.
Я долго матерился, когда посмотрел что у меня помимо спама начало
зарезаться на сервере.

Например, сервер одной туристической фирмы (не будем называть его имени)
в хело мне выдал domain.tld, после чего был успешно послан по старой
дороге.

В прошлой статье я специально не привязывал процесс установки ПО к
платформам, ссылаясь на документацию.

Объясняю почему так. Мне неприятно читать статьи по типу "Ставим ЭТО на
ЭТО (версия прилагается)".

Особенно когда ещё приводятся скрипты под эту платформу. Бросаешь это
чтиво и начинаешь изучать INSTALL и README,который есть в любой софтине.
Администратор всёравно знает как ставить софт на администрируемую им
платформу, поэтому чтоб не толочь воду в ступе лучше описать подводные
камни, которые обязательно встретятся. Это моё мнение, я не хочу
огорчить, расстроить или оскорбить авторов таких статей.

И всё же. Весь перечисленный софт есть в rpm, портежах Генты и портах
FreeBSD за исключением AWStats. Я бы был признателен администраторам,
которые приведут startup скрипты и замечания по установке для платформ
на которые нет собранных пакетов вышеперечисленного ПО.

Итак, постараемся исправить сложившуюся ситуацию и описать процесс
установки с нуля.


Что нам нужно.

Для начала надо завести на ДНСе запись типа A с именем нашего будущего
сервера и указываем в нашем домене MX на наш будущий почтовый сервер.
Потом добавляем в обратную зону PTR на наше имя. Обязательно к
исполнению и обжалованию не подлежит, если не хотим проблем с отправкой
почты на другие сервера.

Устанавливаем PostgreSQL, заводим пользователя, разрешаем ему стучаться
в базу. Если сложно читать документацию, постовляемую с посгрей -
воспользуйтесь поиском.

Кратко от FDS:


# su postgres
bash-3.00$ createuser test
Разрешить новому пользователю создавать базы? (y/n) n
Разрешить новому пользователю создавать пользователей? (y/n) n
CREATE USER
bash-3.00$ createdb postfix
CREATE DATABASE
bash-3.00$
bash-3.00$ psql postfix
Добро пожаловать в psql 7.4.8 - Интерактивный Терминал PostgreSQL.
Наберите: copyright для условий распространения
h для подсказки по SQL командам
? для подсказки по внутренним slash-командам (команда)
g или ";" для завершения и выполнения запроса
q для выхода
postfix=#grant all on database postfix to test;
GRANT
postfix=#q
летим в каталог /var/lib/pgsql/data/pg_hda.conf
пишем
host postfix test 10.0.0.1/32 trust
где 10.0.0.1 это ip mail server-а




Собственно о формате БД. Для virtual_mailbox_maps нужно два поля: имени
пользователя с доменом и пути до ящика. При использовании maildrop,
который использует courier-authlib для получения пути до ящика, второе
поле необязательно. Для courier-authlib нужно имя пользователя, пароль
(открытый или хэшированный в MD5), путь до ящика, владельца и группу
владельца ящика, квоту, полное имя пользователя, дополнительные
параметры, которые указываются через запятую в одном поле.

По поводу квоты. Это очень призрачный параметр у курьера. Смысла его
использования я до сих пор не понял т.к. почта всё равно принимается
MTA.

Параметрам main.cf postfix'a virtual_uid_maps и virtual_gid_maps,
которые отвечают за владельца и группу почтовых ящиков, мы установим
статическое значение - uid и gid пользователя vmail, которого надо
завести на системе. Соответственно теже значения должны отдаваться
courir-authlib'у.

Для примера возмём таблицу mailusers на БД mail:

login varchar(50) unique, pass varchar(50), path varchar(100), fullname varchar(50)
login - имя пользователя с доменом, pass - некриптованый пароль, path - путь до ящика,
fullname - полное имя пользователя.

Этого хватит. Остальное мы зададим в запросе.

Устанавливаем Courier-Authlib и модуль для работы с постгресом. Для
rpm-based - courier-authlib и courier-authlib-pgsql.

В /etc/authlib/authdaemonrc пишем:

authmodulelist="authpgsql"
daemons=5
DEBUG_LOGIN=0
DEFAULTOPTIONS=""


В /etc/authlib/authpgsqlrc пишем:

PGSQL_HOST хост.где.находится.база
PGSQL_PORT 5432
PGSQL_USERNAME имя
PGSQL_PASSWORD пароль
PGSQL_DATABASE база данных с пользователями и их паролями

PGSQL_SELECT_CLAUSE SELECT login as username,'' as cryptpw,
pass as clearpw,506 as uid,
506 as gid,'/mailboxes/'||substring(c.login from 1 for 1)||'/'||c.login as home,
'' as maildir,
30 as quota,fullname,
'disableimap' as options
where login = '$(local_part)'||'@'||'$(domain)';
#'/mailboxes/'||substring(c.login from 1 for 1)||'/'||c.login as home -- пользовательские ящики с путями /mailboxes/первая_буква_логина/логин
# просто мне так больше нравится.
#gid 506 и uid 506 - пользователь vmail, которому будет принадлежать вся почта


Читаем документацию. Запускаем.


Затем устанавливаем Courier-Imap и Maildrop.

в /etc/maildroprc пишем:

`test -f $HOME/.mailfilter`
if ( $RETURNCODE == 0 )
{
include '.mailfilter'
if ( $QUIT )
REASON="users's filter"
}

to 'Maildir/.'


Это нужно для того, чтобы в директории ящика пользователя при
необходимости можно было создать индивидуальные правила в файлике
.mailfilter

Устанавливаем SpamAssassin 3.1.0

Читаем документацию, устанавливаем все необходимые перловые модули и DCC.
Razor2 не является открытым - не используем.
Если нет startup скрипта, можете воспользоваться нижеприведённым
spamd.rc

#!/bin/sh
case "$1" in

start)
spamd -d -u clamav -m 7 -x '--virtual-config-dir=/mailboxes_conf/%u' --max-conn-per-child=5 -r /home/clamav/spamd.pid
;;
stop)
kill `cat /home/clamav/spamd.pid`
;;
restart)
$0 stop
$0 start
;;
esac


--virtual-config-dir=/mailboxes_conf/%u используется для создания
индивидуальных настроек. spamd будет работать от пользователя clamav.
Подробности в документации.

Правим файлы /etc/mail/spamassassin/v310.pre и init.pre на свой вкус и
цвет. Ниже приведу свои настройки.

init.pre

loadplugin Mail::SpamAssassin::Plugin::RelayCountry
loadplugin Mail::SpamAssassin::Plugin::URIDNSBL
loadplugin Mail::SpamAssassin::Plugin::Hashcash


v310.pre

loadplugin Mail::SpamAssassin::Plugin::DCC
loadplugin Mail::SpamAssassin::Plugin::AutoLearnThreshold
loadplugin Mail::SpamAssassin::Plugin::WhiteListSubject
loadplugin Mail::SpamAssassin::Plugin::DomainKeys
loadplugin Mail::SpamAssassin::Plugin::MIMEHeader
loadplugin Mail::SpamAssassin::Plugin::ReplaceTags


В local.cf находятся настройки по выставлению баллов, "белые" листы и
всё остальное, что влияет на определение спама.

Приведу свои настройки.

report_contact me@mydomain.ru
rewrite_subject 1
report_safe 0
whitelist_from *@otherdomain.ru ............
trusted_networks xxx.xxx.xxx
lang ru
ok_languages ru en
ok_locales ru en
rewrite_header Subject SPAM(_SCORE_)
bayes_path /etc/mail/spamassassin/bayes
bayes_auto_learn 0
bayes_min_ham_num 10
bayes_min_spam_num 10
auto_learn 0
use_auto_whitelist 0
use_razor2 1
use_dcc 1
skip_rbl_checks 1
score FROM_ILLEGAL_CHARS 0.5
score HEAD_ILLEGAL_CHARS 0.5
score SUBJ_ILLEGAL_CHARS 1.0
score HTML_FONTCOLOR_RED 3.0
score MIME_HTML_ONLY 2.0
score HTML_FONT_BIG 1.5
score BAYES_99 3
score RCVD_IN_NJABL_DUL 5.5
score URIBL_SBL 3
score RCVD_IN_SORBS_DUL 6.2
score RCVD_IN_XBL 8.1
score DNS_FROM_AHBL_RHSBL 8.1
score RAZOR2_CHECK 8.7
score DNS_FROM_RFC_ABUSE 6.5
required_hits 7


Потом подсовываем sa-learn писем 300-400 spam'a и 300-400 ham'a.
Подробности по [[code]]sa-learn --help[[/code]] Если попалась
корреспонденция в idx (формат аутлука), то в mailbox можно перегнать
перловым скриптом mbx2mbox (ищем в гугле).

В данной конфигурации проскакивает 3% спама на мой ящик, жалоб от
пользователей не было.


ClamAV

Заводим пользователя clamav, создаём директорию /var/clamav/{log,tmp} и
назначаем владельцем clamav Читаем документацию. Думаем. Устанавливаем.

Правим /usr/local/etc/clamd.conf:

LogFile /var/clamav/clamav.log
LogFileMaxSize 2M
LogTime
LogClean
LogSyslog
LogFacility LOG_MAIL
LogVerbose
PidFile /var/clamav/clamd.pid
TemporaryDirectory /var/clamav/tmp
DatabaseDirectory /var/clamav
LocalSocket /var/clamav/clamd.sock
FixStaleSocket
MaxConnectionQueueLength 30
StreamMaxLength 400k
MaxThreads 100
IdleTimeout 5
SelfCheck 100
User clamav
ScanHTML
ScanArchive
ScanRAR
ArchiveMaxFileSize 400k


startup скрипт clamd

#!/bin/sh
case "$1" in

start)
/usr/local/sbin/clamd
;;
stop)
# kill `cat /var/clamav/clmilter.pid`
;;
restart)
$0 stop
sleep 2
$0 start
;;
esac


Правим /usr/local/etc/freshclam.conf:

DatabaseDirectory /var/clamav
UpdateLogFile /var/clamav/freshclam.log
PidFile /var/clamav/freshclam.pid
DatabaseOwner clamav
DatabaseMirror database.clamav.net
Checks 24


startup скрипт freshclamd

#!/bin/sh
case "$1" in

start)
/usr/local/bin/freshclam -d
;;
stop)
kill `cat /var/clamav/freshclam.pid`
;;
restart)
$0 stop
$0 start
;;
esac


Переходим к самому интересному.


Postfix

Читаем документацию, из неё видим:
For example:

% make tidy
% make -f Makefile.init makefiles
'CCARGS=-DHAS_PGSQL -I/usr/local/include/pgsql'
'AUXLIBS=-L/usr/local/lib -lpq'

Then just run 'make'.


собираем, устанавливаем. Заводим пользователя vmail. О том как связать
postfix и clamav через clamsmtpd читаем
http://www.nixp.ru/cgi-bin/go.pl?q=articles;a=clamav_postfix

конфигурация clamsmtpd.conf

OutAddress: 10026
Listen: 127.0.0.1:10025
ClamAddress: /var/clamav/clamd.sock
TempDirectory: /tmp
User: clamav


В /etc/postfix/access разрешаем хостам отправлять почту через нас

Перенаправляем всю почту на наш хост в виртуал, правим /etc/postfix/transport:

то.что.указано.в.myhostname virtual:

Опять же мне так больше нравится. Теперь нет локальных пользователей.
Не забудем поправить myorigin на наш домен.

В /etc/postfix/virtual у нас теперь алиасы виртуальных пользователей,
alias_maps и alias_database не возымеют над виртуальными пользователями
никакой власти, а локальных у нас теперь нет.

/etc/postfix/main.cf:

soft_bounce=no
command_directory = /usr/sbin
daemon_directory = /usr/libexec/postfix
mail_owner = postfix
myhostname = сервер.домен.ru
inet_interfaces = all
myorigin = домен.ru
mydestination = $myhostname

mynetworks = hash:/etc/postfix/access, cidr:/etc/postfix/access.cidr
#cidr нужен чтоб разрешать сети по маскам так как в хеше это невозможно
mynetworks_style = subnet
in_flow_delay = 1s

content_filter = scan:127.0.0.1:10025
receive_override_options = no_address_mappings
#Про это мы уже где-то читали...

smtpd_client_restrictions =
check_client_access hash:/etc/postfix/access,
permit_mynetworks,
# reject_unknown_client, я уже писал выше про кривую настройку некоторых серверов, поэтому не используем
reject_rhsbl_client sbl-xbl.spamhaus.org,
reject_rhsbl_client bl.spamcop.net,
reject_rhsbl_client combined.njabl.org,
reject_rbl_client sbl-xbl.spamhaus.org,
reject_rbl_client bl.spamcop.net,
reject_rbl_client combined.njabl.org,
check_client_access regexp:/etc/postfix/client_check.pcre

smtpd_helo_restrictions =
permit_mynetworks,
reject_non_fqdn_hostname,
reject_invalid_hostname

smtpd_sender_restrictions =
permit_mynetworks,
reject_non_fqdn_sender,
reject_unknown_sender_domain,
reject_rhsbl_sender bl.spamcop.net,
reject_rhsbl_sender combined.njabl.org,
reject_rhsbl_sender sbl-xbl.spamhaus.org

smtpd_recipient_restrictions =
check_recipient_access hash:/etc/postfix/disabled_users,
check_recipient_access hash:/etc/postfix/access,
reject_non_fqdn_recipient,
reject_unknown_recipient_domain,
permit_mynetworks,
reject_unlisted_recipient,
reject_unauth_destination

smtpd_etrn_restrictions =
check_etrn_access hash:/etc/postfix/access,
reject

smtpd_delay_reject = yes
bounce_size_limit = 10000
max_use = 10
smtpd_helo_required = yes
maildrop_destination_recipient_limit = 1
smtpd_recipient_limit = 30
smtpd_client_message_rate_limit = 0
smtpd_client_connection_count_limit = 0

virtual_alias_maps = hash:/etc/postfix/virtual

transport_maps = hash:/etc/postfix/transport
virtual_mailbox_domains = тут пару-тройку наших доменов, исключая mydestination
virtual_mailbox_base = /mailboxes
virtual_transport = maildrop
virtual_mailbox_maps = pgsql:/etc/postfix/mailbox.pgsql

virtual_uid_maps = static:506
#пользователь vmail

default_process_limit = 200
virtual_gid_maps = static:506
virtual_mailbox_limit = 51200000
#с maildrop не работает
#пока не нашел универсальное решение проблемы размера ящика

message_size_limit = 5120000
disable_vrfy_command = yes
bounce_queue_lifetime = 5d

alias_maps = hash:/etc/postfix/aliases
alias_database = hash:/etc/postfix/aliases


Теперь подробнее о файлах /etc/postfix/mailbox.pgsql и
/etc/postfix/client_check.pcre В /etc/postfix/mailbox.pgsql мы указываем
посфиксу каким макаром искать пользователя в БД

hosts = адрес машины с БД
user = владелец БД
password = соответственно пароль
dbname = mail #то, что приводили для примера
query = SELECT substring(c.login from 1 for 1)||'/'||c.login||'/Maildir/' from mailusers where login = '%u'||'@'||'%d';


Таким образом наличие пути говорит о наличии ящика на сервере.

В /etc/postfix/client_check.pcre зафильтруем всякие adsl'и и диалапы с
кабельным ТВ откуда не идёт ничего хорошего (исходный вариант нашел на
опеннете)


/(modem|dia(l|lup)|dialin|dsl|p[cp]p|cable|catv|poo(l|les)|dhcp|client|customer|user|[0-9]{6,})(-|.|[0-9])/ 550 Are you spamer?
/([0-9]{,4}-[0-9]{,4}-[0-9]{,4}-[0-9]{,4})/ 550 Are you spamer?
/([0-9]{,4}.[0-9]{,4}.[0-9]{,4}.[0-9]{,4}.{4,})/ 550 Are you spamer? If you think that the system is mistaken, please report details to abuse@mydomain.ru




Т.к. maildrop не умеет автоматом создавать директорию ящика, придётся его этому обучить.
В master.cf правим:

maildrop unix - n n - - pipe
flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient}
на

maildrop unix - n n - - pipe
flags=DRhu user=vmail argv=/etc/postfix/test -d ${recipient}


/etc/postfix/test

#!/bin/bash
if ! test -d /mailboxes/${2:0:1}/$2; then
mkdir /mailboxes/${2:0:1}/$2 && /usr/local/bin/maildirmake /mailboxes/${2:0:1}/$2/Maildir ;
fi
/usr/local/bin/maildrop $@
exit $?


делаем его исполняемым

Выполняем

mkdir /mailboxes/{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z} && chown vmail.vmail -R /mailboxes


SpamAssassin можно теперь сделать индивидуально или глобально, также
пользователи могут иметь свои white и black листы (читаем документацию)
для глобальной проверки почты spamassassin'om в /etc/maildroprc

Добавляем в начало:

if ( $SIZE < 256000 ) # Filter if message is less than 250k
{

log " running message through spamc"
exception {
xfilter '/usr/bin/spamc -u $LOGNAME'
}
}

#Если хотим, чтобы спам зарезался на месте:
if ( /^X-Spam-Status: *Yes/)
{
to "/dev/null"
}


Для проверки индивидуально - делаем тоже самое в файле
/mailboxes/firs_char_of_user/user/.maildroprc Если хотим сделать
красивее, то создаём файлик /mailboxes/scheck, в него пишем:

if ( $SIZE < 256000 ) # Filter if message is less than 250k
{

log " running message through spamc"
exception {
xfilter '/usr/bin/spamc -u $LOGNAME'
}
}


Создаём файлик /mailboxes/sdrop:

if ( /^X-Spam-Status: *Yes/)
{
to "/dev/null"
}


И теперь .maildroprc будет выглядеть:

#для проверки
include '/mailboxes/scheck'
#для удаления спама
include '/mailboxes/sdrop'


Для первого раза чтобы проверить свой почтовый ящик, нужно сначало
отправить себе письмо.


Об AWStats

Вобщем, он доступен в rpm. С ним идёт вся необходимая документация.


Об SqWebMail

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

На последок.

Читаем RFC 822, 2505.

Буду признателен за замечания, добавления и исправления.

Обновлено: 13.03.2015