Почтовый сервер postfix

Статья описывает создание почтового сервера с нуля для небольшой организации на базе дистрибутива ALTLinux, в итоге получается связка Postfix+Devecot+OpenSSL+MySQL+ClamAV+вебинтерфейс управления (pmpm)+вебинтерфейс для работы с почтой (roundcube).

Статический IP-адрес и регистрация домена

Я пишу ситуацию для Белорусских реалий, возможно у Вас ситуация будет немного другой.

В моем случае уже был выбран провайдер, это Белтелеком (ByFly) с тарифным планом "Домосед", очень хорошо, что этот тарифный план можно использовать как физическим, так и юридическим лицам. Соединение pppoe у меня поднимается прямо на сервере, у кого модем работает в режиме роутера, необходимо пробросить на сервер порты 53 и 25.

Так теперь нужно написать заявление на предоставление услуги статический IP адрес, это бумажный документ, в котором необходимо указать зачем вам нужен этот статический адрес, я писал для размещение в сети Интернет web-сайта и почтового сервера компании. Вам присылают форму, которую необходимо заполнить и отправить провайдеру по электронной почте, это для данных в whois. Статику делали примерно неделю, в результате чего был выделен адрес.

Теперь можно регистрировать домен, я регистрировал на open.by, проверяем домен на доступность и если он свободен, регистрируем наш домен и указываем наш статический IP адрес в качестве ДНС сервера, который будет держать нашу зону, если у вас два IP адреса, вообще хорошо. Домен регистрируют примерно недели две :( ну что делать, пришлось ждать. А пока время идет настраиваем ДНС.

DNS сервер Bind настроенный с использованием internal и external зон.

ДНС сервер является один из важнейших честей почтовой системы. Если Вы собрались поднять почтовый сервер, желательно, что бы у Вас был собственный ДНС сервер. Это избавит от многих проблем, которые бывают у провайдеров. Я не буду сильно подробно описывать настройку ДНС, об этом вполне достаточно написано в Интернете.

Как правило у небольших компаний нет лишних серверов, которые бы на одних держать зону локальной сети, а на других внешнюю зону, которая видна в сети Интернет. У bind'а есть возможность держать одну и ту же зону, но с разными записями в зависимости от того с какого интерфейса будет обращение. Делается это следующим образом:

В конфигурационном файле /var/lib/bind/etc/local.conf пишем примерно следующее:

acl mynetwork {
        192.168.1.0/24;
};
  
view "internal" {
match-clients { localnets; };
include "/etc/rfc1912.conf";
include "/etc/rfc1918.conf";
// Add other zones here
zone "trigran.by." {
    type master;
    file "trigran";
    allow-update {mynetwork;};
};
zone "1.168.192.in-addr.arpa." {
    type master;
    file "192.in-addr.arpa";
    allow-update {mynetwork;};
};
view "external" {
    match-clients { any; };
    recursion no;
    zone "trigran.by." {
    type master;
    file "trigran.by";
    allow-transfer { 193.201.116.2; };
   };
};

Что мы тут имеем:

acl mynetwork - указываем, кому будем разрешать обновлять нашу локальную зону.

В блоке view "internal" прописываем наши локальные зоны с указанием match-clients { localnets; };

В блоке view "external" прописываем наши внешние зоны, которые будут доступны из Интернета, замечу, что файлы зон разные trigran для локальной и trigran.by для внешней. Запись allow-transfer { 193.201.116.2; }; разрешает нашему secondary днс серверу загружать зону.

Вот файл зоны, которую мы показываем локальным пользователям:

$ORIGIN .
$TTL 604800     ; 1 week
trigran.by                   IN SOA  trigran.by. admin.trigran.by. (
                                32         ; serial
                                28800      ; refresh (8 hours)
                                14400      ; retry (4 hours)
                                60480      ; expire (16 hours 48 minutes)
                                86400      ; minimum (1 day)
                                )
                        NS      ns1.trigran.by.
                        NS      ns2.trigran.by.
$TTL 600          ; 10 minutes
                        A       192.168.1.4
                        A       192.168.1.9
$TTL 604800     ; 1 week
                        MX      10 mail.trigran.by.
$ORIGIN trigran.by.
$TTL 30000      ; 8 hours 20 minutes
cam1                    A       192.168.1.70
cam2                    A       192.168.1.71
d-link1                 A       192.168.1.1
d-link2                 A       192.168.3.1
ftp                     CNAME   ns1
glaz-saurona            A       192.168.1.56
mail                    CNAME   ns1
nb1                     A       192.168.1.52
;ну и так далее...

У нас тут два ДНС сервера, которые обслуживают эту зону (192.168.1.4 и 192.168.1.9), имеется MX запись ну и обычные A-записи.

Ну соответственно реверсная зона:

$ORIGIN .
$TTL 86400      ; 1 day
1.168.192.in-addr.arpa  IN SOA  trigran.by. admin.trigran.by. (
                                27         ; serial
                                10800      ; refresh (3 hours)
                                900        ; retry (15 minutes)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
                        NS      ns1.trigran.by.
                        NS      ns2.trigran.by.
$ORIGIN 1.168.192.in-addr.arpa.
$TTL 30000      ; 8 hours 20 minutes
1                       PTR     d-link1.trigran.by.
10                      PTR     ps1.trigran.by.
11                      PTR     ps2.trigran.by.
12                      PTR     ps3.trigran.by.
$TTL 86400      ; 1 day
2                       PTR     node1.trigran.by.
;ну и так далее ...

А вот external зона, доступная из сети Интернет (файл trigran.by):

$TTL 14400
trigran.by.             IN SOA  ns1.trigran.by. admin.trigran.by. (
                                2011090601; serial
                                10800     ; refresh
                                3600      ; retry
                                60480     ; expire (16 hours 48 minutes)
                                86400     ; minimum (1 day)
                                )
                        NS      ns1.trigran.by.
                        NS      ns.secondary.net.ua.
                        A       82.209.207.192
                        MX      10 trigran.by.
trigran.by.             TXT     "v=spf1 ip4:82.209.207.192/32 -all"
$ORIGIN trigran.by.
ns1                     A       82.209.207.192
mail                    CNAME   ns1
www                     CNAME   ns1
ns.secondary.net.ua.    A       195.149.112.1

Разберем ее подробней.

Заметьте формат серийного номера зоны, не знаю на сколько это важно, но есть рекомендации использовать именно такой формат, т.е. год,месяц,число,и кол-во правок за это число.

NS запись указывает на наш сервер, который и держит нашу зону, вторая запись NS это вторичный ДНС, который я зарегистрировал у secondary.net.ua, это бесплатный сервис. Обратите внимание, что у самой зоны есть запись A 82.209.207.192, нужно это для того, что бы можно было обратиться к нашему серверу как к домену второго уровня, например http://trigran.by вместо http://www.trigran.by

Запись MX 10 trigran.by как раз и указывает на наш почтовый обменник, здесь 10 это приоритет, если обменников больше, то чем ниже это значение, тем больший приоритет имеет сервер.

Запись типа TXT "v=spf1 ip4:82.209.207.192/32 -all" это один из способов борьбы со спамом, подробней про Sender Police Framework можно почитать на википедии: http://ru.wikipedia.org/wiki/Sender_Policy_Framework Данная запись крайне рекомендуется.

Далее указываем A запись для нашего ns1 и всяческие CNAME, какие нам могут понадобиться.

Еще нужно настроит бинд, что бы он слушал все необходимые интерфейсы, это делается в файле /var/lib/bind/etc/options.conf

listen-on { 127.0.0.1; 192.168.1.4; 82.209.207.192;};

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

Хочу еще заметить, что ДНС штука не очень шустрая и после правки зон необходимо перегружать зону через rndc либо дергать весь сервер через service bind reload.

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

Тестирование:

С любого компьютера, который находится в локальной сети делаем:

[sf@trigran ~]$ host -t NS trigran.by
trigran.by name server ns1.trigran.by.
trigran.by name server ns2.trigran.by.
[sf@trigran ~]$ host trigran.by
trigran.by has address 192.168.1.9
trigran.by has address 192.168.1.4
trigran.by mail is handled by 10 mail.trigran.by.
[sf@trigran ~]$ host mail.trigran.by
mail.trigran.by is an alias for ns1.trigran.by.
ns1.trigran.by has address 192.168.1.4

Как видно, эти записи из нашей internal зоны.

А вот что мы увидим, если попросим тоже самое но из сети Интернет (например через публичный днс гугла):

[sf@admin ~]$ host -t NS trigran.by 8.8.8.8
Using domain server:
Name: 8.8.8.8
Address: 8.8.8.8#53
Aliases:
trigran.by name server ns1.trigran.by.
trigran.by name server ns.secondary.net.ua.

А вот и MX запись

[sf@admin ~]$ host -t MX trigran.by
trigran.by mail is handled by 10 trigran.by.

Если сервера в Интернет еще не обновили Вашу зону, можно позапрашивать и у своего сервера:

[sf@admin ~]$ host trigran.by 82.209.207.192
Using domain server:
Name: 82.209.207.192
Address: 82.209.207.192#53
Aliases:
trigran.by has address 82.209.207.192
trigran.by mail is handled by 10 trigran.by

Запись в реверсной зоне:

[sf@admin ~]$ host 82.209.207.192
192.207.209.82.in-addr.arpa domain name pointer trigran.by.

И так если все нормально с ДНС, идем дальше.

Устанавливаем и настраиваем MySQL

Почему я выбрал базу данных для хранения учетных записей? Потому-что не хотел мешать системных пользователей linux с пользователями почтового сервера.

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

Устанавливаем и запускаем как обычно:

# apt-get install MySQL-server
# service mysqld start

Далее комментируем строчку skip-networking в файле /var/lib/mysql/my.cnf (у меня postfix без этого не соединялся с базой)

Теперь создаем базу данных, для примера mail,

mysql> create database mail;
Query OK, 1 row affected (0.00 sec)

а в ней следующие таблицы:

Таблица перенаправлений:

--
-- Структура таблицы `alias`
--
CREATE TABLE IF NOT EXISTS `alias` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `address` varchar(128) NOT NULL DEFAULT '',
  `goto` varchar(128) NOT NULL DEFAULT '',
  `description` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;
--
-- Дамп данных таблицы `alias`
--
INSERT INTO `alias` (`id`, `address`, `goto`, `description`) VALUES
(1, 'postmaster@trigran.by', 'root', ''),
(2, 'admin@trigran.by', 'root', ''),
(5, 'webmaster@trigran.by', 'root', ''),
(4, 'root@trigran.by', 'myemail@trigran.by', '');

Транспорт

--
-- Структура таблицы `transport`
--
CREATE TABLE IF NOT EXISTS `transport` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `domain` varchar(128) NOT NULL DEFAULT '',
  `transport` varchar(128) NOT NULL DEFAULT '',
  `description` varchar(128) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
--
-- Дамп данных таблицы `transport`
--
INSERT INTO `transport` (`id`, `domain`, `transport`, `description`) VALUES
(1, 'trigran.by', 'virtual', 'Basic');

И собственно таблица с аккаунтами:

CREATE TABLE IF NOT EXISTS `users` (
  `uid` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `gid` int(11) NOT NULL DEFAULT '12',
  `email` varchar(128) NOT NULL DEFAULT '',
  `passwd` varchar(128) NOT NULL DEFAULT '',
  `mailbox` varchar(255) NOT NULL DEFAULT '/var/spool/mail',
  `enabled` tinyint(1) NOT NULL DEFAULT '1',
  `description` varchar(255) NOT NULL DEFAULT '',
  `quota` int(11) NOT NULL DEFAULT '2048000',
  `maildir` varchar(255) NOT NULL,
  PRIMARY KEY (`uid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 PACK_KEYS=0 AUTO_INCREMENT=2000 ;

Видите, тут значение uid будет начинаться с 2000, это что бы не было каши с системными пользователями.

Я специально не разжевываю как и чем создавать базы данных и таблицы, предполагается, что Вы достаточно осведомлены в этом вопросе.

Я в последнее время просто юзаю phpMyAdmin. Так же нужно создать пользователя, который будет иметь права подключится к нашей базе и сделать select.

В общем то с MySQL все, не забываем только chkconfig mysqld on

Кроме настройки MySQL для наших доменов (домена) нужно создать директорию:

# mkdir /var/spool/mail/trigran.by

Так же создадим папку для imap

# mkdir /var/spool/mail/trigran.by/maildir

Если в таблице transport вы добавите еще какой-то домен, то и для него придется создать директории.

ClamAV

Проверку на вирусы делать нужно, несмотря на то, что дальше мы настроим не пропускать письма с вложениями типа exe,pif и т.п. Под линукс можно поставить разные сканеры почты и Kaspersky и DrWEB вроде бы, но clamav все же бесплатный, а со своими обязанностями справляется неплохо.

Устанавливаем следующие пакеты:

# apt-get install clamav clamsmtp clamav-freshclam clamav-db

У меня получился следуюший конфиг (точно не помню уже, что правил) /etc/clamav/clamd.conf

LogFile /var/log/clamav/clamd.log
LogFileMaxSize 0
LogTime yes
LogSyslog yes
LogFacility LOG_MAIL
LogVerbose yes
PidFile /var/run/clamav/clamd.pid
DatabaseDirectory /var/lib/clamav
LocalSocket /var/lib/clamav/clamd.socket
FixStaleSocket yes
MaxThreads 50
User mail
AllowSupplementaryGroups yes
AlgorithmicDetection yes
ScanPE yes
ScanELF yes
ScanOLE2 yes
ScanMail yes
ScanHTML yes
ScanArchive yes
ClamukoMaxFileSize 20M

Файл для обновления базы /etc/clamav/freshclam.conf

DatabaseDirectory /var/lib/clamav
UpdateLogFile /var/log/clamav/freshclam.log
LogFileMaxSize 0
LogTime yes
LogVerbose yes
LogSyslog yes
LogFacility LOG_MAIL
PidFile /var/run/clamav/freshclam.pid
DatabaseOwner mail
AllowSupplementaryGroups yes
DatabaseMirror database.clamav.net
NotifyClamd /etc/clamav/clamd.conf
SubmitDetectionStats /etc/clamav/clamd.conf

файл /etc/clamsmtpd.conf

OutAddress: 10026
Listen: 127.0.0.1:10025
ClamAddress: /var/lib/clamav/clamd.socket
Header: X-Virus-Scanned: ClamAV using ClamSMTP
TempDirectory: /var/tmp
PidFile: /var/run/clamsmtp/clamsmtp.pid
Action: drop
User: mail
VirusAction: /usr/local/bin/email-virus-notice.sh

И скрипт, который выполняется при обнаружении угрозы:

#!/bin/sh
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#   WARNING WARNING WARNING WARNING WARNING WARNING WARNING
#
#  By using variables passed in from clamsmtpd in file
#  manipulation commands without escaping their contents
#  you are opening yourself up to REMOTE COMPROMISE. You
#  have been warned. Do NOT do the following unless you
#  want to be screwed big time:
#
#  mv $EMAIL "$SENDER.eml"
#
#  An attacker can use the above command to compromise your
#  computer. The only variable that is guaranteed safe in
#  this regard is $EMAIL.
#
#  The following script does not escape its variables
#  because it only uses them in safe ways.
#
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# A sample script for virus actions. When testing make sure
# everything can run as the clamav (or relevant) user.
file="/var/log/clamav/virus.log"
dir="/var/lib/clamav/quarantine/"
exec 1>>$file
exec 2>>$file
# Add some fun log lines to the log file
echo "-------------------------------------------------------"
echo Sender  $SENDER
echo Recipients  $RECIPIENTS
echo Virus  $VIRUS
echo "-------------------------------------------------------"
# Move the virus file to another directory
# This only works if Quarantine is enabled
if [ -n "$EMAIL" ]; then
        mv "$EMAIL" "$dir"
        fi

Теперь мы будем знать, кто, кому и что за вирус прислал.

Запускаем все это дело и добавляем в автозагрузку:

# service clamd start
# service clamsmtpd start
# chkconfig clamd on
# chkconfig clamsmtpd on

С антивирусом вроде бы все, он загрузит актуальные базы и сервис clamsmtpd будет ждать подключений:

Postfix

В ALTLinux postfix установлен по умолчанию, но нам к нему нужно доставить поддержку MySQL и dovecot, ставим:

# apt-get install postfix-mysql postfix-dovecot

Приступаем к настройке конфигурационных файлов postifx:

Файл /etc/postfix/main.cf

myhostname = trigran.by
mydomain = trigran.by
myorigin = $mydomain
inet_interfaces = $myhostname, localhost, 192.168.1.4, 82.209.207.192
mydestination = localhost, $myhostname, localhost.$mydomain, /etc/postfix/mydestination
local_recipient_maps = $virtual_maps $virtual_mailbox_maps
unknown_local_recipient_reject_code = 550
mynetworks_style = subnet
mynetworks = $config_directory/mynetworks
relay_domains =$mydomain
#relayhost =
best_mx_transport = local
default_transport = smtp
#transport_maps = /etc/postfix/transport
#alias_maps = hash:/etc/postfix/aliases
#alias_database = hash:/etc/postfix/aliases
#mailbox_command = /usr/bin/procmail -a $DOMAIN -d $LOGNAME
smtpd_etrn_restrictions = permit_mynetworks, reject
smtpd_helo_required = yes
readme_directory = /etc/postfix/README_FILES
sample_directory = /etc/postfix/samples
sendmail_path = /usr/sbin/sendmail
setgid_group = postdrop
command_directory = /usr/sbin
manpage_directory = /usr/share/man
daemon_directory = /usr/libexec/postfix
newaliases_path = /usr/bin/newaliases
mailq_path = /usr/bin/mailq
queue_directory = /var/spool/postfix
mail_owner = postfix
content_filter = scan:127.0.0.1:10025
header_checks = regexp:/etc/postfix/header_checks
receive_override_options = no_address_mappings
mailbox_size_limit=209715200
message_size_limit=20971520
virtual_mailbox_limit=209715200
smtp_data_done_timeout = 7200s
virtual_alias_recursion_limit=10
#sasl
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
broken_sasl_auth_clients = yes
smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination,reject_rbl_client list.dsbl.org,reject_rbl_client relays.ordb.org,reject_rbl_client dynablock.wirehub.net,reject_rbl_client blackholes.wirehub.net,reject_rbl_client dnsbl.njabl.org
# Не общаться с почтовыми системами, которые не знают имени своего хоста
#smtpd_helo_restrictions = reject_unknown_hostname
virtual_mailbox_base = /
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-maps.cf
virtual_maps =  mysql:/etc/postfix/mysql-virtual.cf
virtual_minimum_uid = 500
virtual_uid_maps = mysql:/etc/postfix/mysql-virtual-uid.cf
virtual_gid_maps = mysql:/etc/postfix/mysql-virtual-gid.cf
transport_maps = mysql:/etc/postfix/mysql-transport.cf
recipient_canonical_maps = hash:/etc/postfix/canonical
recipient_bcc_maps = hash:/etc/postfix/recipient_bcc

Мне очень лениво расписывать все параметры файла, лучше Вы прочитаете подробней про конфигурацию postfix например на http://postfix.ru

Скажу лишь то, что myhostname должен действительно совпадать с вашим hostname, а так же с тем что указано в MX записи.

Файл /etc/postfix/master.cf

# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
scan    unix    -       -       n       -       16      smtp   -o smtp_send_xforward_command=yes
127.0.0.1:10026 inet  n -       n       -       16      smtpd -o content_filter=
    -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
    -o smtpd_helo_restrictions=
    -o smtpd_client_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o mynetworks_style=host
    -o smtpd_authorized_xforward_hosts=127.0.0.0/8
smtp    inet    n       -       -       -       -       smtpd
#628    inet    n       -       -       -       -       qmqpd
pickup  fifo    n       -       -       60      1       pickup
cleanup unix    n       -       -       -       0       cleanup
qmgr    fifo    n       -       -       300     1       qmgr
#qmgr   fifo    n       -       -       300     1       nqmgr
rewrite unix    -       -       -       -       -       trivial-rewrite
bounce  unix    -       -       -       -       0       bounce
defer   unix    -       -       -       -       0       bounce
flush   unix    n       -       -       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
smtp    unix    -       -       -       -       -       smtp
relay   unix    -       -       -       -       -       smtp
#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq   unix    n       -       -       -       -       showq
error   unix    -       -       -       -       -       error
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp    unix    -       -       -       -       -       lmtp
#
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# maildrop. See the Postfix MAILDROP_README file for details.
#
#maildrop  unix  -       n       n       -       -       pipe
#  flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient}
#
# The Cyrus deliver program has changed incompatibly, multiple times.
#
#old-cyrus unix  -       n       n       -       -       pipe
#  flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
# Cyrus 2.1.5 (Amos Gouaux)
#cyrus     unix  -       n       n       -       -       pipe
#  user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
#uucp      unix  -       n       n       -       -       pipe
#  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#ifmail    unix  -       n       n       -       -       pipe
#  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
#bsmtp     unix  -       n       n       -       -       pipe
#  flags=Fq. user=foo argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient
trace     unix  -       -       -       -       0       bounce
verify    unix  -       -       -       -       1       verify
anvil     unix  -       -       -       -       1       anvil
scache    unix  -       -       -       -       1       scache
discard   unix  -       -       -       -       -       discard
tlsmgr    unix  -       -       -       1000?   1       tlsmgr
#spam      unix  -       n       n       -       -       pipe
#    flags=R user=spam argv=/usr/bin/spamc -u spam -e /usr/sbin/sendmail -f $sender $recipient
retry     unix  -       -       -       -       -       error
proxywrite unix -       -       n       -       1       proxymap

Файл /etc/postfix/mynetworks

Тут прописываем нашу локалку.

127.0.0.1/32
192.168.0.0/16

Файл /etc/postfix/mydestination

Здесь прописываем все наши домены, в которые почту будет доставлять наш сервер.

trigran.by

Файл /etc/postfix/header_checks

Отбрасываем письма с ненужными вложениями, а спам перенаправляем на ящик spam@trigran.by

/(filename|name)=".*\.(pif|bat|scr|vbs|vbe|vb)"/ REJECT
/^X-Spam-Flag:.*YES*./ REDIRECT spam@trigran.by
/^Subject:.SPAM.*/ REDIRECT spam@trigran.by
/^Subject:.SUSPECTED.SPAM.*/ REDIRECT spam@trigran.by

Теперь файлики, описывающие настройки работы с MySQL, юзер для подключения к базе postfix и пароль pass

Файл /etc/postfix/mysql-transport.cf

user = postfix
password = pass
dbname = mail
hosts = 127.0.0.1
query = SELECT transport FROM transport WHERE domain = CONVERT('%s' USING cp1251)

Заметьте, что все что попадает в базу конвертируется из cp1251, сделано это из-за того, что некоторые виндовые юзеры иногда могут в адресе получателя вставить вместо латинской, русскую букву, легко ведь перепутать "с", "а" и т.п., и без этого конвертирования выскакивали ошибки.

Файл /etc/postfix/mysql-virtual.cf

user = postfix
password = pass
dbname = mail
hosts = 127.0.0.1
query = SELECT goto FROM alias WHERE address = CONVERT('%s' USING cp1251)

Файл /etc/postfix/mysql-virtual-uid.cf

user = postfix
password = pass
dbname = mail
hosts = 127.0.0.1
query = SELECT uid FROM users WHERE email  = CONVERT('%s' USING cp1251) and enabled = 1

Файл /etc/postfix/mysql-virtual-maps.cf

user = postfix
password = pass
dbname = mail
hosts = 127.0.0.1
query = SELECT mailbox FROM users WHERE email = CONVERT('%s' USING cp1251) and enabled = 1

Файл /etc/postfix/mysql-virtual-gid.cf

user = postfix
password = pass
dbname = mail
hosts = 127.0.0.1
query = SELECT gid FROM users WHERE email = CONVERT('%s' USING cp1251) and enabled = 1

С Постфиксом все, настраиваем Dovecot.

Настройка Dovecot

Dovecot нам предоставляет доступ к почте через pop3, pop3s, imap и imaps, а так же он отвечает за раскладывание почты по ящикам.

Устанавливаем его, если его еще у нас нет:

# apt-get install dovecot

Файл /etc/dovecot/dovecot.conf

protocols = pop3 imap
listen = *
dict {
#quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext
#expire = sqlite:/etc/dovecot/dovecot-dict-sql.conf.ext
}
!include conf.d/*.conf
!include_try local.conf

Файл cat /etc/dovecot/dovecot-sql.conf.ext

driver = mysql
connect = host=localhost dbname=mail user=postfix password=postpass
default_pass_scheme = PLAIN-MD5
password_query = SELECT email AS user, passwd AS password FROM users WHERE email = '%u' and enabled = 1
user_query = SELECT mailbox AS mail, maildir AS home, uid, gid FROM users WHERE email = '%u'

Остальные конфигурационные файлы находятся в директории conf.d

Я настраивал не все, приведу настройки только те, которые правил:

10-auth.conf

disable_plaintext_auth = no
auth_mechanisms = plain
!include auth-system.conf.ext
!include auth-sql.conf.ext

10-master.conf

service imap-login {
  inet_listener imap {
    #port = 143
  }
  inet_listener imaps {
    #port = 993
    #ssl = yes
  }
}
service pop3-login {
  inet_listener pop3 {
    #port = 110
  }
  inet_listener pop3s {
    #port = 995
    #ssl = yes
  }
}
service lmtp {
  unix_listener lmtp {
    #mode = 0666
  }
    # Avoid making LMTP visible for the entire internet
    #address =
    #port =
}
service imap {
}
service pop3 {
}
service auth {
  unix_listener auth-userdb {
    #mode = 0600
    #user =
    #group =
  }
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
  }
}
service auth-worker {
}
service dict {
  unix_listener dict {
    #mode = 0600
    #user =
    #group =
  }
}

20-imap.conf

protocol imap {
      mail_plugins = autocreate
 }

20-pop3.conf

protocol pop3 {
  pop3_uidl_format = %08Xu%08Xv
}

90-plugin.conf (создаем дополнительные папки imap)

plugin {
setting_name = autocreate
autocreate = Trash
autocreate2 = Spam
autosubscribe = Trash
autosubscribe2 = Spam
}

Все, можно пробовать взлетать,

# service dovecot start
# service postfix start

При первом запуске Dovecot должен сгенерировать сертификат SSL, для защещенного соединения по IMAPs и POP3s. Кстати если срок действия сертификата истек, достаточно удалить его на сервере и перезапустить Dovecot, он сделает новый.

Смотрим логи, если что-то не так исправляем. Теперь нам необходимо как-то создавать пользователей, для этого написан небольшой скрипт на php.

Настройка PMPM

Postfix+MySQL Password Manager v0.1 beta

Загружаем его по ссылке http://sites.google.com/site/speccyfan/poctovyj-server/pmpm-0.1.tar.gz

Распаковываем архив где-нибудь на http сервере, делаем на него alias или virtualhost, который будет доступен только из локалки,

правим файлик config.php

<?php
//SQUID+MySQL Password Managet version 0.1 by Yury Konovalov
//MySQL Configuration
        $mysqlhost="172.0.0.1";
        $mysqlbase="mail";
        $mysqluser="postfix";
        $mysqlpass="pass";
?>

и подключаемся

http://domain.com/pmpm/admin

Видим такую вот страничку:

Тут отображается наш домен, помните мы при создании таблиц внесли одну запись в таблицу транспортатра? Если нужно добавить еще один домен, то опять нужно добавить запись в эту таблицу, когда-нибудь я добавлю функционал для создания доменов автоматически.

Жмем на ссылку указывающую на домен и видим следующий диалог:

Вот тут мы можем создавать наших пользователей. Пишем желаемый адрес, коменнтарий и жмем кнопку "добавить пользователя". После чего жмем на ссылку Pass и создаем ему начальный пароль. Тут правда есть один подводный камень, дело в том, что более ранние версии dovecot сами создавали нужные папки imap, если юзер реально существует в базе. Теперь почему-то он создает, но при наличии следующих папок:

/var/spool/mail/domainname/username

/var/spool/mail/domainname/username/mail

/var/spool/mail/domainname/username/mail/.imap

Остальное он делает сам, но эти директории придется создавать нам, т.к. у апача как правило нет прав сюда писать (и особенно менять владельца файла), то пришлось написать еще один скрипт, pmwrap.php

Механизм такой:

1. PMPM при создании пользователя в базе данных, отправляет письмо новому пользователю и postfix для него создает mailbox (/var/spool/mail/domainname/username)

2. Так же создается (или добавляется, если он существует) файл "/var/www/html/pmpm/admin/flag/flag.txt", который содержит uid и имя нового пользоваетеля

3. Скрипт pmwrap.php будущи запущен от рута (например по крону) проверяет наличие этого flag.txt и содает директории меняя владельца на необходимый uid.

4. После создания директорий, файл flag.txt удаляется.

Вот такой вот костыль :-\

Создание алиасов. Если вернуться на главную страничку, используя кнопку "Назад", то увидим, под списков доменов, еще ссылку "Aliases", жмем на нее и попадаем в следующий диалог:

Тут можно создавать любые перенаправления.

Само собой нужно прикрыть доступ к этому безобразию при помощи .htaccess, а вот доступ на папку выше, где лежит index.php нужно дать обычным юзерам, через этот файл можно поменять свой пароль простому смертному.

Тестирование того, что уже получилось

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

[sf@trigran ~]$ telnet mail.trigran.by 25
Trying 192.168.1.4...
Connected to mail.trigran.by.
Escape character is '^]'.
220 trigran.by ESMTP Postfix
helo trigran.by
250 trigran.by
mail from: sf@trigran.by
250 2.1.0 Ok
rcpt to: sf@trigran.by
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
Test server
.
250 2.0.0 Ok: queued as 613904145F
quit
221 2.0.0 Bye
Connection closed by foreign host.
[sf@trigran ~]$

Смотрим логи:

(я бычно запускаю tailf /var/log/mail/all) и вот что видим:

Sep 19 14:29:37 trigran postfix/smtpd[25220]: connect from trigran.by[192.168.1.4]
Sep 19 14:29:37 trigran dovecot: auth: Debug: auth client connected (pid=25220)
Sep 19 14:29:50 trigran postfix/smtpd[25220]: disconnect from trigran.by[192.168.1.4]
Sep 19 14:29:53 trigran postfix/smtpd[25220]: connect from trigran.by[192.168.1.4]
Sep 19 14:30:22 trigran postfix/smtpd[25220]: 613904145F: client=trigran.by[192.168.1.4]
Sep 19 14:30:33 trigran postfix/cleanup[25239]: 613904145F: message-id=<20110919113022.613904145F@trigran.by>
Sep 19 14:30:33 trigran postfix/qmgr[2512]: 613904145F: from=<sf@trigran.by>, size=330, nrcpt=1 (queue active)
Sep 19 14:30:33 trigran clamsmtpd: 100086: accepted connection from: 127.0.0.1
Sep 19 14:30:33 trigran dovecot: auth: Debug: auth client connected (pid=25242)
Sep 19 14:30:33 trigran postfix/smtpd[25242]: connect from localhost.localdomain[127.0.0.1]
Sep 19 14:30:33 trigran postfix/smtpd[25242]: 872A042BB2: client=trigran.by[192.168.1.4]
Sep 19 14:30:33 trigran postfix/cleanup[25239]: 872A042BB2: message-id=<20110919113022.613904145F@trigran.by>
Sep 19 14:30:33 trigran postfix/qmgr[2512]: 872A042BB2: from=<sf@trigran.by>, size=546, nrcpt=1 (queue active)
Sep 19 14:30:33 trigran clamsmtpd: 100086: from=sf@trigran.by, to=sf@trigran.by, status=CLEAN
Sep 19 14:30:33 trigran postfix/smtp[25240]: 613904145F: to=<sf@trigran.by>, relay=127.0.0.1[127.0.0.1]:10025, delay=22, delays=22/0.02/0.05/0.09, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 872A042BB2)
Sep 19 14:30:33 trigran postfix/qmgr[2512]: 613904145F: removed
Sep 19 14:30:33 trigran postfix/smtpd[25242]: disconnect from localhost.localdomain[127.0.0.1]
Sep 19 14:30:33 trigran postfix/virtual[25245]: 872A042BB2: to=<sf@trigran.by>, relay=virtual, delay=0.24, delays=0.09/0.01/0/0.14, dsn=2.0.0, status=sent (delivered to mailbox)
Sep 19 14:30:33 trigran postfix/qmgr[2512]: 872A042BB2: removed
Sep 19 14:30:35 trigran postfix/smtpd[25220]: disconnect from trigran.by[192.168.1.4]

Видим,что письмо проверилось антивирусом и в итоге "delivered to mailbox", т.е. доставлено.

Проверяем:

[sf@trigran ~]$ telnet mail.trigran.by 110
Trying 192.168.1.4...
Connected to mail.trigran.by.
Escape character is '^]'.
+OK Dovecot ready.
user sf@trigran.by
+OK
pass password
+OK Logged in.
stat
+OK 55 804932
retr 55
+OK 635 octets
Return-Path: <sf@trigran.by>
X-Original-To: sf@trigran.by
Delivered-To: sf@trigran.by
Received: from trigran.by (localhost.localdomain [127.0.0.1])
        by trigran.by (Postfix) with ESMTP id 872A042BB2
        for <sf@trigran.by>; Mon, 19 Sep 2011 14:30:33 +0300 (EEST)
Received: from trigran.by (trigran.by [192.168.1.4])
        by trigran.by (Postfix) with SMTP id 613904145F
        for <sf@trigran.by>; Mon, 19 Sep 2011 14:30:11 +0300 (EEST)
Message-Id: <20110919113022.613904145F@trigran.by>
Date: Mon, 19 Sep 2011 14:30:11 +0300 (EEST)
From: sf@trigran.by
To: undisclosed-recipients:;
X-Virus-Scanned: ClamAV using ClamSMTP
Test server
.
quit
+OK Logging out.
Connection closed by foreign host.

Вот и получили наше же письмо, что бы проверить imap и тем более imap через SSL, проще поставить какой-нибудь почтовый клиент, например Mozilla Thunderbird.

Но иногда нужен доступ с Интернета к нашему ящику, для этого я развернул Roundcube.

Установка Roundcube

# apt-get install roundcube roundcube-apache

Roundcube умеет работать с разными базами данных, но у нас уже установлен MySQL, поэтому продолжаем использовать его.

Создаем базу

# mysql -p
mysql> create database roundcube;
Query OK, 1 row affected (0.00 sec)
mysql> quit
Bye

Далее выполняем следующий запрос:

# mysql -D roundcube -p < /usr/share/doc/roundcube-0.5.1/SQL/mysql.initial.sql

Теперь правим следующий конфигурационный файлик:

/etc/roundcube/db.inc.php

В котором редактируем следующую строчку примерно до такого вида:

$rcmail_config['db_dsnw'] = 'mysql://user:pass@localhost/roundcube';

Само собой юзера с паролем для подключения к базе нужно создать заранее.

Теперь можно подключаться к нашему roundcube по адресу http://domain.ru/roundcube

Что еще можно поправить:

1. Лимит на размер сообщения, по умолчанию письмо не может быть больше 5MB, правится в файле

/usr/share/roundcube/.htaccess

У меня такие параметры:

php5_value      upload_max_filesize     20M
php5_value      post_max_size           20M
php5_value      memory_limit            128M

2. Roundcube по умолчанию может работать с разными серверами. И потому спрашивает

кроме имени пользователя и пароля еще и сервер, можно задать наш сервер жестко в файле

/etc/roundcube/main.inc.php

$rcmail_config['default_host'] = 'trigran.by';

Теперь он не будет спрашивать сервер при логине.

Прежде чем слать почту в Интернет

Прежде чем светить свой домен, лучше убедиться в нормальной настройки сервера DNS и почтового сервера. Для этого я использовал следующие online сервисы:

http://www.intodns.com - проверяет ДНС сервер, убидитесь, что запись MX у вас корректна и существует реверсная запись.

http://www.mxtoolbox.com - Сервис для комплексной проверки вашего почтовика, вот например что у вас должно получиться при прохождении SMTP теста:

smtp:82.209.207.192

220 trigran.by ESMTP Postfix

OK - 82.209.207.192 resolves to trigran.by

OK - Reverse DNS matches SMTP Banner

0 seconds - Good on Connection time

Not an open relay.

3.011 seconds - Good on Transaction time

Так же тут можно и нужно провести проверку на то, не светится ли ваш IP в блеклистах. У меня так получилось, что диапазон, из которого был выдан мне провайдером IP адрес был занесен в blacklist (Spamhaus-ZEN), из-за чего почта не уходила на gmail.com, благо сервис предоставляет возможность выписать себя с этого листа самостоятельно, после чего почта начала работать исправно.

Postfix как relay для gmail

Настройка postfix в качестве релея для gmail описана тут: postfix как релей для gmail

Ну вот как-то так, пожалуй на данном этапе мне добавить нечего. Удачи.