Мы — долго запрягаем, быстро ездим, и сильно тормозим.
www.lissyara.su —> статьи —> OpenBSD —> Демоны —> exim + cyrus-imapd

Настройка exim + cyrus-imapd + mysql на базе OpenBSD

Автор: fr33man.


Началось все как всегда банально — кто-то постучал в асю. Спрашивали, как настроить cyrus-imap. Я с ним не работал, поэтому честно ответил, что не знаю, но пообещал разобраться(благо времени немного было). Но просто разобраться было не интересно. :) Поэтому я решил настроить почтовую связку на базе OpenBSD. В принципе все довольно просто, но меня заинтересовал cyrus-imap, который, как выяснилось, хранит всю почту в своей собственной базе(db). После гугления этого вопроса я наткнулся на много различных обсуждений, в которых часто говорилось, что cyrus-imap всех рвет по скорости. Я немного подумал и решил, что нужно его настроить, а потом потестировать. )) Здесь описан процесс его настройки на чистой системе OpenBSD-4.2.
Так же хочется отдельно сказать, что большинство конфигов(exim и postfixadmin) я взял из статьи Лиса(lissyara) про связку exim + courer-imap.
Итак приступим.

Ставим mysql-сервер и mysql-клиент:

# export PKG_PATH="ftp://ftp.openbsd.org/pub/OpenBSD/4.2/packages/i386/"
# pkg_add mysql-server
mysql-client-5.0.45: complete
p5-DBD-mysql-3.0008:p5-Net-Daemon-0.39: complete
p5-DBD-mysql-3.0008:p5-PlRPC-0.2018p0: complete
p5-DBD-mysql-3.0008:p5-DBI-1.53: complete
p5-DBD-mysql-3.0008: complete
mysql-server-5.0.45: complete
--- mysql-server-5.0.45 -------------------
You can find detailed instructions on how to install a database
in /usr/local/share/doc/mysql/README.OpenBSD.
#

Установка mysql завершена. Давайте немного его настроим. Для начала создадим БД:


# /usr/local/bin/mysql_install_db
Installing MySQL system tables...
OK
Filling help tables...
OK
PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !
To do so, start the server, then issue the following commands:
/usr/local/bin/mysqladmin -u root password 'new-password'
/usr/local/bin/mysqladmin -u root -h openbsd.my.domain password 'new-password'
See the manual for more instructions.
Please report any problems with the /usr/local/bin/mysqlbug script!

The latest information about MySQL is available on the web at
http://www.mysql.com
Support MySQL by buying support/licenses at http://shop.mysql.com
#

Теперь создадим свой login class для Mysql'а. Добавим в /etc/login.conf такие строки:


mysql:\
     :openfiles-cur=1024:\
     :openfiles-max=2048:\
     :tc=daemon:

и пересоздадим бд login.conf:

# cap_mkdb /etc/login.conf

Хорошо. Теперь добавим mysql в автозапуск:

# cat >> /etc/rc.local
if [ -x /usr/local/bin/mysqld_safe ] ; then
   su -c mysql root -c '/usr/local/bin/mysqld_safe >/dev/null 2>&1 &'
   echo -n ' mysql'
fi

Запускаем:


# su -c mysql root -c '/usr/local/bin/mysqld_safe >/dev/null 2>&1 &'
# ps ax | grep sql
19337 p0  I       0:00.03 /bin/sh /usr/local/bin/mysqld_safe
29798 p0  I       0:00.74 /usr/local/libexec/mysqld --basedir
=/usr/local --datadir=/var/mysql --user=_mysql --pid-file=
/var/mysql/openbsd.my.domain.pid --po
 4427 p0  R+      0:00.01 grep sql
#

Как видите — все работает.
Удаляем из mysql левые БД.

# mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.0.45-log OpenBSD port: mysql-server-5.0.45

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| test               |
+--------------------+
3 rows in set (0.00 sec)

mysql> drop database test;
Query OK, 0 rows affected (0.00 sec)

mysql> quit
bye
#

Отлично. Так как юзать мы будем postfixadmin, то я вкратце напишу, как настроить apache. Перед установкой php нужно установить xbase — Там есть необходимые библиотеки. Монтируем сидюк с Openbsd и делаем такую штуку:

# cd /
# mount -t cd9660 /dev/cd0a /mnt
# tar xzvphf /mnt/4.2/i386/xbase42.tgz

Усе — теперь ставим php5:

# pkg_add php5-core
libiconv-1.9.2p3: complete
gettext-0.14.6p0: complete
libxml-2.6.29: complete
php5-core-5.2.3: complete
--- php5-core-5.2.3 -------------------
To finish the install, enable the php5 module with:
    /usr/local/sbin/phpxs -s

To enable parsing of PHP scripts, add the following to
/var/www/conf/httpd.conf:

    AddType application/x-httpd-php .php

Copy the config file below into /var/www/conf/php.ini
/usr/local/share/examples/php5/php.ini-recommended

Don't forget that the default OpenBSD httpd is chrooted
into /var/www by default, so you may need to create support
directories such as /var/www/tmp for PHP to work correctly.
#

И ставим расширение php5 — mysql:

# pkg_add php5-mysql
php5-mysql-5.2.3: complete
--- php5-mysql-5.2.3 -------------------
Enable this module in php.ini using the following command:

      /usr/local/sbin/phpxs -a mysql
#

Усе установилось... Теперь добавляем в Httpd.conf строчку для модуля php5:

# /usr/local/sbin/phpxs -s
[activating module `php5' in /var/www/conf/httpd.conf]
cp /usr/local/lib/php/libphp5.so /usr/lib/apache/modules/libphp5.so
chmod 755 /usr/lib/apache/modules/libphp5.so
cp /var/www/conf/httpd.conf /var/www/conf/httpd.conf.bak
cp /var/www/conf/httpd.conf.new /var/www/conf/httpd.conf
rm /var/www/conf/httpd.conf.new

You should copy the sample configuration files from
/usr/local/share/examples/php5 to /var/www/conf/php.ini
#

И включаем модуль mysql:

# cp /usr/local/share/examples/php5/php.ini-dist /var/www/conf/php.ini
# /usr/local/sbin/phpxs -a mysql
Activating extension : mysql
#

Добавляем две строки в /var/www/conf/httpd.conf:

DirectoryIndex index.php index.html
AddType application/x-httpd-php .php

Добавляем httpd в автозапуск:

# cat >> /etc/rc.conf.local
httpd_flags=""

Запускаем apache:

# apachectl start
/usr/sbin/apachectl start: httpd started
# ps ax | grep httpd
17814 ??  Is      0:00.12 httpd: parent [chroot /var/www] (httpd)
16596 ??  I       0:00.02 httpd: child (httpd)
28908 ??  I       0:00.01 httpd: child (httpd)
 6870 ??  I       0:00.02 httpd: child (httpd)
19022 ??  I       0:00.03 httpd: child (httpd)
29760 ??  I       0:00.03 httpd: child (httpd)
21614 p0  I+      0:00.01 grep httpd
#

Вгоняем в Mysql такой dump:

# cd /root
# cat > dump.sql

--
-- БД: `exim`
--
USE mysql;
INSERT INTO `user` (`Host`, `User`, `Password`)
VALUES ('localhost','exim',password('exim'));
INSERT INTO `db` (`Host`, `Db`, `User`, `Select_priv`)
VALUES ('localhost','exim','exim','Y');
FLUSH PRIVILEGES;
GRANT USAGE ON exim.* TO exim@localhost;
GRANT SELECT, INSERT, DELETE, UPDATE ON exim.* TO exim@localhost;
CREATE DATABASE `exim`;
USE `exim`;

-- --------------------------------------------------------

--
-- Структура таблицы `admin`
--

CREATE TABLE `admin` (
  `username` varchar(255) NOT NULL default '',
  `password` varchar(255) NOT NULL default '',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  `active` tinyint(1) NOT NULL default '1',
  PRIMARY KEY  (`username`),
  KEY `username` (`username`)
) TYPE=MyISAM COMMENT='Exim and cyrus-imap Admin - Virtual Admins';

-- --------------------------------------------------------

--
-- Структура таблицы `alias`
--

CREATE TABLE `alias` (
  `address` varchar(255) NOT NULL default '',
  `goto` text NOT NULL,
  `domain` varchar(255) NOT NULL default '',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  `active` tinyint(1) NOT NULL default '1',
  `copy_mail` int(1) NOT NULL default '1',
  PRIMARY KEY  (`address`),
  KEY `address` (`address`)
) TYPE=MyISAM COMMENT='Exim and cyrus-imap Admin - Virtual Aliases';

-- --------------------------------------------------------

--
-- Структура таблицы `domain`
--

CREATE TABLE `domain` (
  `domain` varchar(255) NOT NULL default '',
  `description` varchar(255) NOT NULL default '',
  `aliases` int(10) NOT NULL default '0',
  `mailboxes` int(10) NOT NULL default '0',
  `maxquota` int(10) NOT NULL default '0',
  `transport` varchar(255) default NULL,
  `backupmx` tinyint(1) NOT NULL default '0',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  `active` tinyint(1) NOT NULL default '1',
  PRIMARY KEY  (`domain`),
  KEY `domain` (`domain`)
) TYPE=MyISAM COMMENT='Exim and cyrus-imap Admin - Virtual Domains';

-- --------------------------------------------------------

--
-- Структура таблицы `domain_admins`
--

CREATE TABLE `domain_admins` (
  `username` varchar(255) NOT NULL default '',
  `domain` varchar(255) NOT NULL default '',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `active` tinyint(1) NOT NULL default '1',
  KEY `username` (`username`)
) TYPE=MyISAM COMMENT='Exim and cyrus-imap Admin - Domain Admins';

-- --------------------------------------------------------

--
-- Структура таблицы `log`
--

CREATE TABLE `log` (
  `timestamp` datetime NOT NULL default '0000-00-00 00:00:00',
  `username` varchar(255) NOT NULL default '',
  `domain` varchar(255) NOT NULL default '',
  `action` varchar(255) NOT NULL default '',
  `data` varchar(255) NOT NULL default '',
  KEY `timestamp` (`timestamp`)
) TYPE=MyISAM COMMENT='Exim and cyrus-imap Admin - Log';

-- --------------------------------------------------------

--
-- Структура таблицы `mailbox`
--

CREATE TABLE `mailbox` (
  `username` varchar(255) NOT NULL default '',
  `password` varchar(255) NOT NULL default '',
  `name` varchar(255) NOT NULL default '',
  `maildir` varchar(255) NOT NULL default '',
  `quota` int(10) NOT NULL default '0',
  `domain` varchar(255) NOT NULL default '',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  `active` tinyint(1) NOT NULL default '1',
  PRIMARY KEY  (`username`),
  KEY `username` (`username`)
) TYPE=MyISAM COMMENT='Exim and cyrus-imap Admin - Virtual Mailboxes';

-- --------------------------------------------------------

--
-- Структура таблицы `vacation`
--

CREATE TABLE `vacation` (
  `email` varchar(255) NOT NULL default '',
  `subject` varchar(255) NOT NULL default '',
  `body` text NOT NULL,
  `cache` text NOT NULL,
  `domain` varchar(255) NOT NULL default '',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `active` tinyint(1) NOT NULL default '1',
  PRIMARY KEY  (`email`),
  KEY `email` (`email`)
) TYPE=MyISAM COMMENT='Exim and cyrus-imap Admin - Virtual Vacation';

# mysql -u root < dump.sql

Ставим postfix-admin:


# cd /var/www/htdocs/
# ftp \
> http://optusnet.dl.sourceforge.net/sourceforge/postfixadmin/postfixadmin-2.1.0.tgz
Trying 211.29.132.142...
Requesting 
http://optusnet.dl.sourceforge.net/sourceforge/postfixadmin/postfixadmin-2.1.0.tgz
100% |***************************************|   156 KB    00:04
Successfully retrieved file.
#

Устанавливаем:

# tar zxf postfixadmin-2.1.0.tgz
# mv postfixadmin-2.1.0 mailadmin
# chown -R www:www /var/www/htdocs/mailadmin/

Теперь редактируем конфиг postfixadmin'а:

# cd mailadmin
# cp config.inc.php.sample config.inc.php

Редактируем config.inc.php:

$CONF['database_type'] = 'mysql';
$CONF['database_host'] = '127.0.0.1';
$CONF['database_user'] = 'exim';
$CONF['database_password'] = 'exim';
$CONF['database_name'] = 'exim';
$CONF['database_prefix'] = '';
$CONF['encrypt'] = 'cleartext';
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
$CONF['smtp_server'] = '127.0.0.1';
$PALANG['charset'] = 'cp1251';

И последний штрих:

# cat config.inc.php | \
> sed 's/change-this-to-your.domain.tld/local.ru/' > \
> tmp && mv tmp config.inc.php

Если будете использовать русский язык, то файл: /var/www/htdocs/mailadmin/templates/admin_menu.tpl — тут после строки содержащий backup воткните 4-е <br>.
Так же не забудьте запаролить админку.

Все. Можете заходить по адресу: http://ваш_серв/mailadmin/admin/.

Осталось осилить exim и cyrus-imap..

Ставим exim:

# cd /usr/ports/mail/exim/

Добавляем в Makefile, перед строкой

FLAVORS=no_exiscan no_x11 mysql postgresql sqlite3 ldap iconv sasl

такую вещь:

EXIM_MAKECAT+=          "TRANSPORT_LMTP=yes\n"

Это необходимо для того, что подрубить в exim'е транспорт lmtp. Собираем пакет:

# env FLAVOR="no_x11 mysql" make package

... skipped ...
===>  Building package for exim-4.67-no_x11-mysql
Create /usr/ports/packages/i386/all/exim-4.67-no_x11-mysql.tgz
Link to /usr/ports/packages/i386/ftp/exim-4.67-no_x11-mysql.tgz
Link to /usr/ports/packages/i386/cdrom/exim-4.67-no_x11-mysql.tgz
#

Устанавливаем:

# pkg_add /usr/ports/packages/i386/all/exim-4.67-no_x11-mysql.tgz
useradd: Warning: home directory `/var/spool/exim' 
doesn't exist, and -m was not specified
exim-4.67-no_x11-mysql: complete
--- exim-4.67-no_x11-mysql -------------------
If you intend replacing sendmail with exim, then don't
forget to modify /etc/mailer.conf accordingly; see
mailwrapper(8).

A perl script may help converting from exim-3.xx config
files and has been installed in
      /usr/local/share/examples/exim/convert4r4
you have mail in /var/mail/root
#

Составляем конфиг /etc/exim/configure:

#!/bin/sh
# Файл конфигурации: /usr/local/etc/exim/configure

# моя конфига экзма. Будь проклят тот день,
# когда мне пришла в голову мысль подписать
# русские поясния ко всем пунктам! :) Хоть и
# делал я это в первую очередь для себя -
# чтоб лучше понять его, но работа эта оказалась
# слишком масштабная и неблагодарная...


# Имя хоста. Используется в EHLO.
# Фигурирует в других пунктах, если они не заданы -
# типа qualify_domain и прочих..
# Если тут ничё не установлено (строка закомметрована)
# то используется то, что вернёт функция uname()
primary_hostname = local.ru

# Вводим данные для подключения к MySQL серверу.
# словечко `hide`, вначале, означает, что при
# вызове проверки конфига командой
# exim -bV config_file эти данные не будут отображаться.
# Если без него - то будут показаны... Формат записи:
# хост/имя_бд/пользователь/пароль
hide mysql_servers = localhost/exim/exim/exim



# Делаем список локальных доменов. Далее этот
# список будет фигурировать в виде +local_domains
# В данном случае домены выбираются из БД MySQL. Также
# можно их просто перечислить через двоеточие. Есть интересная
# возможность, можно указать юзер@[хост] - lissyara@[222.222.4.5]
domainlist local_domains = ${lookup mysql{SELECT `domain` \
                            FROM `domain` WHERE \
                            `domain`='${domain}' AND \
                            `active`='1'}}

# делаем список доменов с которых разрешены релеи.
# Далее этот список будет в виде +relay_to_domains
# Можно использовать символы подстановки, типа:
# .... = *.my.domen.su : !spam.my.domen.su : first.su
# тогда пропускается всё, что похоже на *.my.domen.su, но
# от spam.my.domen.su релеится почта не будет.
domainlist relay_to_domains = ${lookup mysql{SELECT `domain` \
                            FROM `domain` WHERE \
                            `domain`='${domain}' AND \
                            `active`='1'}}

# Составляем список хостов с которых разрешён неавторизованый
# релей. Обычно в нём находятся локальные сети, и локалхост...
# ЛокалХост в двух видах был внесён сознательно - пару раз
# сталкивался с кривым файлом /etc/hosts - результатом было
# непонимание `localhost` но пониманием 127.0.0.1/8
hostlist   relay_from_hosts = localhost:127.0.0.0/8:192.168.0.0/16

# Вводим названия acl`ов для проверки почты. (В общем-то, это
# необязательно, если вы делаете открытый релей, или хотите
# принимать вообще всю почту с любого хоста для любых
# получателей... Тока потом не жалуйтесь что у Вас спам
# и провайдер выкатывает немеряный счёт :))
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data

# Имя домена добавляемое для локальных отправителей (реальных
# юзеров системы) т.е. почта отправляемая от root, будет от
# root@домен_указанный_здесь. Если пункт незадан, то используется
# имя хоста из `primary_hostname`. Логичней было бы написать здесь
# local.ru, но мне удобней иначе:
qualify_domain = local.ru

# Имя хоста для ситуации, обратной предыдущей, - это имя домена
# добавляемое к почте для системных юзеров, ну и вообще для почты
# пришедшей на адрес типа `root`, `lissyara`, & etc... Если этот
# пункт незадан то используется значение полученное из
# предыдущего пункта - `qualify_domain`
qualify_recipient = local.ru

# А это как раз кусок вышеописанного анахронизма - про почту в
# виде user@[222.222.222.222] - принимать её или нет. По дефолту
# (когда строка закомментирована) значение - false. Если захотите
# поставить true то надо будет добавить в список доменов
# комбинацию @[] - она означает `все локальные адреса`
allow_domain_literals = false

# Пользователь от которого работает exim
exim_user = _exim 

# группа в кторой работает exim
exim_group = _exim 

# запрещаем работу доставки под юзером root - в целях безопасности
never_users = root

# Тоже анахронизм (на самом деле, не такой уж анахронизм, но все давно
# забили на ident и закрыли файрволлом tcp:113...) Это проверка - Ваш
# хост спрашивает у удалённого, с которого было подключение, а кто
# собстно ко мне подключился на такой-то порт? Если на удалённом хосте
# работает identd - он может ответить (а может и не ответить - как
# настроить), скажет UID пользователя от которого установлено
# соединение, тип ОС, и имя пользователя. Теперь, понимаете, почему
# у всех оно зарублено и файрволлами позакрыто? :) Это же палево :)
# Тока на мой взгляд, если на сервере всё настроено правильно -
# то вовсе это и не страшно.
# Короче - если хостс поставить * то будет проверять все. Таймаут -
# если поставить 0 то не будет ждать ответа ни от кого. По
# вышеописанным причинам - отключаем
#rfc1413_hosts = *
rfc1413_query_timeout = 0s

# Если сообщение было недоставлено, то генерится соощение
# об ошибке. Если сообщение об ошибке не удалось доставить
# то оно замораживается на указанный в этом пункте срок,
# после чего снова попытка доставить его. При очередной
# неудаче - сообщение удаляется.
ignore_bounce_errors_after = 45m

# Замороженные сообщения, находящиеся в очереди, дольше
# указанного времени удаляются и генерится сообщение
# об ошибке (при условии, что это не было недоставленное
# сообщение об ошибке :))
timeout_frozen_after = 15d

# собсно на этом штатный конфиг кончился, но
# меня-то это не устраивает... Поэтому пошли пункты,
# почёрпнутые из других источников.

# список адресов, через запятую, на которые засылаются
# сообщения о замороженных сообщениях (о замороженых
# уведомлениях о заморозке, сообщения не генерятся. - я
# надеюсь эта строка понятна :))
freeze_tell = admin@local.ru

# Список хостов, почта от которых принимается, несмотря
# на ошибки в HELO/EHLO
helo_accept_junk_hosts = 192.168.0.0/16

# Через какое время повторять попытку доставки
# замороженного сообщения
auto_thaw = 1h

# Приветствие сервера
smtp_banner = "$primary_hostname, ESMTP EXIM $version_number"

# Максимальное число одновременных подключений по
# SMTP. Рассчитывать надо исходя из нагрузки на сервер
smtp_accept_max = 50

# максимальное число сообщений принимаемое за одно соединение
# от удалённого сервера (или пользователя). C числом 25
# я имел проблемы тока один раз - когда у меня три дня лежал
# инет и после его подъёма попёрли мессаги. Но у меня не так
# много почты - всего 30 пользователей.
smtp_accept_max_per_connection = 25

# чё-то про логи и борьбу с флудом - я так понимаю -
# максимальное число сообщений записываемых в логи
smtp_connect_backlog = 30

# максимальное число коннектов с одного хоста
smtp_accept_max_per_host = 20

# Ход ладьёй - для увеличения производительности,
# директория `spool` внутри, разбивается на
# директории - это ускоряет обработку
split_spool_directory = true

# Если у сообщения много адресатов на удалённых хостах,
# то запускатеся до указанного числа максимально число
# параллельных процессов доставки
remote_max_parallel = 15

# при генерации сообщения об ошибке прикладывать
# не всё сообщение, а кусок (от начала) указанного
# размера (иногда полезно и целиком - в таком случае
# просто закомментируйте эту строку)
return_size_limit = 70k

# размер сообщения. У меня стоит относительно большой
# размер (`относительно` - потому, что на большинстве
# хостов оно ограничено 2-5-10мб, либо стоит анлим.)
message_size_limit = 24M

# разрешаем неположенные символы в HELO (столкнулся
# с этим случайно - имя фирмы состояло из двух слов
# и какой-то раздолбай домен обозвал my_firme_name
# прям с подчёркиваниями... Виндовые клиенты при
# соединении радостно рапортовали о себе
# `vasya.my_firme_name` ну а экзим их футболил :))
helo_allow_chars = _

# Принудительная синхронизация. Если отправитель
# торопится подавать команды, не дождавшись ответа,
# то он посылается далеко и надолго :) Немного,
# спам режется.
smtp_enforce_sync = false

# Выбираем, что мы будем логировать
# + - писать в логи,
# - - Не писать в логи.
# +all_parents - все входящие?
# +connection_reject - разорваные соединения
# +incoming_interface - интерфейс (реально - IP)
# +lost_incoming_connections - потеряные входящие
# соединения
# +received_sender - отправитель
# +received_recipients - получатель
# +smtp_confirmation - подтверждения SMTP?
# +smtp_syntax_error - ошибки синтаксиса SMTP
# +smtp_protocol_error - ошибки протокола SMTP
# -queue_run - работа очереди (замороженные мессаги)
log_selector = \
    +all_parents \
    +connection_reject \
    +incoming_interface \
    +lost_incoming_connection \
    +received_sender \
    +received_recipients \
    +smtp_confirmation \
    +smtp_syntax_error \
    +smtp_protocol_error \
    -queue_run

# Убираем собственную временную метку exim`a из логов, её ставит
# сам syslogd - нефига дублировать
syslog_timestamp = no

begin acl

# Эти правила срабатывают для каждого получателя
acl_check_rcpt:

  # принимать сообщения которые пришли с локалхоста,
  # не по TCP/IP
  accept  hosts = :
  accept  hosts = localhost : 127.0.0.1

  # Запрещаем письма содержащие в локальной части
  # символы @; %; !; /; |. Учтите, если у вас было
  # `percent_hack_domains` то % надо убрать.
  # Проверяются локальные домены
  deny    message       = "Unknown symbols in address"
          domains       = +local_domains
          local_parts   = ^[.] : ^.*[@%!/|]

  # Проверяем недопустимые символы для
  # нелокальных получателей:
  deny    message       = "Unknown symbols in address"
          domains       = !+local_domains
          local_parts   = ^[./|] : ^.*[@%!] : ^.*/\\.\\./

  # Принимаем почту для постмастеров локальных доменов без
  # проверки отправителя (я закомментировал, т.к. это -
  # основной источник спама с мой ящик).

  accept  local_parts   = postmaster
          domains       = +local_domains

  # Запрещщаем, если невозможно проверить отправителя
  # (отсутствует в списке локальных пользователей)
  # У себя я это закоментил, по причине, что некоторые
  # железяки (принтеры, & etc) и программы (Касперский, DrWEB)
  # умеют слать почту, в случае проблем но не умеют ставить
  # нужного отправителя. Такие письма эта проверка не пускает.
#  require verify        = sender

  # Запрещщаем тех, кто не обменивается приветственными
  # сообщениями (HELO/EHLO)
  deny    message       = "You must send HELO/EHLO"
          condition     = ${if eq{$sender_helo_name}{}{yes}{no}}

  # Принимаем сообщения от тех, кто аутентифицировался:
  # Вообще, большинство конфигов в рунете - это один и тот же
  # конфиг написанный Ginger, в котором этот пункт расположен
  # внизу. Но при таком расположении рубятся клиенты с adsl,
  # ppp, и прочие зарезанные на последующих проверках. Но это
  # жа неправильно! Этом мои пользователи из дома! Потому
  # я это правило расположил до проверок.
  accept  authenticated = *

# Рубаем нах, тех, кто подставляет свой IP в HELO
  deny    message       = "Dont enter my ip in helo"
          hosts         =  *:!+relay_from_hosts
          condition     = ${if eq{$sender_helo_name}\
                          {$sender_host_address}{true}{false}}


# Рубаем тех, кто в HELO пихает мой IP (2500 за месяц!)
  deny    condition     = ${if eq{$sender_helo_name}\
                          {$interface_address}{yes}{no}}
          hosts         = !127.0.0.1 : !localhost : *
          message       = "Its my ip address. Go away"

# Рубаем тех, кто в HELO пихает только цифры
# (не бывает хостов ТОЛЬКО из цифр)
  deny    condition     = ${if match{$sender_helo_name}\
                          {\N^\d+$\N}{yes}{no}}
          hosts         = !127.0.0.1:!localhost:*
          message       = "hmm... I dont understand your helo"

  # Рубаем хосты типа *adsl*; *dialup*; *pool*;....
  # Нормальные люди с таких не пишут. Если будут
  # проблемы - уберёте проблемный пункт (у меня клиенты
  # имеют запись типа asdl-1233.zone.su - я ADSL убрал...)
  deny    message       = "I dont like your host"
          condition     = ${if match{$sender_host_name} \
                               {adsl|dialup|pool|peer|dhcp} \
                               {yes}{no}}


  # Задержка. (это такой метод борьбы со спамом,
  # основанный на принципе его рассылки) На этом рубается
  # почти весь спам. Единственно - метод неприменим на
  # реально загруженных MTA - т.к. в результате ему
  # приходится держать много открытых соединений.
  # но на офисе в сотню-две человек - шикарный метод.
  #
  # более сложный вариант, смотрите в статье по exim и
  # курьер имап. Т.к. там метод боле умный (просто правил
  # больше :), то можно и на более загруженные сервера ставить)
  warn
        # ставим дефолтовую задержку в 20 секунд
        set acl_m0 = 20s
  warn
        # ставим задержку в 0 секунд своим хостам и
        # дружественным сетям (соседняя контора :))
        hosts = +relay_from_hosts : 213.234.195.226/28
        set acl_m0 = 0s
  warn
        # пишем в логи задержку (если оно вам надо)
        logwrite = Delay $acl_m0 for $sender_host_name \
        [$sender_host_address] with HELO=$sender_helo_name. Mail \
        from $sender_address to $local_part@$domain.
        delay = $acl_m0







  # Проверка получателя в локальных доменах.
  # Если не проходит, то проверяется следующий ACL,
  # и если непрошёл и там - deny
  accept  domains       = +local_domains
          endpass
          message       = "I dont know this user"
          verify        = recipient

  # Проверяем получателя в релейных доменах
  # Опять-таки если не проходит -> следующий ACL,
  # и если непрошёл и там - deny
  accept  domains       = +relay_to_domains
          endpass
          message       = "I dont know route to this host"
          verify        = recipient

  # Разрешаем почту от доменов в списке relay_from_hosts
  accept  hosts         = +relay_from_hosts

  # Если неподошло ни одно правило - чувак явно ищет
  # открытый релей. Пшёл прочь. :)
  deny    message       = "Its not openrelay ))"


# Тут идут ACL проверяющие содержимое (тело) письма.
# Без них будут пропускаться все сообщения.

acl_check_data:

  accept



# чё делаем с почтой
begin routers

# Поиск маршрута к хосту в DNS. Если маршрут не найден в DNS -
# то это `унроутабле аддресс`. Не проверяются локальные
# домены, 0.0.0.0 и 127.0.0.0/8
dnslookup:
  driver = dnslookup
  domains = ! +local_domains
  transport = remote_smtp
  ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
  no_more

system_aliases:
    driver      = redirect
    allow_fail
    allow_defer
    data = ${lookup mysql{SELECT `goto` FROM `alias` WHERE \
           `address`='${quote_mysql:$local_part@$domain}' OR \
           `address`='${quote_mysql:@$domain}'}}

mysqluser:
  driver = accept
  condition = ${if eq{}{${lookup mysql{SELECT `maildir` FROM `mailbox` \
              WHERE `username`='${quote_mysql:$local_part@$domain}'}}}{no}{yes}}
  transport = cyrus_delivery

# начинаются транспорты - как доставляем почту
begin transports

# Доставка на удалённые хосты - по SMTP
remote_smtp:
    driver = smtp

# Транспорт для доставки почты локальным пользователям.
cyrus_delivery:
    driver = lmtp
    socket = /var/imap/socket/lmtp
    batch_max = 100
    user = _cyrus

address_file:
    driver = appendfile
    delivery_date_add
    envelope_to_add
    return_path_add

# Имя программы
address_pipe:
  driver = pipe
  return_output

# Транспорт для автоответов
address_reply:
  driver = autoreply



# Начинаются повторы недоставленных писем.
begin retry

# Этот кусок я не трогал. Думаю разработчики лучше знают,
# какие тут должны быть цифирьки. Если же вы это знаете
# лучше их - меняйте. Хотя... А какого, если Вы такой
# умный, читаете этот мануал? Может ну, их, цифирьки, а? :)
# Address or Domain  Error   Retries
# -----------------  -----   -------
*                    *       F,2h,15m; G,16h,1h,1.5; F,4d,6h


# преобразование адресов. У меня такого нету.
begin rewrite


# Секция авторизации при отправке писем. Ввиду того,
# что почтовых клиентов много, и все всё делают
# по-своему, то и механизмов авторизации три...
begin authenticators

# А вот по какому методу авторизуется оутглюк - я уже и
# не помню... Хотя в своё время долго ковырялся,
# пока настроил... Толь plain, толь login...
auth_plain:
  driver = plaintext
  public_name = PLAIN
  server_condition = ${lookup mysql{SELECT `username` FROM \
                     `mailbox` WHERE `username` = \
                     '${quote_mysql:$1}' AND `password` = \
                     '${quote_mysql:$2}'}{yes}{no}}
  server_prompts = :
  server_set_id = $2

# Вроде по этому оутглюк, а по предыдущему нетскейп.
auth_login:
  driver = plaintext
  public_name = LOGIN
  server_condition = ${lookup mysql{SELECT `username` FROM \
                     `mailbox` WHERE `username` = \
                     '${quote_mysql:$1}' AND `password` = \
                     '${quote_mysql:$2}'}{yes}{no}}
  server_prompts = Username:: : Password::
  server_set_id = $1

# А так авторизуется "Летучая Мышь" - TheBat!
auth_cram_md5:
  driver = cram_md5
  public_name = CRAM-MD5
  server_secret = ${lookup mysql{SELECT `password` FROM \
                        `mailbox` WHERE `username` \
                        = '${quote_mysql:$1}'}{$value}fail}
  server_set_id = $1

# Фсё. Конфиг кончился. Два дня убил.
# &copy; lissyara       2006-02-25, 01:19

Меняем sendmail на exim:

# cat > /etc/mailer.conf
sendmail        /usr/local/bin/exim
send-mail       /usr/local/bin/exim
mailq           /usr/local/bin/exim -bp
newaliases      /usr/local/bin/exim -bi
hoststat        /usr/local/bin/exim
purgestat       /usr/local/bin/exim
#

Добавляем в /etc/rc.local, для отключения sendmail'а:

# cat >> /etc/rc.conf.local
sendmail_flags="NO"
#

Добавляем exim в автозагрузку(/etc/rc.local):

if [ -x /usr/local/bin/exim ] ; then
   /usr/local/bin/exim -bd -q30m >/dev/null 2>&1
   echo -n ' exim'
fi

Вырубаем sendmail:

# kill `cat /var/run/sendmail.pid`

Врубить сейчас exim не получится — мы пока не поставили cyrus-imap:
1) У нас нет пользователя _cyrus
2) У нас нет доставщика почты(мы используем cyrus-imap для доставки почты в ящики)

Так что перейдем к настройке cyrus-imap.

Перед тем, как ставить cyrus-imap необходимо установить cyrus-sasl — он потребуется для аутентификации:

# pkg_add cyrus-sasl-2.1.22p1-mysql
cyrus-sasl-2.1.22p1-mysql: complete
#

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


/* ссылки нужно писать одной строкой. Тут просто не влезло. */
# cd /root
# ftp http://email.uoa.gr/download/cyrus/
cyrus-imapd-2.3.8/cyrus-imapd-2.3.8-autocreate-0.10-0.diff
Trying 195.134.100.120...
Requesting http://email.uoa.gr/download/cyrus/
cyrus-imapd-2.3.8/cyrus-imapd-2.3.8-autocreate-0.10-0.diff
100% |**************************************************| 84571       00:00
Successfully retrieved file.
# ftp http://email.uoa.gr/download/cyrus/
cyrus-imapd-2.3.8/cyrus-imapd-2.3.8-autosieve-0.6.0.diff
Trying 195.134.100.120...
Requesting http://email.uoa.gr/download/cyrus/
cyrus-imapd-2.3.8/cyrus-imapd-2.3.8-autosieve-0.6.0.diff
100% |**************************************************|  7906       00:00
Successfully retrieved file.
# ftp http://email.uoa.gr/download/cyrus/
cyrus-imapd-2.3.8/cyrus-imapd-2.3.8-rmquota+deletemailbox-0.2-1.diff
Trying 195.134.100.120...
Requesting http://email.uoa.gr/download/cyrus/
cyrus-imapd-2.3.8/cyrus-imapd-2.3.8-rmquota+deletemailbox-0.2-1.diff
100% |**************************************************| 19775       00:00
Successfully retrieved file.
#

Разархивируем cyrus-imap:

/* На данном шаге система установит все 
зависимости для cyrus-imapd... так что придется подождать... )) */
# make extract
===>  Checking files for cyrus-imapd-2.3.8
>> cyrus-imapd-2.3.8.tar.gz doesn't seem to exist on this system.
>> Fetch ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/cyrus-imapd-2.3.8.tar.gz.
100% |*******************************************|  2155 KB    00:27
>> Size matches for /usr/ports/distfiles/cyrus-imapd-2.3.8.tar.gz
>> (SHA256) cyrus-imapd-2.3.8.tar.gz: OK
===>  cyrus-imapd-2.3.8p0 depends on: cyrus-sasl-* - found
===>  cyrus-imapd-2.3.8p0 depends on: db-4.* - not found

... skipped ...

===>  Extracting for cyrus-imapd-2.3.8
#

Теперь патчим:

# cd w-cyrus-imapd-2.3.8/cyrus-imapd-2.3.8/
# patch -p1 < /root/cyrus-imapd-2.3.8-autocreate-0.10-0.diff
Hmm...  Looks like a unified diff to me...
The text leading up to this was:

... skipped ...

done
# patch -p1 < /root/cyrus-imapd-2.3.8-autosieve-0.6.0.diff
Hmm...  Looks like a unified diff to me...
The text leading up to this was:

... skipped ...

done
# patch -p1 < /root/cyrus-imapd-2.3.8-rmquota+deletemailbox-0.2-1.diff
Hmm...  Looks like a unified diff to me...
The text leading up to this was:

... skipped ...

done
#

Собираем пакет для cyrus-imapd и устанавливаем его:

# cd /usr/ports/mail/cyrus-imapd/
# make package
===>  Patching for cyrus-imapd-2.3.8
===>  Configuring for cyrus-imapd-2.3.8

... skipped ...

===>  Building package for cyrus-imapd-2.3.8p0
Create /usr/ports/packages/i386/all/cyrus-imapd-2.3.8p0.tgz
Link to /usr/ports/packages/i386/ftp/cyrus-imapd-2.3.8p0.tgz
Link to /usr/ports/packages/i386/cdrom/cyrus-imapd-2.3.8p0.tgz
`/usr/ports/mail/cyrus-imapd/w-cyrus-imapd-2.3.8/fake-i386/.fake_done' is up to date.
===>  Building package for cyrus-imapd-perl-2.3.8
Create /usr/ports/packages/i386/all/cyrus-imapd-perl-2.3.8.tgz
Link to /usr/ports/packages/i386/ftp/cyrus-imapd-perl-2.3.8.tgz
Link to /usr/ports/packages/i386/cdrom/cyrus-imapd-perl-2.3.8.tgz
# pkg_add /usr/ports/packages/i386/all/cyrus-imapd-2.3.8p0.tgz
cyrus-imapd-2.3.8p0: complete
--- cyrus-imapd-2.3.8p0 -------------------
Don't forget to edit /etc/services to include missing network services
if needed.
# pkg_add /usr/ports/packages/i386/all/cyrus-imapd-perl-2.3.8.tgz
cyrus-imapd-perl-2.3.8: complete
#

Установилось. ) Теперь составляем конфиг для imap'а:

# cat > /etc/imapd.conf
# Автоматом создавать квоту для пользователя.
# на самом деле нужно только для автоматического
# создания юзерских хомяков
autocreatequota: 10485760
# Создаем почтовые ящики при попытке отправить
# им письмо
createonpost: yes
# Директория с БД и тд.
configdirectory: /var/imap
# Настройки безопасности sasl
sasl_minimum_layer: 0
# Где храним почту
partition-default: /var/spool/imap
# Какие пользователи являются админами
admins: admin
# Директория со скриптами
sievedir: /var/imap/sieve
# sendmail прога
sendmail: /usr/sbin/sendmail
# как проверяем пасс
sasl_pwcheck_method: auxprop
# расположение сокетов
lmtpsocket: /var/imap/socket/lmtp
idlesocket: /var/imap/socket/idle
notifysocket: /var/imap/socket/notify
# сама проверка пароля...
# все параметры очевидны. )
sasl_auxprop_plugin: sql
sasl_sql_engine: mysql
sasl_sql_user: exim
sasl_sql_passwd: exim
sasl_sql_database: exim
sasl_sql_hostnames: 127.0.0.1
sasl_sql_select: SELECT password FROM mailbox WHERE username='%u@%r' AND active='1'
sasl_sql_verbose: yes
sasl_mech_list: PLAIN LOGIN
sasl_password_format: plaintext
# разрешаем не криптованные пароли
allowplaintext: yes
altnamespace: yes
# имя сервера
servername: local.ru
# используем виртуальные домены
virtdomains: userid
# домен по умолчанию
defaultdomain: local.ru
#

Теперь создаем необходимые файлы и папки для работы imap'а.

# /usr/local/share/examples/cyrus-imapd/tools/mkimap
reading configure file /etc/imapd.conf...
i will configure directory /var/imap.
i saw partition /var/spool/imap.
done
configuring /var/imap...
creating /var/spool/imap...
done
#

Добавим cyrus-imap в автозагрузку:

# cat >> /etc/rc.local
if [ -x /usr/local/libexec/cyrus-imapd/master ] ; then
   /usr/local/libexec/cyrus-imapd/master \
   -C /etc/imapd.conf -M /etc/cyrus.conf -d
   echo -n ' cyrus-imap'
fi

Отлично! ) Теперь можно запускать cyrus-imap и exim:

# /usr/local/libexec/cyrus-imapd/master \
> -C /etc/imapd.conf -M /etc/cyrus.conf -d
# ps ax | grep master
29110 ??  Is      0:00.02 /usr/local/libexec/cyrus-imapd/master 
-C /etc/imapd.conf -M /etc/cyrus.conf -d
27057 p0  I+      0:00.01 grep master
# /usr/local/bin/exim -bd -q30m
# ps ax | grep exim
27271 ??  Is      0:00.01 /usr/local/bin/exim -bd -q30m (exim-4.66)
#

Можно проверять!

Заходим в postfixadmin и создаем какой-нить домен. И создаем пользователя двух пользователей: admin@local.ru — будет администратором для cyrus-imapd, прошу обратить внимание, что этот админ не должен получать почту. Его необходимо использовать только для администрирования cyrus-imapd. И второго пользователя: test@local.ru и смотрим логи:

2008-04-03 02:51:49 1JhBo5-0007cT-Ci <= postmaster@local.ru H=(127.0.0.1) [127.0.0.1] I=[127.0.0.1]:25 P=esmtp S=298 from <postmaster@local.ru> for test@local.ru
2008-04-03 02:51:49 1JhBo5-0007cT-Ci => test <test@local.ru> R=mysqluser T=cyrus_delivery
2008-04-03 02:51:49 1JhBo5-0007cT-Ci Completed

Как видите — ящик test успешно был создан, а ящик админа не создался, потому что ему не надо. ))

Теперь можете настраивать свой любимый почтовый клиент(я юзаю thunderbird) на использование нашего сервера.

P.S. По скорости работы cyrus-imap рулит. )
P.S.2 В отличии от courier'а — можно папки создавать в корне, а не во "Входящие". Это радует.
P.S.3 Если Вам нужны логи от cyrus-imap'а, то в /etc/syslogd.conf пропишите следующее:

local6.debug    /var/log/imapd.log
auth.debug      /var/log/auth.log

И перезапустите syslog:

# kill -HUP `cat /var/run/syslog.pid`

P.S.4 В следующей статье попытаюсь рассказать про такие вкусности, как sieve. )



размещено: 2008-04-02,
последнее обновление: 2008-04-02,
автор: fr33man


sundevil, 2008-04-03 в 8:19:34

Полезняшка офигенная! В мемориз однозначно!

f0s, 2008-04-03 в 10:53:08

статья хороша..

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

fr33man, 2008-04-03 в 17:05:48

Хм... Надо настройки покопать. )

stooper, 2008-04-05 в 13:52:00

спасибо, fr33man =)))
почаще буду стучать тебе в аську теперь, хорошие статьи выходят! :) у меня все получилось, за иссключеним того, что патчи плохо ложатся на последний cyrus из портов, 2.3.11, на эту тему есть ветка обуждения в цирусовской конфе http://article.gmane.org/gmane.mail.imap.cyrus/29300
если кто то столкнется, то там есть решение.
я так же установил postfix-admin и импортировал его в базу мускула, и теперь cyrus и postfix авторизируют юзеров из этой базы, очень удобно админить, а на imap еще повесил сверху roundcube ;) так же, кому интересно - есть отличный ман, для freebsd
http://www.wistful.net/wiki/Ed's_FreeBSD_Virtual_Mail_How-To
давайте делать почту вместе)))

123, 2009-02-27 в 15:57:36

Товaрищщи! Это пoля для ввода комментариев к статье, а не для вопросов. Сюда пишите найденные баги, или какие-то фичи :)
Для вопросов есть форум!

itux, 2009-07-30 в 3:34:25

Заходим в Postfixadmin и создаем два пользователя. Как заходим ?

VaLoR, 2009-10-30 в 11:03:56

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

Serg, 2010-05-25 в 11:58:31

Автору респект и уважуха!!!
Хочу заметить некоторые баги которые не принесли гемора, но были вполне ожидаемыми:
1) проблема с созданием доменов и юзверей в postfixadmin, решается просто и вусно в файле
functions.inc.php
в сторке \"get_magic_quotes_gpc () == 0\" меняем 0 на 1!
у меня ругань была такая
\"mysql_real_escape_string() [<a href=\'function.mysql-real-escape-string\'>function.mysql-real-escape-string</a>]: A link to the server could not be established in /var/www/htdocs/mail/functions.inc.php on line 131\"
2) более ублюдского фейса как postfixadmin я еще не видил! если есть мысли чем его заменить прошу делиться!
3) у меня apache крутится в chroot, поэтому не забываем прописывать ln -s mysql.sock в /var/run/mysql/mysql.sock, или куда там у Вас экзим пишет)))
Самое главное это перевод конфига, труд капитальный!!! Респект за это отдельный!!! Сам юзал кумыл, думал самый лучший, теперь добавился экзим! постфикс и седмайл не воспринимаю органически, только для очень маленьких почтовиков с 10 юзерей с ручной правкой юзерей\\доменов. Постфикс, выросший из сендмайла напоминает ладу калину выросшей из десятки, вроде новая тачка а гемор так и остался)
А тем кто любит задавать глупые вопросы хочу посоветовать внимательно читать логи и тестить почту через телнет вручную смотря в логи через tail -f, там все написано, и все будет гутт!!!



 

  Этот информационный блок появился по той простой причине, что многие считают нормальным, брать чужую информацию не уведомляя автора (что не так страшно), и не оставляя линк на оригинал и автора — что более существенно. Я не против распространения информации — только за. Только условие простое — извольте подписывать автора, и оставлять линк на оригинальную страницу в виде прямой, активной, нескриптовой, незакрытой от индексирования, и не запрещенной для следования роботов ссылки.
  Если соизволите поставить автора в известность — то вообще почёт вам и уважение.

© lissyara 2006-10-24 08:47 MSK

Время генерации страницы 0.1045 секунд
Из них PHP: 56%; SQL: 44%; Число SQL-запросов: 70 шт.
У Вас отключено GZIP-сжатие в браузере. Размер страницы 118850