Почтовый сервер на базе Ubuntu 10.04 LTS
Этот документ описывает процедуру установки почтового сервера на базе Ubuntu 10.04 LTS. В документе использовано следующее форматирование:
строки с таким выделениемэто команды, которые мы задаем в терминале.
строки с таким выделением
это ответы, которые мы получаем на введенные нами команды
строки с таким выделениемэто содержимое различного рода конфигурационных файлов.
Будьте предельно внимательны при копировании команд!
Вся процедура создания почтового сервера проверена, однако, естественно,
в документе возможны ошибки и неточности. Если у Вас что-то не
получается, или получается не так, как следует/описано, то:
- еще раз проверьте, все ли Вы делаете правильно
- анализируйте соответствующие лог-файлы, расположенные в /var/log/
- ищите решение Ваших проблем в гугле
- консультируйтесь на форуме (старайтесь быть как можно более конкретным, и точно сообщите, в чем именно у Вас возникла проблема)
Постановка задачи
Мы установим на чистую машину на Ubuntu 10.04 LTS server почтовый сервер на базе postfix. Для «забора» почты по протоколам pop3/imap будем использовать dovecot с поддержкой квот для почтовых ящиков пользователей. На нашем сервере будет располагаться почта для двух разных доменов - aaa.ru (наш «основной» домен) и bbb.ru. Для настройки почты будем использовать mysql. Для аутентификации пользователей будем использовать два механизма - mysql для домена bbb.ru и openldap для пользователей нашего основного домена aaa.ru. Кроме этого, почтовый сервер будет проверять входящую почту с помощью amavis на вирусы (clamav) и спам (spamassassin). Сделаем также лист рассылки (mailman) и автоответчик для пользователей. Установим систему для доступа к почте через web — horde/imp. Мы будем использовать horde/imp,
т.к. это самый продвинутый веб-клиент, позволяющий полностью
использовать все современные возможности почты, включая подписывание
почты по протоколам S/MIME и прочие. Кроме этого, установим munin для рисования красивых графиков работы нашего почтового сервера.
Итак, предположим, что у нас есть только что установленная 10.04 LTS. Предположим также, что компьютер зовут «oban», он имеет IP адреc 10.0.0.6, находится в DMZ за NAT. Для доступа извне на наш почтовый сервер мы пробросим нужные порты по протоколу TCP – 80, 443 (для доступа к веб-серверу), 25 (для доступа к SMTP-серверу), 110, 143, 993, 995 (для “забора” почты снаружи по протоколам POP3 и IMAP). Если нужно, откроем еще порт 22 для доступа по SSH (хотя этого делать не стоит – лучше иметь доступ к серверу только изнутри нашей сети).
Пользователь, за которым мы «сидим» - это, конечно, не root, а toor (Вы же не сидите за рутом, правда?).
Итак, предположим, что у нас есть только что установленная 10.04 LTS. Предположим также, что компьютер зовут «oban», он имеет IP адреc 10.0.0.6, находится в DMZ за NAT. Для доступа извне на наш почтовый сервер мы пробросим нужные порты по протоколу TCP – 80, 443 (для доступа к веб-серверу), 25 (для доступа к SMTP-серверу), 110, 143, 993, 995 (для “забора” почты снаружи по протоколам POP3 и IMAP). Если нужно, откроем еще порт 22 для доступа по SSH (хотя этого делать не стоит – лучше иметь доступ к серверу только изнутри нашей сети).
Пользователь, за которым мы «сидим» - это, конечно, не root, а toor (Вы же не сидите за рутом, правда?).
Установка системы
Вначале установим «чистую» систему Ubuntu 10.04 LTS server. В процессе установки ничего дополнительно устанавливать не будем, все нужное установим позже.
Первое что мы сделаем после перезагрузки, еще не отходя от терминала - установим ssh-сервер, чтобы все остальное делать удаленно:
Итак, вначале установим все обновления (их наверняка набралось уже порядочно):
Естественно, соглашаемся с предложенным списком и (если были обновления ядра или подобные важные обновления) перезагружаемся
Установим нужные пакеты
Отвечаем на вопросы
Создадим базу данных mysql для хранения всей информации для почтового сервера
и выйдем из оболочки mysql
Первое что мы сделаем после перезагрузки, еще не отходя от терминала - установим ssh-сервер, чтобы все остальное делать удаленно:
sudo apt-get install openssh-serverПосле этого со спокойной совестью выходим и идем к нашему собственному компьютеру. Чтобы не набирать каждый раз пароль при входе на наш сервер, сделаем вход по ключу:
ssh-copy-id -i ~/.ssh/id_rsa.pub toor@10.0.0.6Нас спросят, уверены ли мы, что хотим соединиться с этим сервером
Are you sure you want to continue connecting (yes/no)?
Ответим
yes
Нас спросят пароль пользователя toor на oban
toor@10.0.0.6's password:
Введем. Все, теперь для захода на наш сервер с нашего компьютера достаточно набрать
ssh toor@10.0.0.6и мы там. Заметьте, что это не то же самое, что попытка входа как
ssh toor@obanтак что если хотите - проделайте это еще раз уже для такого варианта.
Итак, вначале установим все обновления (их наверняка набралось уже порядочно):
sudo apt-get update sudo apt-get dist-upgradeМы используем dist-upgrade а не просто upgrade чтобы получить обновления в том числе и для ядра.
Естественно, соглашаемся с предложенным списком и (если были обновления ядра или подобные важные обновления) перезагружаемся
sudo reboot
Начинаем установку.
Установим нужные пакеты
sudo apt-get install postfix postfix-mysql postfix-ldap postfix-doc postfix-tls libsasl2-2 libsasl2-modules libsasl2-modules-sql sasl2-bin libpam-mysql dovecot-imapd dovecot-pop3d dovecot-common mysql-client mysql-server apache2 libapache2-mod-php5 php5 php5-mysql(здесь и далее соглашаемся с установкой дополнительных пакетов).
Отвечаем на вопросы
Новый пароль для MySQL пользователя «root»:
Обязательно устанавливаем пароль для пользователя root в mysql (это - не пароль пользователя root на компьютере, не путайте!). Здесь и далее это -
<mysql_password>
Повторите ввод пароля для MySQL пользователя «root»:
<mysql_password>
Выберите тип настройки почтового сервера, который оптимально удовлетворяет ваши требования.
Здесь просто жмем <OK>
.
Общий тип почтовой настройки:
Выбираем
Internet - сайт
Системное почтовое имя:
oban.aaa.ruПосле окончания установки начнем конфигурацию.
Создадим базу данных mysql для хранения всей информации для почтового сервера
mysqladmin -u root -p create mailНас спросят пароль пользователя root mysql
Enter password:
Введем выбранный на этапе установки пароль
<mysql_password>Перейдем в оболочку mysql (опять вводя тот же пароль)
mysql -u root -pСоздадим специального пользователя mail_admin и паролем <mail_admin_password> (замените!) для доступа к нашей базе данных mail с привилегиями SELECT, INSERT, UPDATE и DELETE. Доступ ему будет разрешен только с локального компьютера (т.е. с самого сервера):
GRANT SELECT, INSERT, UPDATE, DELETE ON mail.* TO 'mail_admin'@'localhost' IDENTIFIED BY '<mail_admin_password>'; GRANT SELECT, INSERT, UPDATE, DELETE ON mail.* TO 'mail_admin'@'localhost.localdomain' IDENTIFIED BY '<mail_admin_password>'; FLUSH PRIVILEGES;Теперь создадим нужные нам таблицы в базе данных mail
use mail; CREATE TABLE domains ( domain varchar(50) NOT NULL, PRIMARY KEY (domain) ) TYPE=MyISAM; CREATE TABLE forwardings ( source varchar(80) NOT NULL, destination TEXT NOT NULL, PRIMARY KEY (source) ) TYPE=MyISAM; CREATE TABLE transport ( domain varchar(128) NOT NULL DEFAULT '', transport varchar(128) NOT NULL DEFAULT '', UNIQUE KEY domain (`domain`) ) ENGINE=MyISAM; CREATE TABLE users ( email varchar(80) NOT NULL, password varchar(20) NOT NULL, quota varchar(20) DEFAULT '0', PRIMARY KEY (email) ) TYPE=MyISAM;(здесь мы задаем квоту для пользователей по умолчанию без лимита - 0)
и выйдем из оболочки mysql
quit;
Настройка Postfix
Сейчас нам необходимо указать Postfix, где ему искать информацию в базе данных. Для этого создадим шесть текстовых файлов. Как вы можете заметить, я указываю Postfix соединяться с MySQL через IP адрес 127.0.0.1 вместо localhost. Это связано с тем, что Postfix запущенный в chroot окружении не сможет иметь доступа к MySQL сокету, если будет пытаться использовать localhost для подключения.
Проверим, что mysql «слушает» локальный IP адрес
Теперь создадим файлы для того, чтобы postfix знал, где что искать в нашей базе данных:
Проверим, что mysql «слушает» локальный IP адрес
cat /etc/mysql/my.cnf | grep bind
bind-address = 127.0.0.1
Если пришлось поменять /etc/mysql/my.cnf, то перезапустим mysql
sudo service mysql restart
и проверяем, что он действительно слушает этот адрес:
sudo netstat -tap | grep mysql
tcp 0 0 localhost:mysql *:* LISTEN 5908/mysqld
(здесь 5908- это номер процесса, у Вас будет другой).
Теперь создадим файлы для того, чтобы postfix знал, где что искать в нашей базе данных:
sudo nano /etc/postfix/mysql-virtual_domains.cf
user = mail_admin password = <mail_admin_password> dbname = mail query = SELECT domain AS virtual FROM domains WHERE domain='%s' hosts = 127.0.0.1
sudo nano /etc/postfix/mysql-virtual_forwardings.cf
user = mail_admin password = <mail_admin_password> dbname = mail query = SELECT destination FROM forwardings WHERE source='%s' hosts = 127.0.0.1
sudo nano /etc/postfix/mysql-virtual_mailboxes.cf
user = mail_admin password = <mail_admin_password> dbname = mail query = SELECT CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/') FROM users WHERE email='%s' hosts = 127.0.0.1
sudo nano /etc/postfix/mysql-virtual_email2email.cf
user = mail_admin password = <mail_admin_password> dbname = mail query = SELECT email FROM users WHERE email='%s' hosts = 127.0.0.1
sudo nano /etc/postfix/mysql-virtual_transports.cf
user = mail_admin password = <mail_admin_password> dbname = mail query = SELECT transport FROM transport WHERE domain='%s' hosts = 127.0.0.1Т.к. в этих файлах у нас лежит пароль для доступа к базе данных, меняем права доступа к ним (разрешаем чтение только группе postfix, в которую входит наш почтовый сервер postfix):
sudo chmod o= /etc/postfix/mysql-virtual_*.cf sudo chgrp postfix /etc/postfix/mysql-virtual_*.cfПроверяем права доступа к этим файлам:
ls -al /etc/postfix/mysql-virtual*.cf
-rw-r—– 1 root postfix 134 2010-11-26 11:24 /etc/postfix/mysql-virtual_domains.cf
-rw-r—– 1 root postfix 119 2010-11-26 11:25 /etc/postfix/mysql-virtual_email2email.cf
-rw-r—– 1 root postfix 132 2010-11-26 11:24 /etc/postfix/mysql-virtual_forwardings.cf
-rw-r—– 1 root postfix 188 2010-11-26 11:25 /etc/postfix/mysql-virtual_mailboxes.cf
-rw-r—– 1 root postfix 128 2010-11-26 11:25 /etc/postfix/mysql-virtual_transports.cf
Создаем нового пользователя и группу с названием vmail с домашней директорией /home/vmail , где будут находится почтовые ящики:
-rw-r—– 1 root postfix 119 2010-11-26 11:25 /etc/postfix/mysql-virtual_email2email.cf
-rw-r—– 1 root postfix 132 2010-11-26 11:24 /etc/postfix/mysql-virtual_forwardings.cf
-rw-r—– 1 root postfix 188 2010-11-26 11:25 /etc/postfix/mysql-virtual_mailboxes.cf
-rw-r—– 1 root postfix 128 2010-11-26 11:25 /etc/postfix/mysql-virtual_transports.cf
sudo groupadd -g 5000 vmail \\ sudo useradd -g vmail -u 5000 vmail -d /home/vmail -mПредварительная настройка postfix (нам еще придется ее менять чуть позже). Не забудьте поменять oban.aaa.ru на Ваше реальное полное имя сервера, а то postfix не будет работать!
sudo postconf -e 'myhostname = oban.aaa.ru' sudo postconf -e 'mydestination = oban.aaa.ru, localhost, localhost.localdomain' sudo postconf -e 'mynetworks = 127.0.0.0/8' sudo postconf -e 'virtual_alias_domains =' sudo postconf -e 'virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual_forwardings.cf, mysql:/etc/postfix/mysql-virtual_email2email.cf' sudo postconf -e 'virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual_domains.cf' sudo postconf -e 'virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailboxes.cf' sudo postconf -e 'virtual_mailbox_base = /home/vmail' sudo postconf -e 'virtual_uid_maps = static:5000' sudo postconf -e 'virtual_gid_maps = static:5000' sudo postconf -e 'smtpd_sasl_auth_enable = yes' sudo postconf -e 'broken_sasl_auth_clients = yes' sudo postconf -e 'smtpd_sasl_authenticated_header = yes' sudo postconf -e 'smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination' sudo postconf -e 'smtpd_use_tls = yes' sudo postconf -e 'smtpd_tls_cert_file = /etc/postfix/smtp.crt' sudo postconf -e 'smtpd_tls_key_file = /etc/postfix/smtp.key' sudo postconf -e 'transport_maps = proxy:mysql:/etc/postfix/mysql-virtual_transports.cf' sudo postconf -e 'proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks'
Создание SSL-сертификатов
Теперь создадим SSL
сертификаты для TLS. Лучше всего (хотя и не обязательно) создать вначале
свой CA (Certificate Authority), а потом подписать от его имени все
сертификаты (нам еще понадобятся сертификаты для dovecot). В этом случае клиентам нужно будет добавить доверие к этому CA, а не каждому сертификату отдельно.
Создаем CA.
Создадим папку, в которой будем генерить все сертификаты
C = RU (страна)
ST = Moscow Region (регион)
L = Moscow (город)
O = AAA Ltd. (название компании)
CN = aaa.ru (имя сервера, для которого выдается ключ; в случае CA - имя домена)
emailAddress = admin@aaa.ru (почтовый адрес администратора)
(закоментаренные строки нужны только, если Вы действительно хотите иметь более-менее нормальный CA с листами отзыва ключей и т.п., но это выходит за рамки этого how-to)
Создаем частный ключ ключ CA
Создаем открытый ключ CA. Мы говорим, что ключи нашего CA имеют «срок жизни» 10 лет (-days 3650).
Создаем сертификат для подписывания:
openssl x509 -trustout -inform PEM -in ca.crt -outform DER -out ca.pfx
Создадим директорию, в которой у нас будут лежать все ключи для всех серверов (если мы в дальнейшем будем создавать и подписывать ключи для других серверов; например, захотим, чтобы ключи были разные для smtp.aaa.ru pop3.aaa.ru и imap.aaa.ru) и, соответственно, директории для всех имен серверов (в нашем случае — oban.aaa.ru)
Убираем из ключа парольную фразу:
Сделаем конфигурационный файл для подписи (срок действия подписи 5 лет - 1828 дней):
Проверим подпись (на всякий случай):
Нашим клиентам, которые будут связываться с нашим сервером с использованием шифрования (TLS, SSL) или с нашим веб-сервером по протоколу HTTPS нужно установить доверие к нашему CA. Тем или иным способом передайте им открытый ключ нашего CA - ca.crt.
Создаем CA.
Создадим папку, в которой будем генерить все сертификаты
mkdir ~/CA_cleanНам нужно вначале подготовить конфигурационный файл для создания CA
nano ca.conf
[req] distinguished_name =req_distinguished_name x509_extensions = v3_ca prompt = no [req_distinguished_name] C= RU ST = Moscow Region L = Moscow O = AAA Ltd. OU = ROOTCA CN = aaa.ru emailAddress = admin@aaa.ru [v3_ca] basicConstraints = CA:true nsComment = "CA certificate of AAA Ltd." nsCertType = sslCA, emailCA subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer:always [ usr_cert ] nsComment = "Certificate issued by AAA Ltd." ;nsBaseUrl = http://ca.aaa.ru/ ;nsRevocationUrl = http://ca.aaa.ru/crl.crl ;issuerAltName = URI:http://ca.aaa.ru/ca.crt ;crlDistributionPoints = URI:http://ca.aaa.ru/crl.crlЗдесь и далее (замените на нужное Вам):
C = RU (страна)
ST = Moscow Region (регион)
L = Moscow (город)
O = AAA Ltd. (название компании)
CN = aaa.ru (имя сервера, для которого выдается ключ; в случае CA - имя домена)
emailAddress = admin@aaa.ru (почтовый адрес администратора)
(закоментаренные строки нужны только, если Вы действительно хотите иметь более-менее нормальный CA с листами отзыва ключей и т.п., но это выходит за рамки этого how-to)
Создаем частный ключ ключ CA
sudo openssl genrsa -des3 -out ca.key 4096
Enter pass phrase for ca.key:
Введите пароль для файла ca.key (два раза для подтверждения) и не забывайте его!
Verifying - Enter pass phrase for ca.key:
Он будет нужен для подписывания всех ключей (здесь используем sudo т.к. при этом переписывается состояние random_state компьютера)
Создаем открытый ключ CA. Мы говорим, что ключи нашего CA имеют «срок жизни» 10 лет (-days 3650).
openssl req -new -x509 -nodes -sha1 -days 3650 -key ca.key -out ca.crt -config ca.conf
Enter pass phrase for ca.key:
(вводим выбранный нами на предыдущем шаге пароль закрытого ключа CA)
Создаем сертификат для подписывания:
openssl pkcs12 -export -in ca.cer -inkey ca.key -out ca.pfx
Создадим директорию, в которой у нас будут лежать все ключи для всех серверов (если мы в дальнейшем будем создавать и подписывать ключи для других серверов; например, захотим, чтобы ключи были разные для smtp.aaa.ru pop3.aaa.ru и imap.aaa.ru) и, соответственно, директории для всех имен серверов (в нашем случае — oban.aaa.ru)
mkdir SERVERS mkdir SERVERS/oban.aaa.ruСоздаем файлы конфигураций для ключей серверов (в каждой директории - свой файл, т.к. в нем записано имя сервера). В случае одного имени (замените на нужные Вам значения):
nano SERVERS/oban.aaa.ru/openssl.conf
[ req ] default_bits = 2048 distinguished_name = req_distinguished_name prompt = no req_extensions = v3_req [ req_distinguished_name ] C = RU ST = Moscow Region L = Moscow O = AAA Ltd. CN = oban.aaa.ru emailAddress = admin@aaa.ru [ v3_req ] basicConstraints = CA:FALSE subjectKeyIdentifier = hashТеперь сгенерим ключи для нашего сервера (заметьте, что мы опять используем здесь sudo):
sudo openssl genrsa -passout pass:1234 -des3 -out SERVERS/oban.aaa.ru/server.key.1 2048Здесь 1234 — парольная фраза для промежуточного ключа. Она нам нужна только временно, т.к. мы в результате хотим получить ключ без пароля (требование postfix).
Убираем из ключа парольную фразу:
openssl rsa -passin pass:1234 -in SERVERS/oban.aaa.ru/server.key.1 -out SERVERS/oban.aaa.ru/server.keyГенерим запрос на подпись нашего ключа
openssl req -config SERVERS/oban.aaa.ru/openssl.conf -new -key SERVERS/oban.aaa.ru/server.key -out SERVERS/oban.aaa.ru/server.csrи удаляем промежуточный ключ
rm -f SERVERS/oban.aaa.ru/server.key.1Теперь нам нужно подписать наш созданный ключ от имени своего CA
Сделаем конфигурационный файл для подписи (срок действия подписи 5 лет - 1828 дней):
nano sign.config
[ ca ] default_ca = CA_own [ CA_own ] certs = . new_certs_dir = ca.db.certs database = ca.db.index serial = ca.db.serial RANDFILE = ca.db.rand certificate = ca.crt private_key = ca.key default_days = 1825 default_crl_days = 1 default_md = sha1 preserve = no policy = policy_anything x509_extensions = usr_cert [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [usr_cert] basicConstraints = CA:false subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer:alwaysи создадим директорию для хранения сертификатов подписей:
mkdir ca.db.certs
Для первого подписанного ключа создаем его номер и формируем индексный файл (для остальных - не нужно!)
echo '01' > ca.db.serial cp /dev/null ca.db.indexи подписываем (обратите внимание, что мы опять используем sudo)
sudo openssl ca -batch -config sign.config -out SERVERS/oban.aaa.ru/server.crt -infiles SERVERS/oban.aaa.ru/server.csr
Enter pass phrase for ca.key:
(введем пароль закрытого ключа CA)
Проверим подпись (на всякий случай):
openssl verify -CAfile ca.crt SERVERS/oban.aaa.ru/server.crtМы должны получить
SERVERS/oban.aaa.ru/server.crt: OK
Номер ключа и индексный файл автоматически обновились, удалим старые файлы
rm -f ca.db.serial.old rm -rf ca.db.index.oldСкопируем ключи в директорию /etc/ssl
sudo cp SERVERS/oban.aaa.ru/server.key /etc/ssl/private/oban.key sudo cp SERVERS/oban.aaa.ru/server.crt /etc/ssl/certs/oban.crtи сменим права доступа к закрытому ключу
sudo chmod og= /etc/ssl/private/oban.keyТеперь установим доверие к новому CA. Для этого создадим папку для него
sudo mkdir /usr/share/ca-certificates/aaaи скопируем туда наш сертификат CA
sudo cp ca.crt /usr/share/ca-certificates/aaa/После этого переконфигурируем наши корневые сертификаты
sudo dpkg-reconfigure ca-certificates
(ответим, что мы хотим доверять новым сертификатам и выберем в списке наш новый сертификат для активации)
Нашим клиентам, которые будут связываться с нашим сервером с использованием шифрования (TLS, SSL) или с нашим веб-сервером по протоколу HTTPS нужно установить доверие к нашему CA. Тем или иным способом передайте им открытый ключ нашего CA - ca.crt.
Внимание! Никогда никому не передавайте созданные приватные ключи *.key и не делайте их доступными!
Настройка saslauthd
Авторизация почтовых пользователей на нашем сервере будет происходить через pam, к которому будет обращаться демон авторизации sasl.
Сначала выполним следующую команду:
Создадим файл /etc/pam.d/smtp
Для проверки авторизации нам нужно сгенерить строку, которую нужно передать при авторизации (обратите внимание на обратные слеши перед @ и 0):
Теперь сделаем аутентификацию по openldap. Установим нужные пакеты:
Создаем файл /etc/postfix/ldap-mailboxes.cf
Перезапускаем postfix
Сначала выполним следующую команду:
sudo mkdir -p /var/spool/postfix/var/run/saslauthdЗатем отредактируем файл /etc/default/saslauthd
sudo nano /etc/default/saslauthdУстановим параметр
START
в yes
и заменим строку OPTIONS=»-c -m /var/run/saslauthd»
на OPTIONS=»-c -m /var/spool/postfix/var/run/saslauthd -r»
Создадим файл /etc/pam.d/smtp
sudo nano /etc/pam.d/smtp
auth sufficient pam_mysql.so user=mail_admin passwd=<mail_admin_password> host=127.0.0.1 db=mail table=users usercolumn=email passwdcolumn=password crypt=1 account sufficient pam_mysql.so user=mail_admin passwd=<mail_admin_password> host=127.0.0.1 db=mail table=users usercolumn=email passwdcolumn=password crypt=1и сменим его права доступа
sudo chmod o= /etc/pam.d/smtpСоздаем файл /etc/postfix/sasl/smtpd.conf
sudo nano /etc/postfix/sasl/smtpd.conf
pwcheck_method: saslauthd mech_list: plain login allow_plaintext: trueи меняем ему владельца и права доступа
sudo chown postfix /etc/postfix/sasl/smtpd.conf sudo chmod og= /etc/postfix/sasl/smtpd.confДобавляем пользователя postfix в группу sasl (это даст Postfix права доступа к saslauthd):
sudo adduser postfix sasl
Перезапускаем Postfix и Saslauthd:
sudo /etc/init.d/postfix restart sudo /etc/init.d/saslauthd restartДля проверки авторизации создадим пользователя admin@bbb.ru в базе данных (заодно вначале в таблице domains зададим оба наших почтовых домена — aaa.ru и bbb.ru):
mysql -u root -p
Enter password:
Введем пароль mysql
<mysql_password>
USE mail; INSERT INTO `domains` (`domain`) VALUES ('aaa.ru'); INSERT INTO `domains` (`domain`) VALUES ('bbb.ru'); INSERT INTO `users` (`email`, `password`, `quota`) VALUES ('admin@bbb.ru', ENCRYPT('secret'), '10M'); quit;(здесь secret - это пароль нашего пользователя, выберите более подходящий; квоту пользователю мы задаем в размере 10Мбайт)
Для проверки авторизации нам нужно сгенерить строку, которую нужно передать при авторизации (обратите внимание на обратные слеши перед @ и 0):
perl -MMIME::Base64 -e 'print encode_base64("admin\@bbb.ru\0admin\@bbb.ru\0secret");'
YWRtaW5AYmJiLnJ1AGFkbWluQGJiYi5ydQBzZWNyZXQ=
Теперь проверим авторизацию
telnet 127.0.0.1 25
Trying 127.0.0.1…
Connected to 127.0.0.1.
Escape character is '^]'.
220 oban.aaa.ru ESMTP Postfix (Ubuntu)
Connected to 127.0.0.1.
Escape character is '^]'.
220 oban.aaa.ru ESMTP Postfix (Ubuntu)
EHLO testing
250-oban.aaa.ru
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH PLAIN YWRtaW5AYmJiLnJ1AGFkbWluQGJiYi5ydQBzZWNyZXQ=
(здесь вставляем полученную ранее строку авторизации)
235 2.7.0 Authentication successful
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
Если мы получим ответ, отличный от «Authentication successful», то мы где-то ошиблись. Проверить, в чем именно, можно, посмотрев файлы /var/log/auth.log и /var/log/mail.log
Connection closed by foreign host.
Теперь сделаем аутентификацию по openldap. Установим нужные пакеты:
sudo apt-get install libpam-ldapи ответим на вопросы:
LDAP server Uniform Resource Identifier:
ldap://10.0.0.3/
Обратите внимание — не ldapi!
Distinguished name of the search base:
dc=aaa,dc=ru
LDAP version to use:
3
Make local root Database admin:
Да
Does the LDAP database require login?
Нет
LDAP account for root:
cn=admin,dc=aaa,dc=ru
LDAP root account password:
<ldap_root_password>(конечно, нужное замените на свои параметры). Здесь мы предполагаем, что:
- ldap-сервер доступен по IP 10.0.0.3
- корень расположен в dc=aaa,dc=ru
- администратор ldap-сервера это cn=admin,dc=aaa,dc=ru
- он имеет пароль <ldap_root_password>
sudo nano /etc/ldap.confи добавляем в него одну строку после закомментаренной #bind_policy hard
bind_policy softРедактируем файл
sudo nano /etc/pam.d/smtpи добавляем в него строки
auth sufficient pam_ldap.so account sufficient pam_ldap.soТеперь можем проверить аутентификацию ldap-пользователя (предполагаем, что в ldap есть пользователь admin с паролем secret (у которого, кстати, почтовый адрес admin@aaa.ru, но это сейчас неважно; важно понимать, что это — другой пользователь, а не admin@bbb.ru):
perl -MMIME::Base64 -e 'print encode_base64("admin\0admin\0secret");'
YWRtaW4AYWRtaW4Ac2VjcmV0
telnet 127.0.0.1 25
Trying 127.0.0.1…
Connected to 127.0.0.1.
Escape character is '^]'.
220 oban.aaa.ru ESMTP Postfix (Ubuntu)
Connected to 127.0.0.1.
Escape character is '^]'.
220 oban.aaa.ru ESMTP Postfix (Ubuntu)
EHLO testing
250-oban.aaa.ru
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH PLAIN YWRtaW4AYWRtaW4Ac2VjcmV0
235 2.7.0 Authentication successful
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
Для почтовых ящиков локальных пользователей будем использовать LDAP.
Заметьте, что мы конфигурируем их как виртуальных пользователей, т.е.
локальный домен (aaa.ru) мы занесли в базу данных. Предположим, что
локальные пользователи в LDAP расположены в ou=Users,dc=aaa,dc=ru причем их имена записаны в uid а почтовые адреса - в mail.
Connection closed by foreign host.
Создаем файл /etc/postfix/ldap-mailboxes.cf
sudo nano /etc/postfix/ldap-mailboxes.cf
server_host = 10.0.0.3 server_port = 389 version = 3 bind = yes bind_dn = cn=admin,dc=aaa,dc=ru bind_pw = <ldap_root_password> search_base = ou=Users,dc=aaa,dc=ru query_filter = (mail=%s) result_attribute = mail result_filter = %d/%u/Меняем права доступа
sudo chgrp postfix /etc/postfix/ldap-mailboxes.cf sudo chmod o= /etc/postfix/ldap-mailboxes.cfи меняем строку
virtual_mailbox_maps = …
в файле /etc/postfix/main.cf
sudo nano /etc/postfix/main.cf
virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailboxes.cf ldap:/etc/postfix/ldap-mailboxes.cfДля проверки в том же файле временно меняем строку
#smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination smtpd_recipient_restrictions = permit_sasl_authenticated, reject_unauth_destination(это запрещает доставку писем с локального IP-адреса не в наши виртуальные домены)
Перезапускаем postfix
sudo /etc/init.d/postfix restartи проверяем работу обоих наших тестовых адресов - test@bbb.ru (который записан в базе данных) и betatest@aaa.ru (который записан в LDAP у пользователя betatest)
telnet 127.0.0.1 25
Trying 127.0.0.1…
Connected to 127.0.0.1.
Escape character is '^]'.
220 oban.aaa.ru ESMTP Postfix (Ubuntu)
Connected to 127.0.0.1.
Escape character is '^]'.
220 oban.aaa.ru ESMTP Postfix (Ubuntu)
HELO test
250 oban.aaa.ru
MAIL FROM: aaa@aa.aa
250 2.1.0 Ok
RCPT TO: admin@bbb.ru
250 2.1.5 Ok
RCPT TO: admin@aaa.ru
250 2.1.5 Ok
(если мы попробуем передать на несуществующий адрес, мы получим:)
RCPT TO: aaa@bbb.ru
550 5.1.1 <aaa@bbb.ru>: Recipient address rejected: User unknown in virtual mailbox table
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
Вернем обратно строку в файле /etc/postfix/main.cf:
Connection closed by foreign host.
sudo nano /etc/postfix/main.cf
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destinationДля запрета аутентификации в postfix с передачей данных открытым текстом, вставляем в файл /etc/postfix/main.cf
sudo nano /etc/postfix/main.cf
smtpd_tls_auth_only = yes smtpd_tls_cert_file = /etc/ssl/certs/oban.crt smtpd_tls_key_file = /etc/ssl/private/oban.key smtpd_use_tls = yesи перезапускаем postfix
sudo /etc/init.d/postfix restartОткроем и изменим /etc/aliases
sudo nano /etc/aliasesСделайте так, чтобы postmaster указывал на root, а root указывал на ваше имя пользователя или ваш почтовый адрес, у вас должно получится примерно так:
postmaster: root clamav: root root: admin@aaa.ruПосле изменения /etc/aliases вы должны запустить команду
sudo newaliases
Настройка dovecot
Скопируем файл
Отредактируем файл /etc/dovecot/dovecot-ldap.conf
Отредактируем файл /etc/dovecot/dovecot-sql.conf
и сделаем его выполняемым
Сменим права файлам, в которых записана информация о доступе к mysql и ldap
sudo cp /etc/pam.d/smtp /etc/pam.d/dovecot(мы будем для dovecot использовать тоже аутентификацию через pam)
Отредактируем файл /etc/dovecot/dovecot-ldap.conf
sudo nano /etc/dovecot/dovecot-ldap.conf
uris = ldap://10.0.0.3/ dn = cn=admin,dc=aaa,dc=ru dnpass = <ldap_root_password> ldap_version = 3 base = ou=Users,dc=aaa,dc=ru deref = searching scope = subtree user_attrs = mail=mail=maildir:/home/vmail/aaa.ru/%n/ user_filter = (&(uid=%n))Мы не будем задавать квоту для локальных пользователей, чтобы у них была неограниченная квота (напомним, что мы задали по умолчанию квоту без лимита).
Отредактируем файл /etc/dovecot/dovecot-sql.conf
sudo nano /etc/dovecot/dovecot-sql.conf
driver = mysql connect = host=127.0.0.1 user=mail_admin password=<mail_admin_password> dbname=mail user_query = SELECT email, CONCAT('/home/vmail/',CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1))) AS home, concat('*:storage=', quota) as quota_rule FROM users WHERE email='%u'Отредактируем файл /etc/dovecot/dovecot.conf, изменив следующие параметры:
sudo nano /etc/dovecot/dovecot.conf
disable_plaintext_auth = yes ssl = yes ssl_cert_file = /etc/ssl/certs/oban.crt ssl_key_file = /etc/ssl/private/oban.key mail_location = maildir:/home/vmail/%d/%n mail_uid = vmail mail_gid = vmail maildir_copy_with_hardlinks = yesВ блоке
auth default {
должно быть выбрано
mechanisms = plainи раскомментарено
passdb pam { … }закомментарим
# userdb passwd { … # }и раскомментарим
# SQL database </usr/share/doc/dovecot-common/wiki/AuthDatabase.SQL.txt> userdb sql { # Path for SQL configuration file args = /etc/dovecot/dovecot-sql.conf } # LDAP database </usr/share/doc/dovecot-common/wiki/AuthDatabase.LDAP.txt> userdb ldap { # Path for LDAP configuration file args = /etc/dovecot/dovecot-ldap.conf }В блоке
protocol imap {
добавляем строку
mail_plugins = quota imap_quotaВ блоке
protocol pop3 {
добавляем строку
mail_plugins = quotaВ блоке
plugin {
добавляем строки
quota = maildir:Quota quota_rule = *:storage=0 quota_rule2 = Trash:ignore quota_warning = storage=95%% /usr/local/bin/quota-warning.sh 95 quota_warning2 = storage=80%% /usr/local/bin/quota-warning.sh 80Создадим скрипт, который будет посылать пользователям напоминания при превышении ими квоты
sudo nano /usr/local/bin/quota-warning.sh
#!/bin/sh PERCENT=$1 FROM="admin@aaa.ru" qwf="/tmp/quota.warning.$$" echo "From: $FROM To: $USER To: admin@aaa.ru Subject: Your email quota is $PERCENT% full Content-Type: text/plain; charset="UTF-8" Your mailbox is now $PERCENT% full." >> $qwf cat $qwf | /usr/sbin/sendmail -f $FROM "$USER" rm -f $qwf exit 0(здесь мы посылаем сообщение от имени admin@aaa.ru, причем копию сообщения направляем на admin@aaa.ru)
и сделаем его выполняемым
sudo chmod a+x /usr/local/bin/quota-warning.shНе ждите от dovecot немедленной реакции на достижение квоты пороговых значений: dovecot пересчитывает квоту периодически.
Сменим права файлам, в которых записана информация о доступе к mysql и ldap
sudo chown root.root /etc/dovecot/dovecot-ldap.conf sudo chown root.root /etc/dovecot/dovecot-sql.conf sudo chmod og= /etc/dovecot/dovecot-ldap.conf sudo chmod og= /etc/dovecot/dovecot-sql.confПерезапустим dovecot
sudo /etc/init.d/dovecot restartи проверим аутентификацию dovecot для обоих наших пользователей:
telnet 127.0.0.1 110
Trying 127.0.0.1…
Connected to 127.0.0.1.
Escape character is '^]'.
+OK Dovecot ready.
Connected to 127.0.0.1.
Escape character is '^]'.
+OK Dovecot ready.
user admin@bbb.ru
+OK
pass secret(здесь, конечно, вводим пароль пользователя admin@bbb.ru)
+OK Logged in.
quit
+OK Logging out.
Connection closed by foreign host.
и
Connection closed by foreign host.
telnet 127.0.0.1 110
Trying 127.0.0.1…
Connected to 127.0.0.1.
Escape character is '^]'.
+OK Dovecot ready.
Connected to 127.0.0.1.
Escape character is '^]'.
+OK Dovecot ready.
user admin
+OK
pass secret(здесь, конечно, вводим пароль пользователя admin)
+OK Logged in.
quit
+OK Logging out.
Connection closed by foreign host.
После этой проверки, кстати, автоматически создадутся папки для хранения почты:
Connection closed by foreign host.
sudo ls -R /home/vmail/
/home/vmail:
aaa.ru bbb.ru
/home/vmail/aaa.ru:
admin
/home/vmail/aaa.ru/admin:
cur dovecot.index.log dovecot-uidlist dovecot-uidvalidity dovecot-uidvalidity.4cf4e5c7 new tmp
/home/vmail/aaa.ru/admin/cur:
/home/vmail/aaa.ru/admin/new:
/home/vmail/aaa.ru/admin/tmp:
/home/vmail/bbb.ru:
admin
/home/vmail/bbb.ru/admin:
cur dovecot.index.log dovecot-uidlist dovecot-uidvalidity dovecot-uidvalidity.4cf4e5ba new tmp
/home/vmail/bbb.ru/admin/cur:
/home/vmail/bbb.ru/admin/new:
/home/vmail/bbb.ru/admin/tmp:
aaa.ru bbb.ru
/home/vmail/aaa.ru:
admin
/home/vmail/aaa.ru/admin:
cur dovecot.index.log dovecot-uidlist dovecot-uidvalidity dovecot-uidvalidity.4cf4e5c7 new tmp
/home/vmail/aaa.ru/admin/cur:
/home/vmail/aaa.ru/admin/new:
/home/vmail/aaa.ru/admin/tmp:
/home/vmail/bbb.ru:
admin
/home/vmail/bbb.ru/admin:
cur dovecot.index.log dovecot-uidlist dovecot-uidvalidity dovecot-uidvalidity.4cf4e5ba new tmp
/home/vmail/bbb.ru/admin/cur:
/home/vmail/bbb.ru/admin/new:
/home/vmail/bbb.ru/admin/tmp:
Установка horde
Установим нужные пакеты
Исполняем скрипт с параметрами администратора mysql
В первый раз нас пустят с администраторскими привилегиями. Настроим систему аутентификации. Вначале войдем в Управление - Приложения - Портал (horde) и выберем закладку Authentication.
Зададим список пользователей-администраторов, перечислив двух наших пользователей —
Затем выберем способ аутентификации - через IMAP (выберем
В поле «Configuration type» выберем
В поле «The hostname or IP address of the server» оставим
В поле «The server port to which we will connect. IMAP is generally 143, while IMAP-SSL is generally 993.» выберем
В поле «The connection protocol» выберем
Переходим во вкладку Database и конфигурируем доступ к созданной ранее базе данных.
В поле «What database backend should we use?» выбираем
В поле «Username to connect to the database as» вводим
В поле «Password to connect with» вводим пароль, который мы вводили в скрипте создания базы данных-
В поле «How should we connect to the database?» выбираем
В поле «Database server/host» вводим
В поле «Port the DB is running on, if non-standard» оставляем
В поле «Database name to use» вводим
В поле «Internally used charset» оставляем
Переходим в закладку Mailer и настраиваем доступ к SMTP-серверу:
В поле «What method should we use for sending mail?» выбираем
В поле «SMTP authentication» выбираем
Переходим в закладку Preference System и выбираем
Переходим в закладку Datatree System и выбираем
Переходим в закладку Cache System и выбираем
Переходим в закладку Virtual File Storage и выбираем
Переходим в закладку Custom Session Handler и настраиваем доступ к созданной ранее базе данных:
В поле «What sessionhandler driver should we use?» выбираем
В поле «What protocol will we use to connect to the database?» выбираем
В поле «What password do we authenticate to the database server with?» вводим пароль, который мы вводили в скрипте создания базы данных -
Остальные поля оставляем по умолчанию.
Теперь нажмем кнопку Generate Портал Configuration. Получим сообщение «Невозможно сохранить резервную копию конфигурации в файл /usr/share/horde3/config/conf.bak.php.
Невозможно сохранить файл конфигурации /usr/share/horde3/config/conf.php. Вы можете использовать опции для сохранения кода обратно в Приложения или скопировать вручную код, приведенный ниже в /usr/share/horde3/config/conf.php.»
Это нормально, т.к. мы не хотим, чтобы возможно было менять конфигурацию через веб. Скопируем показанный внизу на странице сгенеренный код и запишем его в файл /etc/horde/horde3/conf.php (важно скопировать ВЕСЬ текст, заменив ВЕСЬ текст, имеющийся в файле).
Закроем окно броузера.
Отредактируем файл /etc/horde/imp4/servers.php
Войдем заново на https://oban.aaa.ru уже под одним из введенных нами пользователей с правами администратора.
Зайдем в Управление - Приложения - Почта (imp) и выберем закладку Server.
В поле «Should we display a list of servers (defined in config/servers.php) for users to choose from? The options are 'shown', 'hidden', and 'none'. If the server list is hidden then you can use the 'preferred' mechanism to auto-select from it based on an HTTP virtualhost or another piece of data. If it is shown, the user will be able to pick from any of the options. If none, no server list will be shown and the defaults will be used unless another mechanism changes them.» выберем
Нажмем кнопку Generate Почта Configuration, скопируем сгенеренный текст конфигурации и запишем в файл /etc/horde/imp4/conf.php
Отредактируем файл /etc/horde/passwd3/backends.php
'minLength' — минимальная длина паролей
'maxLength' — максимальная длина паролей
'minUpper' — минимальное количество заглавных букв в паролях
'minLower' — минимальное количество прописных букв в паролях
'minNumeric' — минимальное количество цифровых символов в паролях
'minSymbols' — минимальное количество прочих символов букв в паролях)
Зайдем в Управление - Приложения - Пароль (passwd) и в поле «Should we display a list of backends (defined in config/backends.php) for users to choose from? The options are 'shown', 'hidden'. If the backend list is hidden then you can use the 'preferred' mechanism to auto-select from it based on an HTTP virtualhost or another piece of data. If it is shown, the user will be able to pick from any of the options.» выберем
Нажмем кнопку Generate Пароль Configuration, скопируем сгенеренный текст конфигурации и запишем в файл /etc/horde/passwd3/conf.php
Отредактируем файл /etc/horde/horde3/registry.php
Для настройки адресной книги выполним
Основное мы уже установили и настроили. Теперь установим ряд дополнений.
sudo apt-get install horde3 imp4 turba2 sork-passwd-h3Разрешим доступ к нашей web-почте только через ssl. Для этого вначале отредактируем файл /etc/apache2/sites-available/default-ssl
sudo nano /etc/apache2/sites-available/default-sslЗаменяем
DocumentRoot /var/www <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /var/www/> Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory> ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ <Directory "/usr/lib/cgi-bin"> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all </Directory>на
DocumentRoot /usr/share/horde3 <Directory /> Options FollowSymLinks AllowOverride Limit </Directory> <Directory /usr/share/horde3> Options Indexes FollowSymLinks MultiViews AllowOverride Limit Order allow,deny allow from all </Directory> Alias /horde3 /usr/share/horde3и
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.keyна
SSLCertificateFile /etc/ssl/certs/oban.crt SSLCertificateKeyFile /etc/ssl/private/oban.keyПодключаем модуль ssl, разрешаем сайт default-ssl и перезапускаем apache
sudo a2enmod ssl sudo a2ensite default-ssl sudo /etc/init.d/apache2 restartРедактируем файл /etc/horde/horde3/conf.php и закомментарим строки
sudo nano /etc/horde/horde3/conf.php
//echo "Horde3 configuration disabled by default because the administration/install wizard gives the whole world too much access to the system. Read /usr/share/doc/horde3/README.Debian.gz on how to allow access."; //exit (0);Распаковываем скрипт для создания базы данных horde
sudo gzip -d /usr/share/doc/horde3/examples/scripts/sql/create.mysql.sql.gzи меняем пароль в файле /usr/share/doc/horde3/examples/scripts/sql/create.mysql.sql
sudo nano /usr/share/doc/horde3/examples/scripts/sql/create.mysql.sql
-- IMPORTANT: Change this password. PASSWORD('horde')на другой (далее будем называть его <horde_password>)
Исполняем скрипт с параметрами администратора mysql
sudo mysql --user=root --password=<mysql_password> < /usr/share/doc/horde3/examples/scripts/sql/create.mysql.sqlи заходим браузером на https://oban.aaa.ru
В первый раз нас пустят с администраторскими привилегиями. Настроим систему аутентификации. Вначале войдем в Управление - Приложения - Портал (horde) и выберем закладку Authentication.
Зададим список пользователей-администраторов, перечислив двух наших пользователей —
admin@bbb.ru, admin
(через запятую) в поле «Which users should be treated as administrators (root, super-user) by Horde?».
Затем выберем способ аутентификации - через IMAP (выберем
IMAP authentication
в поле «What backend should we use for authenticating users to Horde?»). Страница обновится, дав нам настройки для выбранного нами способа аутентификации.
В поле «Configuration type» выберем
Separate values
.
В поле «The hostname or IP address of the server» оставим
localhost
В поле «The server port to which we will connect. IMAP is generally 143, while IMAP-SSL is generally 993.» выберем
143
(в данном случае мы используем локальный IMAP-сервер, так что это нам подходит)
В поле «The connection protocol» выберем
imap/notls
Переходим во вкладку Database и конфигурируем доступ к созданной ранее базе данных.
В поле «What database backend should we use?» выбираем
MySQL
В поле «Username to connect to the database as» вводим
horde
В поле «Password to connect with» вводим пароль, который мы вводили в скрипте создания базы данных-
<horde_password>
В поле «How should we connect to the database?» выбираем
TCP/IP
В поле «Database server/host» вводим
localhost
В поле «Port the DB is running on, if non-standard» оставляем
3306
В поле «Database name to use» вводим
horde
В поле «Internally used charset» оставляем
utf-8
Переходим в закладку Mailer и настраиваем доступ к SMTP-серверу:
В поле «What method should we use for sending mail?» выбираем
Use a SMTP server
В поле «SMTP authentication» выбираем
PLAIN
Переходим в закладку Preference System и выбираем
SQL Database
в поле «What preferences driver should we use?».
Переходим в закладку Datatree System и выбираем
SQL Database
в поле «What backend should we use for Horde DataTree storage?».
Переходим в закладку Cache System и выбираем
Store objects in filesystem
в поле «If
you want to enable the Horde Cache, select a driver here. This is used
to speed up portions of Horde by storing commonly processed objects.». В поле «The location to store the cached files» выбираем /tmp
Переходим в закладку Virtual File Storage и выбираем
Files on the local system
в закладке «What VFS driver should we use?»
Переходим в закладку Custom Session Handler и настраиваем доступ к созданной ранее базе данных:
В поле «What sessionhandler driver should we use?» выбираем
MySQL based sessions
В поле «What protocol will we use to connect to the database?» выбираем
TCP/IP
В поле «What password do we authenticate to the database server with?» вводим пароль, который мы вводили в скрипте создания базы данных -
<horde_password>
Остальные поля оставляем по умолчанию.
Теперь нажмем кнопку Generate Портал Configuration. Получим сообщение «Невозможно сохранить резервную копию конфигурации в файл /usr/share/horde3/config/conf.bak.php.
Невозможно сохранить файл конфигурации /usr/share/horde3/config/conf.php. Вы можете использовать опции для сохранения кода обратно в Приложения или скопировать вручную код, приведенный ниже в /usr/share/horde3/config/conf.php.»
Это нормально, т.к. мы не хотим, чтобы возможно было менять конфигурацию через веб. Скопируем показанный внизу на странице сгенеренный код и запишем его в файл /etc/horde/horde3/conf.php (важно скопировать ВЕСЬ текст, заменив ВЕСЬ текст, имеющийся в файле).
sudo nano /etc/horde/horde3/conf.php(здесь вставляем скопированный текст со страницы броузера)
Закроем окно броузера.
Отредактируем файл /etc/horde/imp4/servers.php
sudo nano /etc/horde/imp4/servers.php
$servers['imap'] = array( 'name' => 'IMAP Server', 'server' => '127.0.0.1', 'hordeauth' => full, 'protocol' => 'imap/notls', 'port' => 143, 'maildomain' => '', 'smtphost' => '127.0.0.1', 'smtpport' => 25, 'realm' => '', 'preferred' => '', 'quota' => array('driver'=>imap), );и закомментируем все остальные примеры ниже.
Войдем заново на https://oban.aaa.ru уже под одним из введенных нами пользователей с правами администратора.
Зайдем в Управление - Приложения - Почта (imp) и выберем закладку Server.
В поле «Should we display a list of servers (defined in config/servers.php) for users to choose from? The options are 'shown', 'hidden', and 'none'. If the server list is hidden then you can use the 'preferred' mechanism to auto-select from it based on an HTTP virtualhost or another piece of data. If it is shown, the user will be able to pick from any of the options. If none, no server list will be shown and the defaults will be used unless another mechanism changes them.» выберем
Hidden
.
Нажмем кнопку Generate Почта Configuration, скопируем сгенеренный текст конфигурации и запишем в файл /etc/horde/imp4/conf.php
sudo nano /etc/horde/imp4/conf.php(здесь вставляем скопированный текст со страницы броузера)
Отредактируем файл /etc/horde/passwd3/backends.php
sudo nano /etc/horde/passwd3/backends.phpЗакомментируем все кроме
$backends['sql'] = array ( 'name' => 'Exampe SQL Server', 'preferred' => '', 'password policy' => array( 'minLength' => 3, 'maxLength' => 8, 'maxSpace' => 0, 'minUpper' => 0, 'minLower' => 0, 'minNumeric' => 0, 'minSymbols' => 0 ), 'driver' => 'sql', 'params' => array( 'phptype' => 'mysql', 'hostspec' => 'localhost', 'username' => 'mail_admin', 'password' => '<mail_admin_password>', 'encryption' => 'crypt', 'database' => 'mail', 'table' => 'users', 'user_col' => 'email', 'pass_col' => 'password', 'show_encryption' => false // The following two settings allow you to specify custom queries for // lookup and modify functions if special functions need to be // performed. In places where a username or a password needs to be // used, refer to this placeholder reference: // %d -> gets substituted with the domain // %u -> gets substituted with the user // %U -> gets substituted with the user without a domain part // %p -> gets substituted with the plaintext password // %e -> gets substituted with the encrypted password // // 'query_lookup' => 'SELECT user_pass FROM horde_users WHERE user_uid = %u', // 'query_modify' => 'UPDATE horde_users SET user_pass = %e WHERE user_uid = %u', ) );(здесь вместо <mail_admin_password> вставьте пароль mysql пользователя mail_admin, а также можете изменить политику паролей — какие пароли допустимы:
'minLength' — минимальная длина паролей
'maxLength' — максимальная длина паролей
'minUpper' — минимальное количество заглавных букв в паролях
'minLower' — минимальное количество прописных букв в паролях
'minNumeric' — минимальное количество цифровых символов в паролях
'minSymbols' — минимальное количество прочих символов букв в паролях)
Зайдем в Управление - Приложения - Пароль (passwd) и в поле «Should we display a list of backends (defined in config/backends.php) for users to choose from? The options are 'shown', 'hidden'. If the backend list is hidden then you can use the 'preferred' mechanism to auto-select from it based on an HTTP virtualhost or another piece of data. If it is shown, the user will be able to pick from any of the options.» выберем
Hidden
.
Нажмем кнопку Generate Пароль Configuration, скопируем сгенеренный текст конфигурации и запишем в файл /etc/horde/passwd3/conf.php
sudo nano /etc/horde/passwd3/conf.php(здесь вставляем скопированный текст со страницы броузера)
Отредактируем файл /etc/horde/horde3/registry.php
sudo nano /etc/horde/horde3/registry.phpи для приложений imp, passwd и turba заменим
'status' => 'inactive',на
'status' => 'active',Учтите, что для пользователей, которые входят с использованием ldap мы не настроили смену пароля (это лучше делать другими средствами - внутри нашей сети, а не давать им менять пароль через веб). Кроме этого, этим пользователям (т.к. они входят, вводя только имя, а не имя@домен), нужно задавать свой почтовый адрес в поле «Ваш адрес отправителя:« в Настройки - Почта — Личные.
Для настройки адресной книги выполним
sudo mysql -u horde -p horde < /usr/share/doc/turba2/examples/scripts/sql/turba.sql
Enter password:
Введем пароль пользователя horde
<horde_password>Зайдем в Управление - Приложения — Адресная книга (turba) и нажмем кнопку Create Адресная книга Configuration, скопируем сгенеренный текст конфигурации и запишем в файл /etc/horde/turba2/conf.php
sudo nano /etc/horde/turba2/conf.php(здесь вставляем скопированный текст со страницы броузера)
Основное мы уже установили и настроили. Теперь установим ряд дополнений.
Установка amavisd-new, SpamAssassin и ClamAV
Для установки amavisd-new, spamassassin и clamav, выполним следующую команду:
$sa_spam_report_header - добавление заголовков с подробным отчетом о результатах проверки. Учтите только, что эти заголовки будут вставлены только в письма, признанные спамом. Подробный отчет - это объяснения каждого сработавшего правила spamassassin, типа вот такого:
$sa_tag2_level_deflt - уровень, начиная с которого сообщение признается спамом.
$sa_kill_level_deflt - уровень, начиная с которого выполняется правило по обработке спама (описание ниже)
$sa_dsn_cutoff_level - уровень, начиная с которого не отсылается сообщение о невозможности доставки. Очень советую его иметь равным $sa_kill_level_deflt, иначе Вас, скорее всего, внесут в какой-нибудь черный список. Особенно это любит делать, например, att.com
$sa_quarantine_cutoff_level - уровень начиная с которого письмо не сохраняется в карантине (/var/lib/amavis/virusmails/…)
$final_virus_destiny - просто игнорировать (сами письма сохраняются в карантине)
$final_banned_destiny - письма с запрещенными вложениями по типу файлов: сообщить отправителю о невозможности доставки
$final_spam_destiny - игнорировать (это и есть то самое правило обработки спама, о котором шла речи выше)
$final_bad_header_destiny - некорректные заголовки писем пропускать.
$virus_admin - адрес, куда доставлять сообщения о вирусах и отраженных письмах с запрещенными вложениями (postmaster), чтобы можно было проверить содержимое писем в карантине. О письмах со спамом, попавшим в карантин, сообщений не будет.
Настройки, связанные с вирусами и запрещенными вложениями лучше оставить «по умолчанию».
Конкретные уровни оценки выставьте сами (я использую именно такие, и они меня полностью удовлетворяют, по крайней мере, по прошествии довольно большого времени и накопленной bayes-овской базы и с регулярными обновлениями правил spamassassin). Недавно специально проверял - за три дня ложных срабатываний было 0 (менял
Сделаем так, чтобы amavis не проверял исходящие письма на спам, а только входящие (на вирусы он будет проверять все письма). Вставим строки
sudo apt-get install amavisd-new spamassassin clamav clamav-daemon zoo unzip bzip2 libnet-ph-perl libnet-snpp-perl libnet-telnet-perl nomarch lzop paxВключим ClamAV и SpamAssassin отредактировав /etc/amavis/conf.d/15-content_filter_mode
sudo nano /etc/amavis/conf.d/15-content_filter_modeРаскомментируем
@bypass_virus_checks_maps = ( \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);и
@bypass_spam_checks_maps = ( \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);Отредактируем /etc/amavis/conf.d/50-user
sudo nano /etc/amavis/conf.d/50-userДобавим посередке параметр
$pax='pax';и
@lookup_sql_dsn = (['DBI:mysql:mail; host=127.0.0.1; port=3306', 'mail_admin' ,'<mail_admin_password>']); $sql_select_policy = 'SELECT "Y" as local FROM domains WHERE CONCAT("@",domain) IN (%k)';(нам нужно указать amavis, что виртуальные домены являются локальными. Иначе он не будет вставлять заголовки и проверять на спам, т.к. будет считать, что письма, посланные на виртуальные домены — исходящие) .
Не забудьте подставить свой пароль пользователя mysql mail_admin.
Откроем файл /etc/amavis/conf.d/20-debian_defaults
sudo nano /etc/amavis/conf.d/20-debian_defaultsДальше — список параметров, которые используются у меня с кратким пояснением, зачем и почему.
$enable_db = 1; # enable use of BerkeleyDB/libdb (SNMP and nanny) $enable_global_cache = 1; # enable use of libdb-based cache if $enable_db=1 $spam_check_negative_ttl = 30*60; $spam_check_positive_ttl = 30*60;Это позволяет держать небольшой кеш уже проверенных писем и не проверять точно такие же письма заново, если они уже есть в кеше. Проверка идет по сигнатуре, которую amavis генерирует сам. Полезно, когда, в частности, один и тот же спам валится на несколько адресов. ttl-параметры - это срок жизни сигнатуры в кеше (с положительным и отрицательным результатом проверки на спам). В моем случае, процент попадания в кеш порядка 8.
$sa_spam_subject_tag = '***SPAM*** '; $sa_spam_report_header = 1; $sa_tag_level_deflt = undef; # add spam info headers if at, or above that level $sa_tag2_level_deflt = 4.5; # add 'spam detected' headers at that level $sa_kill_level_deflt = 6.9; # triggers spam evasive actions $sa_dsn_cutoff_level = 6.9; # spam level beyond which a DSN is not sent $sa_quarantine_cutoff_level = 11.9;$sa_spam_subject_tag - добавление указанной строки в начало темы письма. Удобно для получателей.
$sa_spam_report_header - добавление заголовков с подробным отчетом о результатах проверки. Учтите только, что эти заголовки будут вставлены только в письма, признанные спамом. Подробный отчет - это объяснения каждого сработавшего правила spamassassin, типа вот такого:
X-Spam-Report:
* 1.4 MSGID_MULTIPLE_AT Message-ID contains multiple '@' characters
* 0.0 HTML_MESSAGE BODY: HTML included in message
* 0.0 BAYES_50 BODY: Bayesian spam probability is 40 to 60%
* [score: 0.5000]
* 1.8 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding
* 1.3 AWL AWL: From: address is in the auto white-list
$sa_tag_level_deflt - добавлять заголовки с результатом
проверки на спам в сообщения с указанной оценкой и выше. Здесь - всегда
добавлять эти заголовки. Заголовки вот такие:
* 1.4 MSGID_MULTIPLE_AT Message-ID contains multiple '@' characters
* 0.0 HTML_MESSAGE BODY: HTML included in message
* 0.0 BAYES_50 BODY: Bayesian spam probability is 40 to 60%
* [score: 0.5000]
* 1.8 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding
* 1.3 AWL AWL: From: address is in the auto white-list
Х-Spam-Flag: YES
X-Spam-Score: 4.54
X-Spam-Level:
X-Spam-Status: Yes, score=4.54 required=4.5 tests=[AWL=1.336, BAYES_50=0.001,
HTML_MESSAGE=0.001, MIME_BASE64_TEXT=1.753, MSGID_MULTIPLE_AT=1.449]
если опознан спам и
X-Spam-Score: 4.54
X-Spam-Level:
X-Spam-Status: Yes, score=4.54 required=4.5 tests=[AWL=1.336, BAYES_50=0.001,
HTML_MESSAGE=0.001, MIME_BASE64_TEXT=1.753, MSGID_MULTIPLE_AT=1.449]
X-Spam-Flag: NO
X-Spam-Score: -0.708
X-Spam-Level:
X-Spam-Status: No, score=-0.708 required=4.5 tests=[AWL=0.403, BAYES_05=-1.11,
SPF_PASS=-0.001]
если сообщение «чистое». Еще раз подчеркну, что в этом случае заголовка
«X-Spam-Report:» не будет. Если нужен - нужно править сам amavis.
X-Spam-Score: -0.708
X-Spam-Level:
X-Spam-Status: No, score=-0.708 required=4.5 tests=[AWL=0.403, BAYES_05=-1.11,
SPF_PASS=-0.001]
$sa_tag2_level_deflt - уровень, начиная с которого сообщение признается спамом.
$sa_kill_level_deflt - уровень, начиная с которого выполняется правило по обработке спама (описание ниже)
$sa_dsn_cutoff_level - уровень, начиная с которого не отсылается сообщение о невозможности доставки. Очень советую его иметь равным $sa_kill_level_deflt, иначе Вас, скорее всего, внесут в какой-нибудь черный список. Особенно это любит делать, например, att.com
$sa_quarantine_cutoff_level - уровень начиная с которого письмо не сохраняется в карантине (/var/lib/amavis/virusmails/…)
$final_virus_destiny = D_DISCARD; # (data not lost, see virus quarantine) $final_banned_destiny = D_BOUNCE; # D_REJECT when front-end MTA $final_spam_destiny = D_DISCARD; $final_bad_header_destiny = D_PASS; # False-positive prone (for spam) $virus_admin = "admin\@aaa.ru"; # due to D_DISCARD defaultПараметры задают правила обработки «нехороших» сообщений:
$final_virus_destiny - просто игнорировать (сами письма сохраняются в карантине)
$final_banned_destiny - письма с запрещенными вложениями по типу файлов: сообщить отправителю о невозможности доставки
$final_spam_destiny - игнорировать (это и есть то самое правило обработки спама, о котором шла речи выше)
$final_bad_header_destiny - некорректные заголовки писем пропускать.
$virus_admin - адрес, куда доставлять сообщения о вирусах и отраженных письмах с запрещенными вложениями (postmaster), чтобы можно было проверить содержимое писем в карантине. О письмах со спамом, попавшим в карантин, сообщений не будет.
Настройки, связанные с вирусами и запрещенными вложениями лучше оставить «по умолчанию».
Конкретные уровни оценки выставьте сами (я использую именно такие, и они меня полностью удовлетворяют, по крайней мере, по прошествии довольно большого времени и накопленной bayes-овской базы и с регулярными обновлениями правил spamassassin). Недавно специально проверял - за три дня ложных срабатываний было 0 (менял
D_DISCARD
на D_PASS
у $final_spam_destiny).
Сделаем так, чтобы amavis не проверял исходящие письма на спам, а только входящие (на вирусы он будет проверять все письма). Вставим строки
# add these for SASL SA bypass $policy_bank{'MYUSERS'} = { # mail from submission and smtps ports originating => 1, # Since amavisd-new 2.5.0 # declare that mail was submitted by our smtp client bypass_spam_checks_maps => [1], # don't spam-check this mail bypass_banned_checks_maps => [1], # don't banned-check this mail bypass_header_checks_maps => [1], # don't header-check this mail };Отредактируйте файл /etc/amavis/conf.d/21-ubuntu_defaults
sudo nano /etc/amavis/conf.d/21-ubuntu_defaultsи закомментируйте строки
#$final_virus_destiny = D_DISCARD; # (defaults to D_BOUNCE) #$final_banned_destiny = D_DISCARD; # (defaults to D_BOUNCE) #$final_spam_destiny = D_DISCARD; # (defaults to D_REJECT) #$final_bad_header_destiny = D_PASS; # (defaults to D_PASS), D_BOUNCE suggested #$virus_admin = undef; #$spam_admin = undef;Добавим пользователя clamav в группу amavis и перезапустим amavisd-new и ClamAV:
sudo adduser clamav amavis sudo /etc/init.d/amavis restart sudo /etc/init.d/clamav-daemon restart sudo /etc/init.d/clamav-freshclam restartУкажем, чтобы postfix проверял почту через amavis
sudo postconf -e 'content_filter = amavis:[127.0.0.1]:10024' sudo postconf -e 'receive_override_options = no_address_mappings'Отредактируем файл /etc/postfix/master.cf
sudo nano /etc/postfix/master.cfи добавим в конец следующие строки
amavis unix - - - - 2 smtp -o smtp_data_done_timeout=1200 -o smtp_send_xforward_command=yes 127.0.0.1:10025 inet n - - - - smtpd -o content_filter= -o local_recipient_maps= -o relay_recipient_maps= -o smtpd_restriction_classes= -o smtpd_client_restrictions= -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks=127.0.0.0/8 -o strict_rfc821_envelopes=yes -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks -o smtpd_bind_address=127.0.0.1Перезапустим postfix
sudo /etc/init.d/postfix restartДля периодической очистки карантина вставим в cron
sudo crontab -e
1 0 * * * find /var/lib/amavis/virusmails/* -mtime +60 | xargs rm &> /dev/null(ежедневная очистка всех файлов из карантина, старше 60 дней)
Установка Razor, Pyzor And DCC и настройка SpamAssassin
Установим нужные пакеты
Скажем spamassassin использовать эти три программы. Отредактируем /etc/spamassassin/local.cf добавив несколько строчек в конец:
Обновим набор правил для SpamAssassin следующим образом:
Для работы razor нам нужно сформировать для него домашнюю директорию и зарегистрироваться, для того, чтобы иметь возможность сообщать о спаме. Т. к. spamassassin работает от имени пользователя amavis, сделаем следующее (по умолчанию домашней директорией пользователя amavis является /var/lib/amavis):
Зададим правила отчета о спаме в horde. Зайдем броузером на https://oban.aaa.ru под административной записью и зайдя в Управление - Приложения - Почта (imp) и выберем закладку Message and Spam.
В поле «Should we report the spam message via an external program (e.g. /usr/local/bin/spamassassin -r)? If you include the placeholder %u in this string, it will be replaced with the current username. If you include the placeholder %l in this string, it will be replaced with the current short username. If you include the placeholder %d in this string, it will be replaced with the current domain name.» введем
При приеме писем postfix проверки на спам проводятся amavisd-new пользователем amavis, а при работе horde — пользователем www-data. Поэтому создаем ссылки
sudo apt-get install razor pyzorDCC не содержится в репозитории Ubuntu, поэтому мы его установим так:
cd /tmp wget http://launchpadlibrarian.net/11564361/dcc-server_1.3.42-5_i386.deb wget http://launchpadlibrarian.net/11564359/dcc-common_1.3.42-5_i386.deb sudo dpkg -i dcc-common_1.3.42-5_i386.deb sudo dpkg -i dcc-server_1.3.42-5_i386.deb cd ~(Для работы клиента DCC нам нужно пробросить на шлюзе UDP порт 6277 на наш почтовый сервер)
Скажем spamassassin использовать эти три программы. Отредактируем /etc/spamassassin/local.cf добавив несколько строчек в конец:
sudo nano /etc/spamassassin/local.cf
#dcc use_dcc 1 dcc_path /usr/bin/dccproc #pyzor use_pyzor 1 pyzor_path /usr/bin/pyzor #razor use_razor2 1 razor_config /etc/razor/razor-agent.conf #bayes use_bayes 1 use_bayes_rules 1 bayes_auto_learn 1Мы должны включить плагин DCC в SpamAssassin. Откроем /etc/spamassassin/v310.pre
sudo nano /etc/spamassassin/v310.preи раскомментируем такую строчку
loadplugin Mail::SpamAssassin::Plugin::DCCПроверим конфигурацию spamassassin
spamassassin --lint
Мы не должны получить никакого сообщения, если у нас все в норме.
Обновим набор правил для SpamAssassin следующим образом:
sudo sa-update --no-gpgДобавим в cron задание, чтобы набор правил обновлялся регулярно. Запустим
sudo crontab -eчтобы открыть редактор cron и добавим в него следующее задание:
23 4 */2 * * /usr/bin/sa-update --no-gpg &> /dev/nullЭто позволит обновлять набор правил каждый 2 день в 4 часа 23 минуты.
Для работы razor нам нужно сформировать для него домашнюю директорию и зарегистрироваться, для того, чтобы иметь возможность сообщать о спаме. Т. к. spamassassin работает от имени пользователя amavis, сделаем следующее (по умолчанию домашней директорией пользователя amavis является /var/lib/amavis):
sudo su amavis cd razor-admin -create razor-admin -register
Register successful. Identity stored in /var/lib/amavis/.razor/identity-XXXXXXXXXX
exit
После этого у нас появится директория /var/lib/amavis/.razor/ в которой будет лежать информация о серверах razor и о имени/пароле для доступа к ним (сгенеренные автоматически).
Зададим правила отчета о спаме в horde. Зайдем броузером на https://oban.aaa.ru под административной записью и зайдя в Управление - Приложения - Почта (imp) и выберем закладку Message and Spam.
В поле «Should we report the spam message via an external program (e.g. /usr/local/bin/spamassassin -r)? If you include the placeholder %u in this string, it will be replaced with the current username. If you include the placeholder %l in this string, it will be replaced with the current short username. If you include the placeholder %d in this string, it will be replaced with the current domain name.» введем
/usr/local/bin/spamassassin -r
а в поле «Should
we report the innocent message via an external program (e.g.
/usr/local/bin/spamassassin -k)? If you include the placeholder %u in
this string, it will be replaced with the current username» введем /usr/local/bin/spamassassin -k
При приеме писем postfix проверки на спам проводятся amavisd-new пользователем amavis, а при работе horde — пользователем www-data. Поэтому создаем ссылки
sudo ln -s /var/lib/amavis/.pyzor /var/www/.pyzor sudo ln -s /var/lib/amavis/.razor /var/www/.razor sudo ln -s /var/lib/amavis/.spamassassin /var/www/.spamassassinи меняем права
sudo chmod -R g+rw /var/lib/amavis/.pyzor sudo chmod -R g+rw /var/lib/amavis/.razor sudo chmod -R g+rw /var/lib/amavis/.spamassassin sudo chmod g+x /var/lib/amavis/.pyzor sudo chmod g+x /var/lib/amavis/.razor sudo chmod g+x /var/lib/amavis/.spamassassinи вставляем пользователя www-data в группу amavis (чтобы разрешить доступ к bayes-базе при работе в horde)
sudo adduser www-data amavis
и перезапустим apache
sudo /etc/init.d/apache2 restartОтредактируем файл
sudo nano /etc/mail/spamassassin/local.cfи вставим туда строку
bayes_path /var/lib/amavis/.spamassassin/bayesВставим периодическое обновление нашей bayes-базы (будем делать это каждую ночь). Отредактируем файл
sudo nano /etc/cron.d/amavisd-newи вставим строку
1 0 * * * amavis sa-learn --force-expire --syncТаким образом, при приеме писем postfix при помощи amavis будет проверять письма в том числе по bayes-базе, которая формируется автоматически (обучение идет из писем с достаточно большим значением уровня спама; письма с очень малым показателем также участвуют в обучении — они помечаются, как ham, т. е. не-спам; письма со средним значением уровня спама в автоматическом обучении не участвуют). Кроме этого, в пополнении базы данных принимают участие и пользователи, когда помечают письма, как спам или не-спам (innocent). Чем больше писем участвует в обучении (и как спам, и как ham), тем лучше работает bayes-база данных спама.
Дополнительные правила для защиты от спама
Множество спам-хостов находится на компьютерах-зомби. К счастью, в
большинстве случаев эти компьютеры не настроены должным образом, как
мейл-серверы, что дает возможность их с легкостью отсекать еще на
начальном этапе получения писем.
Дело в том, что процесс передачи/получения письма начинается с представления серверов друг другу. После соединения по порту 25 (SMTP), компьютер - инициатор выдает команду
Для того, чтобы такие проверки проводились на этапе приемки писем, в файл /etc/postfix/main.cf нужно вставить следующие строки:
Подробнее об этих параметрах:
strict_rfc821_envelopes - запрет на использование заголовков в стиле RFC822. Если кратко - этот стандарт не имеет отношения к SMTP, а к формату самих писем, и не должен использоваться на этапе общения между серверами. Даже их названия об этом говорят: 821: SIMPLE MAIL TRANSFER PROTOCOL, 822: STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES.
disable_vrfy_command - запрет на использование команды VRFY. Эта команда зачастую используется для сбора с сервера существующих адресов почты для дальнейшей рассылки на них спама.
smtpd_delay_reject - подождать команды RCPT TO перед (возможным) отказом от приема письма. Нужно из-за того, что некоторые сервера неверно реагируют на отказ от приема писем до посылки ими команды RCPT TO
smtpd_helo_required - требовать от сервера обязательно представиться командой HELO. Это дает возможность проведения нужных нам проверок.
Проверки на каждом этапе происходят последовательно, в указанном в каждой команде порядке. Если условие выполнено, дальнейшие проверки не производятся.
smtpd_client_restrictions - ограничения на этапе установления связи по протоколу SMTP
Дело в том, что процесс передачи/получения письма начинается с представления серверов друг другу. После соединения по порту 25 (SMTP), компьютер - инициатор выдает команду
HELO hostname.domain.ltd
Принимающий сервер уже на этом этапе может отсечь кучу спама. Как это
сделать? Очень просто. Нормально сконфигурированный сервер обязан в
сообщении HELO передать свое истинное имя; причем это имя должно
соответствовать IP-адресу, с которого осуществляется соединение; а
IP-адрес должен резолвится в обратной зоне в это имя. Если это не так -
Вы имеете полное право отсечь соединение прямо на этом этапе. Плюсы: не
тратится лишний трафик на прием сообщений, которые заведомо являются
спамом; экономятся вычислительные затраты на дальнейшие проверки писем
на спам и вирусы. Необходим какой-то трафик для проведения проверок по DNS
(но он заведомо меньше трафика на прием писем). Отсечь «нормальное»
письмо бояться не стоит: неверная настройка почтового сервера, который
Вы отсекли - не Ваша головная боль.
Для того, чтобы такие проверки проводились на этапе приемки писем, в файл /etc/postfix/main.cf нужно вставить следующие строки:
sudo nano /etc/postfix/main.cf
strict_rfc821_envelopes = yes disable_vrfy_command = yes smtpd_delay_reject = yes smtpd_helo_required = yes smtpd_client_restrictions = sleep 1, reject_unauth_pipelining, permit_sasl_authenticated, permit_mynetworks, reject_unknown_client_hostname, permit smtpd_helo_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, reject_unknown_helo_hostname, permit smtpd_sender_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_sender, reject_unknown_sender_domain, permit smtpd_recipient_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unlisted_recipient, check_policy_service inet:127.0.0.1:10023, permit(отредактируйте существующие и добавьте отсутствующие) Если Вы не собираетесь использовать postgrey (я рекомендую его использовать), не вставляйте
check_policy_service inet:127.0.0.1:10023,
Подробнее об этих параметрах:
strict_rfc821_envelopes - запрет на использование заголовков в стиле RFC822. Если кратко - этот стандарт не имеет отношения к SMTP, а к формату самих писем, и не должен использоваться на этапе общения между серверами. Даже их названия об этом говорят: 821: SIMPLE MAIL TRANSFER PROTOCOL, 822: STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES.
disable_vrfy_command - запрет на использование команды VRFY. Эта команда зачастую используется для сбора с сервера существующих адресов почты для дальнейшей рассылки на них спама.
smtpd_delay_reject - подождать команды RCPT TO перед (возможным) отказом от приема письма. Нужно из-за того, что некоторые сервера неверно реагируют на отказ от приема писем до посылки ими команды RCPT TO
smtpd_helo_required - требовать от сервера обязательно представиться командой HELO. Это дает возможность проведения нужных нам проверок.
Проверки на каждом этапе происходят последовательно, в указанном в каждой команде порядке. Если условие выполнено, дальнейшие проверки не производятся.
smtpd_client_restrictions - ограничения на этапе установления связи по протоколу SMTP
- sleep 1 - пауза на 1 секунду для отсекания совсем нетерпеливых спам-хостов (обычно они просто сразу же рвут соединение - им нужно разослать как можно больше спама, поэтому ждать им - как серпом…)
- reject_unauth_pipelining - отсечь хосты, которые пытаются слать команды в конвейере, даже не проверив, поддерживает ли это наш сервер. Это часто делают именно спам-хосты для увеличения скорости передачи
- permit_sasl_authenticated - разрешить для авторизованных клиентов (пользователи)
- permit_mynetworks - разрешить при соединении из моей подсети
- reject_unknown_client_hostname -отказать в случае, если 1) не удалось сопоставить IP адрес имени хоста (по PTR-записи в DNS), 2) не удалось сопоставить имя IP-адресу хоста (прямой запрос DNS), 3) адрес, полученный из DNS по имени не совпадает с IP-адресом , с которого идет соединение. Отсекается ОЧЕНЬ много спам-хостов (в моем случае - процентов 80)
- permit - в другом случае продолжать прием
- permit_mynetworks - разрешить при соединении из моей подсети
- permit_sasl_authenticated - разрешить при аутентификации (пользователи)
- reject_invalid_helo_hostname - отказать при нарушении синтаксиса имени хоста в HELO (случается очень редко, тем не менее…)
- reject_non_fqdn_helo_hostname - отказать, если имя хоста в HELO не в полной форме (не должно быть просто server, а должно быть типа server.domain.ltd)
- reject_unknown_helo_hostname - отказать, если у хоста, указанного в команде HELO, в DNS нет записи типа MX или A (множество зобми-хостов)
- permit - в другом случае продолжать прием
- permit_mynetworks - разрешить при соединении из моей подсети
- permit_sasl_authenticated - разрешить при аутентификации (пользователи)
- reject_non_fqdn_sender - отказать, если имя отправителя не в полной форме (должно быть не name или name@domain а name@domain.ltd)
- reject_unknown_sender_domain - отказать, если наш сервер не является «родным» для отправителя и домен отправителя не имеет в DNS записи MX или A, или если он имеет неверную запись MX (например, пустую)
- permit - в другом случае продолжать прием
- reject_unauth_pipelining - отсечь хосты, которые пытаются слать команды в конвейере
- permit_sasl_authenticated - разрешить для авторизованных клиентов (пользователи)
- permit_mynetworks - разрешить при соединении из моей подсети
- reject_unauth_destination - отказать, если домен-адресат: 1) не перечислен в списке доменов, для которых мы форвардим почту ($relay_domains) и не содержит команд переадресации (типа user@another@domain); 2) не является «нашим» (т.е. не перечислен в списках $mydestination, $inet_interfaces, $proxy_interfaces, $virtual_alias_domains, или $virtual_mailbox_domains ) и не содержит команд переадресации (типа user@another@domain). Это - традиционные правила, чтобы наш сервер не служил т.н. Open Relay, через который спамеры рассылают почту третьим лицам.
- reject_non_fqdn_recipient - отказать, если имя получателя не в полной форме (должно быть не name или name@domain а name@domain.ltd)
- reject_unknown_recipient_domain - отказать, если мы не являемся «родным» сервером для получателя и домен получателя не имеет в DNS записи MX или A, или если он имеет неверную запись MX (например, пустую)
- reject_unlisted_recipient - отказать, если адрес получателя не указан в списках получателей домена (не перечислен в $local_recipient_maps или $virtual_alias_maps или $virtual_mailbox_maps или $relay_recipient_maps, в зависимости от того, в какой именно таблице найден домен получателя)
- check_policy_service inet:127.0.0.1:10023 - проверка у стороннего сервиса (в данном случае - postgrey, о нем чуть позже)
- permit - продолжать прием
Установка postgrey
Теперь о postgrey. Это еще один способ борьбы со спамом. Многим
он не нравится, мне - так очень. Работает он так. При приходе письма
(конечно, если оно «прорвалось» через все проверки, указанные выше)
сервер запоминает три параметра (так называемый триплет): от кого оно
послано, кому послано, и кем (т.е. адрес сервера, который его посылает),
и сообщает передающему серверу «Я сейчас занят, повторите чуть позже»,
после чего начинает отсчет времени для конкретного триплета. Большинство
спамеров, как мы знаем, ждать не любят, и либо пытаются повторить
посылку сразу же (на что получают тот же ответ), либо просто прекращают
свои попытки. Наш же сервер, если обнаружит повторное письмо с тем же
триплетом по прошествии некоторого времени (по умолчанию - 5 минут),
спокойно его примет. При этом этот триплет будет запомнен на какое-то
время (35 дней), так что следующие письма с тем же триплетом пройдут без
задержки. Если это Ваш постоянный корреспондент, то задержек больше не
будет вообще.
Установить postgrey очень просто:
Если Вы хотите изменить параметры postgrey, то это делается в файле /etc/default/postgrey.
Установить postgrey очень просто:
sudo apt-get install postgrey(в main.cf обращение к postgrey у нас уже добавлено)
Если Вы хотите изменить параметры postgrey, то это делается в файле /etc/default/postgrey.
sudo nano /etc/default/postgreyОтредактируйте строку
POSTGREY_OPTS="--inet=127.0.0.1:10023"добавив параметры
–delay=N
(в секундах; по умолчанию 300) и –max-age=N
(в сутках; по умолчанию 35):
POSTGREY_OPTS="--inet=127.0.0.1:10023 --delay=300 --max-age=35"Стоит заглянуть еще в два файла: это /etc/postgrey/whitelist_clients и /etc/postgrey/whitelist_recipients. В первом перечислены домены-отправители, письма от которых принимаются автоматом (по разным причинам), во втором - адреса-получатели, письма на которые также принимаются сразу всегда (например, abuse@). Можете при необходимости дописать в эти файлы свои строки.
Установка spf, , sender id, dkim, domainkey
И еще немного о борьбе со спамом.
Зачастую спамеры пытаются «замаскироваться» под обычных отправителей, т.е. подделывают обратный адрес (mail from:).
Есть способ а) обезопасить себя от таких «подделок» и б) проверять на этапе приема, не подделан ли обратный адрес.
Для этого в настоящее время существует четыре варианта. Советую использовать все.
Основная идея у всех вариантов похожа: в запись DNS Вашего домена вставляется некая информация, проверив которую принимающий сервер может определить, есть ли у отправителя разрешение на отсылку писем от имени указанного домена.
Зачастую спамеры пытаются «замаскироваться» под обычных отправителей, т.е. подделывают обратный адрес (mail from:).
Есть способ а) обезопасить себя от таких «подделок» и б) проверять на этапе приема, не подделан ли обратный адрес.
Для этого в настоящее время существует четыре варианта. Советую использовать все.
Основная идея у всех вариантов похожа: в запись DNS Вашего домена вставляется некая информация, проверив которую принимающий сервер может определить, есть ли у отправителя разрешение на отсылку писем от имени указанного домена.
Использование SPF
В DNS-запись своего домена нужно вставить следующую строку:
Если сервер обслуживает несколько доменов, нужно вставить соответствующие записи во все зоны.
Эта запись означает, что домен aaa.ru использует версию SPF1 и разрешает от своего имени посылать почту серверу, указанному в записи MX и A домена, и запрещает всем остальным.
На этапе приема сервер запросит в DNS запись MX и A Вашего домена, и, если полученный IP-адрес не совпадает с IP-адресом отправителя, то письмо будет отклонено.
Вместо -all на этапе тестирования можно вставить ~all (в этом случае письмо будет не отклонено, а сервер-получатель получит «предупреждение» о возможной подделке адреса отправителя - т.н. softfail).
Вообще говоря, запись для SPF в домене можно сгенерировать автоматически, ответив на несколько вопросов вот тут: http://www.openspf.org/
Для того, чтобы Ваш почтовый сервер производил проверку по SPF, нужно установить пакеты:
Отредактируйте файл /etc/postfix/master.cf
Перезагрузите postfix
aaa.ru. IN TXT "v=spf1 a mx -all"(здесь aaa.ru — Ваш домен)
Если сервер обслуживает несколько доменов, нужно вставить соответствующие записи во все зоны.
Эта запись означает, что домен aaa.ru использует версию SPF1 и разрешает от своего имени посылать почту серверу, указанному в записи MX и A домена, и запрещает всем остальным.
На этапе приема сервер запросит в DNS запись MX и A Вашего домена, и, если полученный IP-адрес не совпадает с IP-адресом отправителя, то письмо будет отклонено.
Вместо -all на этапе тестирования можно вставить ~all (в этом случае письмо будет не отклонено, а сервер-получатель получит «предупреждение» о возможной подделке адреса отправителя - т.н. softfail).
Вообще говоря, запись для SPF в домене можно сгенерировать автоматически, ответив на несколько вопросов вот тут: http://www.openspf.org/
Для того, чтобы Ваш почтовый сервер производил проверку по SPF, нужно установить пакеты:
sudo apt-get install python-policyd-spf python-spfОтредактируйте файл /etc/postfix/main.cf
sudo nano /etc/postfix/main.cfи вставьте строку
spf-policyd_time_limit = 3600sВ строку smtpd_recipient_restrictions вставьте
check_policy_service unix:private/policy-spf,(эту проверку следует вставить после reject_unauth_destination чтобы не было риска использовать Вас, как open relay)
Отредактируйте файл /etc/postfix/master.cf
sudo nano /etc/postfix/master.cfи вставьте строки
policy-spf unix - n n - - spawn user=nobody argv=/usr/bin/policyd-spfПроверка на SPF нужна только для входящих писем, исходящие письма с Вашего сервера проверять не надо.
Перезагрузите postfix
sudo /etc/init.d/postfix reload
Использование Sender ID
Технология Sender ID - это вариант от Microsoft. И, хотя мы не собираемся проверять входящую почту на Sender ID, мы уже сконфигурировали все, что необходимо для отправки писем с использованием Sender ID: эта технология использует ту же запись в DNS, которую мы внесли. Единственно что можно еще сделать - это зарегистрировать нашу запись в Microsoft вот здесь: https://support.msn.com/eform.aspx?productKey=senderid&page=support_senderid_options_form_byemail&ct=eformts
Использование Domainkey и DKIM
Эта технология несколько отличается от SPF. DKIM - это несколько улучшенный вариант Domainkey, однако лучше использовать оба сервиса, тем более, что установка очень похожа. Для использования Domankey и DKIM установим пакеты
Создадим директорию для хранения ключа и перепишем ключ в нее под именем mail (опять же, используйте свое имя домена), изменим разрешения для него и переименуем файл mail.txt:
Отредактируем файл /etc/default/dk-filter
и строку
Отредактируем файл конфигурации /etc/dkim-filter.conf
Создадим файл /etc/mail/dk-keys.conf
Создаем директорию для записи протокола работы dkim и меняем ее владельца
Последнее, что нам осталось сделать - это внести изменения в DNS-записи нашего домена (доменов):
Важное замечание: в записи _domainkey.aaa.ru. вместо «o=-» на этапе тестирования можно вставить «o=~». Первое означает, что ВСЕ письма от вашего домена подписываются, а второе - что подписываются только некоторые письма.
Кроме этого, на этапе тестирования в запись mail._domainkey.aaa.ru. (внутри кавычек) можно добавить ключ t=y; :
В ответ Вы получите письмо с результатами проверки всех четырех сервисов. Если в ответе будет примерно следующее:
sudo apt-get install dk-filter dkim-filterВыбирайте все опции «по умолчанию» при установке - сейчас мы сконфигурируем их вручную. Вначале сгенерим ключи (вместо aaa.ru используйте свой домен):
dkim-genkey -d aaa.ru -s mailУ Вас в текущей директории появится два файла: mail.private и mail.txt
Создадим директорию для хранения ключа и перепишем ключ в нее под именем mail (опять же, используйте свое имя домена), изменим разрешения для него и переименуем файл mail.txt:
sudo mkdir /etc/mail/aaa.ru sudo mv mail.private /etc/mail/aaa.ru/mail sudo chown root /etc/mail/aaa.ru/mail sudo chmod 644 /etc/mail/aaa.ru/mail mv mail.txt aaa.ru.txt(при необходимости повторим для другого домена)
Отредактируем файл /etc/default/dk-filter
sudo nano /etc/default/dk-filterи вставим туда строку
DAEMON_OPTS="$DAEMON_OPTS -d aaa.ru -k -s /etc/mail/dk-keys.conf -S mail"(если нужно несколько доменов — перечисляем их через запятую)
и строку
SOCKET="inet:8892@localhost"Отредактируем файл /etc/default/dkim-filter
sudo nano /etc/default/dkim-filterСтрока
SOCKET="inet:8891@localhost" # Ubuntu default - listen on loopback on port 8891должна быть раскомментарена.
Отредактируем файл конфигурации /etc/dkim-filter.conf
sudo nano /etc/dkim-filter.confи поменяем в нем строку
Domain aaa.ruЕсли нужно подписывать почту от нескольких доменов, вставляем список этих доменов:
Domain aaa.ru, bbb.ruи следующие строки
Selector mail AutoRestart no Background yes Canonicalization simple DNSTimeout 5 Mode sv SignatureAlgorithm rsa-sha256 SubDomains yes X-Header no AlwaysAddARHeader yes On-BadSignature reject Statistics /var/log/dkim-filter/dkim-stats KeyList /etc/mail/dkim-keys.confСоздадим файл /etc/mail/dkim-keys.conf
sudo nano /etc/mail/dkim-keys.conf
*@aaa.ru:aaa.ru:/etc/mail/aaa.ru/mail(вставляем строки с соответствующими параметрами для каждого домена)
Создадим файл /etc/mail/dk-keys.conf
sudo nano /etc/mail/dk-keys.conf
*@aaa.ru:/etc/mail/aaa.ru/mail(вставляем строки с соответствующими параметрами для каждого домена)
Создаем директорию для записи протокола работы dkim и меняем ее владельца
sudo mkdir /var/log/dkim-filter sudo chown dkim-filter /var/log/dkim-filterОтредактируем файл /etc/postfix/main.cf
sudo nano /etc/postfix/main.cfи добавим в него строки
milter_default_action = accept milter_protocol = 2 smtpd_milters = inet:localhost:8891,inet:localhost:8892 non_smtpd_milters = inet:localhost:8891,inet:localhost:8892Проверьте, что файл
sudo nano /etc/amavis/conf.d/21-ubuntu_defaultsсодержит раскомментаренную строку
$enable_dkim_verification = 1;Отредактируем файл /etc/postfix/master.cf
sudo nano /etc/postfix/master.cfи в блоке
127.0.0.1:10025 inet n - - - - smtpd -o content_filter= -o local_recipient_maps= -o relay_recipient_maps= -o smtpd_restriction_classes= -o smtpd_client_restrictions= -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks=127.0.0.0/8 -o strict_rfc821_envelopes=yes -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks -o smtpd_bind_address=127.0.0.1изменим строку
-o receive_override_options=no_unknown_recipient_checks,no_header_body_checks,no_miltersиначе наши исходящие письма будут подписываться DKIM два раза.
Последнее, что нам осталось сделать - это внести изменения в DNS-записи нашего домена (доменов):
mail._domainkey.aaa.ru. IN TXT "g=*; k=rsa; p=XXXXXXXXXX" ; ----- DKIM mail for aaa.ru _domainkey.aaa.ru. IN TXT "o=-"Здесь вместо aaa.ru - Ваш домен, а вместо XXXXXXXXXX - значение, записанное в «p=» в файле aaa.ru.txt для соответствующего домена, который появился при генерации ключей.
Важное замечание: в записи _domainkey.aaa.ru. вместо «o=-» на этапе тестирования можно вставить «o=~». Первое означает, что ВСЕ письма от вашего домена подписываются, а второе - что подписываются только некоторые письма.
Кроме этого, на этапе тестирования в запись mail._domainkey.aaa.ru. (внутри кавычек) можно добавить ключ t=y; :
mail._domainkey.aaa.ru. IN TXT "g=*; k=rsa; t=y; p=XXXXXXXXXX" ; ----- DKIM mail for aaa.ru _domainkey.aaa.ru. IN TXT "o=~"
ВАЖНО: При внесении изменений в зону DNS не забудьте увеличить номер зоны в записи SOA!
Перезапускаем сервисы dk-filter и dkim-filter
sudo /etc/init.d/dk-filter restart sudo /etc/init.d/dkim-filter restartЕсли они запустились нормально, перезапускаем postfix
sudo /etc/init.d/postfix restartПротестировать только что установленные сервисы можно послав тестовое письмо на адрес check-auth@verifier.port25.com
В ответ Вы получите письмо с результатами проверки всех четырех сервисов. Если в ответе будет примерно следующее:
==========================================================
Summary of Results
==========================================================
SPF check: pass
DomainKeys check: pass
DKIM check: pass
Sender-ID check: pass
то все работает нормально.
Summary of Results
==========================================================
SPF check: pass
DomainKeys check: pass
DKIM check: pass
Sender-ID check: pass
Проверяем работу антиспама и антивируса
Для проверки работы антивируса пошлите себе с внешнего почтового аккаунта (например, gmail) письмо, содержащее следующую строку (это - не вирус, а стандартное тестовое письмо EICAR для проверки антивируса):
Для проверки антиспама пошлите себе с внешнего почтового аккаунта (например, gmail) письмо, содержащее следующую строку (это стандартный антиспам-тест GTUBE):
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*и проверьте логи /etc/log/mail.log
cat /var/log/mail.log | grep "Blocked INFECTED"Вы должны увидеть примерно такую запись:
Nov 30 22:02:22 oban amavis[21994]:
(21994-01) Blocked INFECTED
(Eicar-Test-Signature(69630e4574ec6798239b091cda43dca0:69)),
[209.85.161.169] [209.85.161.169] <username@gmail.com> ->
<admin@aaa.ru>, quarantine: n/virus-nGy-KxAsczIP, Message-ID:
<AANLkTinxbYap5wcw8pstUQiLCuR1GjQQNPcWT_SCKtAo@mail.gmail.com>,
mail_id: nGy-KxAsczIP, Hits: -, size: 2159,
dkim_id=@gmail.com,username@gmail.com, 157 ms
Это письмо попадет в карантин (в нашем случае — в /var/lib/amavis/n/virus-nGy-KxAsczIP)
Для проверки антиспама пошлите себе с внешнего почтового аккаунта (например, gmail) письмо, содержащее следующую строку (это стандартный антиспам-тест GTUBE):
XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34Xи проверьте логи /etc/log/mail.log
cat /var/log/mail.log | grep "Blocked SPAM"
Nov 30 22:37:29 oban amavis[22916]:
(22916-01) Blocked SPAM, [209.85.161.41] [209.85.161.41]
<username@gmail.com> -> <admin@aaa.ru>, Message-ID:
<AANLkTinwyt0y-nk2yynQ40LfGmv9kO5vv082zubwwrk+@mail.gmail.com>,
mail_id: ZD4iIEb5EZHD, Hits: 1002.473, size: 2168,
dkim_id=@gmail.com,username@gmail.com, 2727 ms
(обратите внимание, что это тестовое письмо получит «вес» около 1000)
Установка fail2ban
Еще одно добавление к серверу. Дело в том, что все сервера так или иначе
«торчащие» в интернет, становятся целью для атак, и наш почтовый сервер
- не исключение. Одна из атак - попытка «взлома» паролей пользователей.
Такая атака обычно проводится с перебором паролей, и рано или поздно
может быть удачной. В нашем случае - это атака на аутентификацию
пользователей по IMAP, POP3, SMTP.
Бороться достаточно просто - есть прекрасная программа fail2ban, которая после N неудачных попыток просто прописывает в файрволле правила, запрещающие доступ с атакующего IP-адреса на определенный срок (чаще всего - на час через 3 неудачных попытки). Такие «паузы» делают подобные атаки практически бессмысленными.
Для защиты устанавливаем пакет fail2ban
Когда убедимся, что все работает - перезапустим сервис
Бороться достаточно просто - есть прекрасная программа fail2ban, которая после N неудачных попыток просто прописывает в файрволле правила, запрещающие доступ с атакующего IP-адреса на определенный срок (чаще всего - на час через 3 неудачных попытки). Такие «паузы» делают подобные атаки практически бессмысленными.
Для защиты устанавливаем пакет fail2ban
sudo apt-get install fail2banСоздаем файл /etc/fail2ban/filter.d/dovecot.conf
sudo nano /etc/fail2ban/filter.d/dovecot.conf
[Definition] failregex = (?: pop3-login|imap-login): (?:Authentication failure|Aborted login \(auth failed|Aborted login \(tried to use disabled|Disconnected \(auth failed).*rip=(?P<host>\S*),.* ignoreregex =Скопируем на всякий случай файл /etc/fail2ban/jail.conf
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.conf_origВ нем есть примеры множества сервисов, нас же интересуют только часть из них. Отредактируем нужные строки в файле /etc/fail2ban/jail.conf
sudo nano /etc/fail2ban/jail.conf
ignoreip = 127.0.0.1 10.0.0.0/16 bantime = 3600 destemail = admin@aaa.ruЗдесь мы говорим, чтобы fail2ban игнорировал атаки с адресов 127.0.0.1 и сети 10.0.0.0/255.255.0.0 (предполагаем, что это наша внутренняя сеть, и из нее могут быть разве что ошибочные попытки набора паролей пользователями); после 3 неудачных попыток аутентификации мы ставим бан на 3600 секунд (1 час); информацию о банах будем посылать на admin@company.ru (поменяйте на свой).
[ssh] enabled = true port = ssh filter = sshd banaction = iptables-allports sendmail-whois logpath = /var/log/auth.log maxretry = 3 [dovecot] enabled = true port = imap2,imap3,imaps,pop3,pop3s filter = dovecot logpath = /var/log/mail.log banaction = iptables-allports sendmail-whois maxretry = 3 [sasl] enabled = true port = smtp,ssmtp filter = sasl banaction = iptables-allports sendmail-whois logpath = /var/log/mail.warn maxretry = 3По правилам, описанным в файле /etc/fail2ban/filter.d/sshd.conf мы:
- анализируем лог-файл /var/log/auth.log
- баним доступ по всем портам и посылаем письмо о возможной атаке через 3 неверные попытки аутентификации
- сами правила в файле sshd.conf оставляем «по умолчанию»
Nov 25 10:19:41 oban sshd[30769]: Failed password for root from AA.BB.CC.DD port 60031 ssh2
По правилам, описанным в файле /etc/fail2ban/filter.d/dovecot.conf мы:
- анализируем лог-файл /var/log/mail.log
- баним доступ по всем портам и посылаем письмо о возможной атаке через 3 неверные попытки аутентификации
- сами правила в файле dovecot.conf мы только что составили
Nov 27 23:41:57 oban dovecot: imap-login: Aborted login (no auth attempts): rip=AA.BB.CC.DD, lip=10.0.0.6
Nov 27 23:40:18 oban dovecot: pop3-login: Disconnected (no auth attempts): rip=AA.BB.CC.DD, lip=10.0.0.6, TLS handshaking: SSL_accept() failed: error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca
По правилам, описанным в файле /etc/fail2ban/filter.d/sasl.conf мы:
Nov 27 23:40:18 oban dovecot: pop3-login: Disconnected (no auth attempts): rip=AA.BB.CC.DD, lip=10.0.0.6, TLS handshaking: SSL_accept() failed: error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca
- анализируем лог-файл /var/log/mail.warn
- баним доступ по всем портам и посылаем письмо о возможной атаке через 3 неверные попытки аутентификации
- правило в файле /etc/fail2ban/filter.d/sasl.conf чуть изменим (с правилом «по умолчанию» срабатываний не будет):
sudo nano /etc/fail2ban/filter.d/sasl.conf
#failregex = (?i): warning: [-._\w]+\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [A-Za-z0-9+/]*={0,2})?$ failregex = (?i): warning: [-._\w]+\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failedПримеры записей в /etc/log/mail.log которые будут «пойманы»
Nov 24 19:21:20 oban postfix/smtpd[458]: warning: unknown[AA.BB.CC.DD]: SASL LOGIN authentication failed: generic failure
Nov 24 22:32:35 oban postfix/smtpd[2593]: warning: unknown[AA.BB.CC.DD]: SASL LOGIN authentication failed: authentication failure
Можно проверить срабатывание написанных нами правил:
Nov 24 22:32:35 oban postfix/smtpd[2593]: warning: unknown[AA.BB.CC.DD]: SASL LOGIN authentication failed: authentication failure
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf fail2ban-regex /var/log/mail.log /etc/fail2ban/filter.d/dovecot.conf fail2ban-regex /var/log/mail.warn /etc/fail2ban/filter.d/sasl.confЕсли в лог-файлах были попытки неверной аутентификации, мы получим по ним «отчет».
Когда убедимся, что все работает - перезапустим сервис
sudo /etc/init.d/fail2ban restartи наслаждаемся попадающими к нам «хакерами».
Дополнительные настройки
Для того, чтобы наш сервер нормально воспринимали другие сервера, нам нужно сделать еще две вещи.
Первая - правильно и полно прописать DNS-зоны. В идеале MX запись должна указывать на имя сервера, а IP сервера в свою очередь, должен резолвиться в то же имя сервера. Тогда все будет «в шоколаде».
Т.е., например:
Первая - правильно и полно прописать DNS-зоны. В идеале MX запись должна указывать на имя сервера, а IP сервера в свою очередь, должен резолвиться в то же имя сервера. Тогда все будет «в шоколаде».
Т.е., например:
host aaa.ru
aaa.ru has address 78.108.81.68
aaa.ru mail is handled by 10 mxs.majordomo.ru.
aaa.ru mail is handled by 10 mxs.majordomo.ru.
host mxs.majordomo.ru
mxs.majordomo.ru has address 78.108.81.249
host 78.108.81.249
249.81.108.78.in-addr.arpa domain name pointer mxs.majordomo.ru.
Вторая - если Ваш почтовый сервер расположен за NAT, а Вы используете
алиас на шлюзе, то он будет виден другим серверам не со своим IP-адресом
(адресом алиаса), а с IP-адресом шлюза, что нехорошо (Ваши письма могут
быть «отражены» адресатом на этом основании). Чтобы Ваш почтовый сервер
был виден под своим IP-адресом (т.е. IP-адресом алиаса на шлюзе), нужно
вставить на шлюзе что-то типа
#Added for 1:1 NAT — BEGIN /sbin/iptables -t nat -I POSTROUTING -o eth1 -s 10.0.0.6 -j SNAT --to-source AA.BB.CC.DD #Added for 1:1 NAT - END(здесь eth1 - внешний интерфейс шлюза, 10.0.0.6 - IP-адрес почтового сервера, AA.BB.CC.DD - IP-адрес алиаса на шлюзе)
Не забудьте обеспечить, чтобы эта строка выполнялась при перезагрузке шлюза
Установка mailman
Установим и настроим пакет mailman
Нас предупредят, что Отсутствует список рассылки сайта. Мы его создадим чуть позже.
Т.к. mailman не поддерживает utf8, часть операций с mailman производим с указанием LANG=C
Исправим ошибки (они неизбежны при установке) и проверим:
Сменим права доступа к директории с архивами списков рассылки для доступа к ним через веб:
Вставим запись в таблицу transport postfix
Отредактируем файл /etc/postfix/main.cf
sudo apt-get install mailmanОтветим на вопросы
Поддерживаемые языки:
Выберем русский и английский (en
и ru
)
Язык по умолчанию для Mailman:
ru (Russian)
Нас предупредят, что Отсутствует список рассылки сайта. Мы его создадим чуть позже.
Т.к. mailman не поддерживает utf8, часть операций с mailman производим с указанием LANG=C
Исправим ошибки (они неизбежны при установке) и проверим:
LANG=C sudo check_perms -f LANG=C sudo check_permsМы получим что-то типа такого списка
/var/lib/mailman/mail bad group (has: root, expected list)
/var/lib/mailman/templates bad group (has: root, expected list)
/var/lib/mailman/locks bad group (has: root, expected list)
/var/lib/mailman/logs bad group (has: root, expected list)
/var/lib/mailman/bin bad group (has: root, expected list)
/var/lib/mailman/cgi-bin bad group (has: root, expected list)
/var/lib/mailman/cron bad group (has: root, expected list)
/var/lib/mailman/scripts bad group (has: root, expected list)
/var/lib/mailman/icons bad group (has: root, expected list)
/var/lib/mailman/Mailman bad group (has: root, expected list)
Problems found: 10
Re-run as list (or root) with -f flag to fix
Это нормально, т.к. все это — ссылки.
/var/lib/mailman/templates bad group (has: root, expected list)
/var/lib/mailman/locks bad group (has: root, expected list)
/var/lib/mailman/logs bad group (has: root, expected list)
/var/lib/mailman/bin bad group (has: root, expected list)
/var/lib/mailman/cgi-bin bad group (has: root, expected list)
/var/lib/mailman/cron bad group (has: root, expected list)
/var/lib/mailman/scripts bad group (has: root, expected list)
/var/lib/mailman/icons bad group (has: root, expected list)
/var/lib/mailman/Mailman bad group (has: root, expected list)
Problems found: 10
Re-run as list (or root) with -f flag to fix
Сменим права доступа к директории с архивами списков рассылки для доступа к ним через веб:
sudo chown -R list /var/lib/mailman/archives/* sudo chmod o+x/var/lib/mailman/archives/privateОтредактируем нужные строки в файле /etc/mailman/mm_cfg.py
sudo nano /etc/mailman/mm_cfg.py
DEFAULT_EMAIL_HOST = 'aaa.ru' DEFAULT_URL_HOST = 'lists.aaa.ru' MTA=None # Misnomer, suppresses alias output on newlistПроверим содержимое файла /etc/postfix/master.cf
sudo nano /etc/postfix/master.cfЕсли в нем строка mailman имеет вид
mailman unix - - n - - pipeто изменим ее на
mailman unix - n n - - pipeНастроим apache. Создадим файл /etc/apache2/sites-available/mailman
sudo nano /etc/apache2/sites-available/mailman
<VirtualHost *:80> ServerName lists.aaa.ru Alias /images/ /usr/share/images/ RedirectMatch ^/$ http://lists.aaa.ru/cgi-bin/mailman/listinfo ScriptAlias /mailman/ /usr/lib/cgi-bin/mailman/ ScriptAlias /cgi-bin/mailman/ /usr/lib/cgi-bin/mailman/ <Directory /usr/lib/cgi-bin/mailman/> AllowOverride None Options ExecCGI Order allow,deny Allow from all </Directory> Alias /pipermail/ /var/lib/mailman/archives/public/ <Directory /var/lib/mailman/archives/public> AddDefaultCharset KOI8-R Options Indexes MultiViews FollowSymLinks AllowOverride None Order allow,deny Allow from all </Directory> Alias /archives/ /var/lib/mailman/archives/public/ <Directory /var/lib/mailman/archives/public> AddDefaultCharset KOI8-R DirectoryIndex index.html Options Indexes MultiViews FollowSymLinks AllowOverride None Order allow,deny Allow from all </Directory> CustomLog /var/log/apache2/lists.log combined <Directory /var/lib/mailman/archives/> Options Indexes FollowSymLinks AllowOverride None </Directory> </VirtualHost>и разрешим запуск этого сайта
sudo a2ensite mailman
и перезапустим apache
sudo /etc/init.d/apache2 restartСконфигурируем postfix
Вставим запись в таблицу transport postfix
mysql -u mail_admin -p
Enter password:
Введем пароль
<mail_admin_password>
use mail; INSERT INTO `transport` (`domain`, `transport`) VALUES ('lists.aaa.ru', 'mailman:'); quit;Проверим содержимое файла /etc/postfix/master.cf
sudo nano /etc/postfix/master.cfи убедимся, что он содержит
mailman unix - n n - - pipe flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user}(здесь должно быть две строки)
Отредактируем файл /etc/postfix/main.cf
sudo nano /etc/postfix/main.cfи добавим в него
# For mailman relay_domains = lists.aaa.ru mailman_destination_recipient_limit = 1Теперь перезапустим сервисы и запустим mailman
sudo /etc/init.d/apache2 restart sudo /etc/init.d/postfix reload LANG=C sudo /etc/init.d/mailman start
Создание листа рассылки
Выполним
Добавим в таблицу forwardings базы данных mail следующие записи:
Прочие листы рассылки добавляются аналогично.
LANG=C sudo newlist mailman
Enter the email of the person running the list:
Введем адрес администратора листа рассылки
admin@aaa.ru
Initial mailman password:
Введем пароль, который будет использоваться при администрировании листа рассылки (замените на свой)
<mailman_list_password>
Hit enter to notify mailman owner…
Нажмите Enter.
Добавим в таблицу forwardings базы данных mail следующие записи:
source | destination |
---|---|
mailman@aaa.ru | mailman@lists.aaa.ru |
mailman-admin@aaa.ru | mailman-admin@lists.aaa.ru |
mailman-bounces@aaa.ru | mailman-bounces@lists.aaa.ru |
mailman-confirm@aaa.ru | mailman-confirm@lists.aaa.ru |
mailman-join@aaa.ru | mailman-join@lists.aaa.ru |
mailman-leave@aaa.ru | mailman-leave@lists.aaa.ru |
mailman-owner@aaa.ru | mailman-owner@lists.aaa.ru |
mailman-request@aaa.ru | mailman-request@lists.aaa.ru |
mailman-subscribe@aaa.ru | mailman-subscribe@lists.aaa.ru |
mailman-unsubscribe@aaa.ru | mailman-unsubscribe@lists.aaa.ru |
mysql -u mail_admin -p
Enter password:
Введем пароль
<mail_admin_password>
use mail; INSERT INTO `forwardings` (`source`, `destination`) VALUES ('mailman@aaa.ru', 'mailman@lists.aaa.ru '); INSERT INTO `forwardings` (`source`, `destination`) VALUES ('mailman-admin@aaa.ru', 'mailman-admin@lists.aaa.ru '); INSERT INTO `forwardings` (`source`, `destination`) VALUES ('mailman-bounces@aaa.ru', 'mailman-bounces@lists.aaa.ru '); INSERT INTO `forwardings` (`source`, `destination`) VALUES ('mailman-confirm@aaa.ru', 'mailman-confirm@lists.aaa.ru '); INSERT INTO `forwardings` (`source`, `destination`) VALUES ('mailman-join@aaa.ru', 'mailman-join@lists.aaa.ru '); INSERT INTO `forwardings` (`source`, `destination`) VALUES ('mailman-leave@aaa.ru', 'mailman-leave@lists.aaa.ru '); INSERT INTO `forwardings` (`source`, `destination`) VALUES ('mailman-owner@aaa.ru', 'mailman-owner@lists.aaa.ru '); INSERT INTO `forwardings` (`source`, `destination`) VALUES ('mailman-request@aaa.ru', 'mailman-request@lists.aaa.ru '); INSERT INTO `forwardings` (`source`, `destination`) VALUES ('mailman-subscribe@aaa.ru', 'mailman-subscribe@lists.aaa.ru '); INSERT INTO `forwardings` (`source`, `destination`) VALUES ('mailman-unsubscribe@aaa.ru', 'mailman-unsubscribe@lists.aaa.ru ); quit;Перезапуcтим mailman
LANG=C sudo /etc/init.d/mailman stop LANG=C sudo /etc/init.d/mailman startНам нужно вставить в DNS-зону для нашего домена запись типа
lists CNAME oban.aaa.ru.чтобы у нас был доступ к нашим спискам рассылки через веб.
Не забудьте увеличить порядковый номер в записи SOA зоны
Теперь мы можем зайти с паролем администратора листа mailman браузером на http://lists.aaa.ru для дальнейшей настройки листа рассылки.
Прочие листы рассылки добавляются аналогично.
Установка автоответчика
Создадим файл ./autoresponse следующего содержания (отличие от варианта, лежащего на http://nefaria.com/project_index/autoresponse/ в том, что для совместимости с mailman мы используем -autoresponse вместо +autoresponse):
В конце файла вставляем
Выполняем команды
Если все прошло нормально, Вы получите ответ с темой «Out Of Office» следующего содержания: «Autoresponse enabled for admin@aaa.ru by SASL authenticated user: admin@aaa.ru from: x.x.x.x», где x.x.x.x - IP-адрес хоста, с которого было отправлено письмо.
Теперь при посылке Вам письма все автоматически в ответ будут получать то письмо, которое вы установили в качестве автоответчика, сами письма будут сохраняться у Вас в папке «Входящие» как обычно.
Для того, чтобы убрать сообщение автоответчка, пошлите еще раз любое письмо на адрес <ваш логин>-autoresponse@aaa.ru и Вы получите в ответ письмо с темой «Out Of Office» следующего содержания: «Autoresponse disabled for admin@aaa.ru by SASL authenticated user: admin@aaa.ru from: x.x.x.x», где x.x.x.x - IP-адрес хоста, с которого было отправлено письмо.
Каждому корреспонденту автоответ будет отсылаться не чаще, чем раз в сутки, даже если он пошлет Вам несколько писем.
Письма для включения/выключения автоответчика должны быть посланы с Вашего адреса, иначе они не «сработают».
nano ~/autoresponse
#!/bin/bash #+--------------------------------------------------------+ #|autoresponse 1.6.3 - an autoresponder script for postfix| #| Charles Hamilton - musashi@nefaria.com | #| This program is GNU/GPL software | #+--------------------------------------------------------+ shopt -s -o nounset shopt -s extglob if [ "${#}" -eq "0" ]; then printf "%s\n" "Autoresponse v. 1.6.2" printf "%s\n" "Type -h for help" exit 0 fi declare RECIPIENT="unset" declare SENDER="unset" declare SASL_USERNAME="unset" declare CLIENT_IP="unset" declare AUTHENTICATED="unset" declare AUTORESPONSE_MESSAGE="unset" declare DISABLE_AUTORESPONSE="unset" declare ENABLE_AUTORESPONSE="unset" declare DELETE_AUTORESPONSE="unset" declare SEND_RESPONSE="unset" declare RESPONSES_DIR="/var/spool/autoresponse/responses" declare SENDMAIL="/usr/sbin/sendmail" declare RATE_LOG_DIR="/var/spool/autoresponse/log" declare LOGGER="/usr/bin/logger" #There are two different modes of operation: # MODE="0" represents the actions that can not be executed from the command line # MODE="1" represents the actions that can be executed from the command line declare MODE="0" #Time limit, in seconds that determines how often an #autoresponse will be sent, per e-mail address (3600 = 1 hour, 86400 = 1 day) declare RESPONSE_RATE="86400" while getopts "r:s:S:C:e:d:E:D:h" SWITCH; do case "${SWITCH}" in r) #Set the recipient's address RECIPIENT="`echo ${OPTARG} | tr '[:upper:]' '[:lower:]'`" SEND_RESPONSE="1" ;; s) #Set the sender's address SENDER="`echo ${OPTARG} | tr '[:upper:]' '[:lower:]'`" SEND_RESPONSE="1" ;; S) #If SASL_USERNAME exists then the user was authenticated SASL_USERNAME="${OPTARG}" if [ -z "${SASL_USERNAME}" ]; then AUTHENTICATED="0" else AUTHENTICATED="1" fi ;; C) #IP address of client (sender) CLIENT_IP="${OPTARG}" ;; e) #Set the filename of the user's autoresponse message #This is used for creating/editing new autoresponse messages AUTORESPONSE_MESSAGE="${OPTARG}" MODE="1" ;; d) #Disable an existing autoresponse message DISABLE_AUTORESPONSE="${OPTARG}" MODE="1" ;; E) #Enable an existing autoresponse message ENABLE_AUTORESPONSE="${OPTARG}" MODE="1" ;; D) #Delete an existing autoresponse message DELETE_AUTORESPONSE="${OPTARG}" MODE="1" ;; h|*) #Print the help dialog and exit echo -e "\n${0} [-r {recipient email} -s {sender email} -S {sasl username} -C {client ip}] [-e {email address}] [-d {email address}] [-E {email address}] [-D {email address}] [-h]\n" echo -e " -r, -s, -S, and optionally -C must be used together to specify a recipient, sender, sasl username, and client IP of an autoresponse message." echo -e " Normally you configure these in postfix's \"master.cf\" but they can be used from the terminal as well (only for testing purposes!)." echo -e " If this is executed from a terminal, you'll need to hit CTRL-D when you are finished typing your autoresponse message.\n" echo " -e is used to create a new autoresponse or edit an existing one for the specified user." echo -e " If a disabled autoresponse message exists, it will be ignored and a new message will be created.\n" echo -e " -d is used to disable an existing active autoresponse message.\n" echo " -E is used to enable an existing autoresponse message. If both a disabled AND and an active autoresponse message exist," echo -e " the active message will be overwritten by the disabled one.\n" echo -e " -D is used to delete an existing autoresponse message, it will not delete disabled autoresponse messages.\n" echo -e " -h prints this help menu\n" exit 0 ;; esac done #If a SASL authenticated user wants to set their autoresponse message via e-mail... if [ "${AUTHENTICATED}" = "1" ] && [ "${RECIPIENT/@*/}" = "${SENDER/@*/-autoresponse}" ] && [ "${MODE}" = "0" ]; then if [ -f "${RESPONSES_DIR}/${SENDER}" ]; then #Delete a user's existing autoresponse message. (${0} -D "${SENDER}") if [ ! -f "${RESPONSES_DIR}/${SENDER}" ]; then ${LOGGER} -i -t autoresponse -p mail.notice "Autoresponse disabled for address: ${SENDER} by SASL authenticated user: ${SASL_USERNAME} from: ${CLIENT_IP}" (echo -e "From: ${RECIPIENT}\nTo: ${SENDER}\nSubject: Out of Office\n\n" echo "Autoresponse disabled for ${SENDER} by SASL authenticated user: ${SASL_USERNAME} from: ${CLIENT_IP}") | ${SENDMAIL} -i -f "${RECIPIENT}" "${SENDER}" else ${LOGGER} -i -t autoresponse -p mail.notice "Autoresponse could not be disabled for address: ${SENDER}" fi elif [ ! -f "${RESPONSES_DIR}/${SENDER}" ]; then #Read from STDIN and save this as the user's autoresponse message. #This will overwrite any pre-existing autoresponse messages! cat > "${RESPONSES_DIR}/${SENDER}" if [ -f "${RESPONSES_DIR}/${SENDER}" ]; then ${LOGGER} -i -t autoresponse -p mail.notice "Autoresponse enabled for address: ${SENDER} by SASL authenticated user: ${SASL_USERNAME} from: ${CLIENT_IP}" (echo -e "From: ${RECIPIENT}\nTo: ${SENDER}\nSubject: Out of Office\n\n" echo "Autoresponse enabled for ${SENDER} by SASL authenticated user: ${SASL_USERNAME} from: ${CLIENT_IP}") | ${SENDMAIL} -i -f "${RECIPIENT}" "${SENDER}" else ${LOGGER} -i -t autoresponse -p mail.notice "Autoresponse could not be enabled for address: ${SENDER}" fi fi #Log any unauthenticated shenanigans. We're attempting to prevent two scenarios here: # #(1) A user sends an e-mail to user-autoresponse@domain.tld from user@domain.tld through an open relay # in an unauthorized attempt to set an autoresponse for the real user@domain.tld. The open relay # will relay the message but because it will not authenticate with the mail server for domain.tld # AUTHENTICATED will equal 0 and the user portion of the recipient address will equal user-autoresponse. # Since we do not allow unauthenticated users to set autoresponse messages, we log this attempt as # suspicious and exit cleanly so that postfix doesn't generate a bounce message. # #(2) A user sends e-mail to user-autoresponse@domain.tld from user@domain.tld through a mail server # that requires authentication, (but allows relaying) and has autoresponse configured. This will result in # an autoresponse toggle message being sent to the real user@domain.tld, notifying them that their # autoresponse message has been enabled or disabled when in fact it has not. This scenario is rarer # than the first and it is mainly meant to protect against compromised accounts and/or potential abuse # by legitimate users of the rogue mail server. # elif [ "${AUTHENTICATED}" = "0" ] && [ "${RECIPIENT/@*/}" = "${SENDER/@*/-autoresponse}" ] || [ "${SENDER/@*/-autoresponse}" = "${RECIPIENT/@*/-autoresponse-autoresponse}" ] && [ "${MODE}" = "0" ]; then ${LOGGER} -i -t autoresponse -p mail.warning "Unauthenticated attempt to set autoresponse message for ${SENDER/-autoresponse/} from ${CLIENT_IP}!" exit 0 #Finally, if the user recipient address does not equal user-autoresponse then we assume that it's #just a normal message. We check to see if the recipient has an autoresponse message set; if one #has not already been sent to the sender within our timeframe, we send it and then we deliver the #original message to the original recipient. elif [ "${RECIPIENT/@*/}" != "${SENDER/@*/-autoresponse}" ] && [ "${MODE}" = "0" ]; then rate_log_check() { #Only send one autoresponse per e-mail address per the time limit (in seconds) designated by the RESPONSE_RATE variable if [ -f "${RATE_LOG_DIR}/${RECIPIENT}/${SENDER}" ]; then declare ELAPSED_TIME=`echo $[\`date +%s\` - \`stat -c %X "${RATE_LOG_DIR}/${RECIPIENT}/${SENDER}"\`]` if [ "${ELAPSED_TIME}" -lt "${RESPONSE_RATE}" ]; then ${LOGGER} -i -t autoresponse -p mail.notice "An autoresponse has already been sent from ${RECIPIENT} to ${SENDER} within the last ${RESPONSE_RATE} seconds" SEND_RESPONSE=0 fi fi } if [ -f "${RESPONSES_DIR}/${RECIPIENT}" ]; then rate_log_check #If SEND_RESPONSE still equals "1" after the rate_log_check function, send an autoresponse. if [ "${SEND_RESPONSE}" = "1" ] && [ "${RECIPIENT}" != "${SENDER}" ]; then (cat "${RESPONSES_DIR}/${RECIPIENT}") | sed -e "0,/^$/ { s/^To:.*/To: <${SENDER}>/ }" -e '0,/^$/ { /^Date:/ d }' | ${SENDMAIL} -i -f "${RECIPIENT}" "${SENDER}" mkdir -p "${RATE_LOG_DIR}/${RECIPIENT}" touch "${RATE_LOG_DIR}/${RECIPIENT}/${SENDER}" ${LOGGER} -i -t autoresponse -p mail.notice "Autoresponse sent from ${RECIPIENT} to ${SENDER}" fi fi exec ${SENDMAIL} -i -f "${SENDER}" "${RECIPIENT}" fi #Check to see if we are editing or creating a new autoresponse for a user. #This should only be used from the command line unlike -D, -d, and -E which #could be used via postfix pipe or in other areas where no user interaction #is required. if [ "${AUTORESPONSE_MESSAGE}" != "unset" ] && [ "${MODE}" = "1" ]; then #Check to see if an autoresponse message exists for the email address specified by the "AUTORESPONSE_MESSAGE" parameter, if one exists #then edit the existing one, if one does not exist, create a new one. This action will ignore any disabled autoresponse messages. if [ -f "${RESPONSES_DIR}/${AUTORESPONSE_MESSAGE}" ]; then vi "${RESPONSES_DIR}/${AUTORESPONSE_MESSAGE}" elif ! [ -f "${RESPONSES_DIR}/${AUTORESPONSE_MESSAGE}" ]; then vi "${RESPONSES_DIR}/${AUTORESPONSE_MESSAGE}" if [ -f "${RESPONSES_DIR}/${AUTORESPONSE_MESSAGE}" ]; then #Insert our mail headers; people who will be setting autoresponses from the command line #hopefully will know better than to screw with these when editing an existing autoresponse. sed -i "1i\From: ${AUTORESPONSE_MESSAGE}\nTo: THIS GETS REPLACED\nSubject: Out Of Office\n\n" "${RESPONSES_DIR}/${AUTORESPONSE_MESSAGE}" fi fi if [ -f "${RESPONSES_DIR}/${AUTORESPONSE_MESSAGE}" ]; then chown autoresponse.autoresponse "${RESPONSES_DIR}/${AUTORESPONSE_MESSAGE}" chmod 600 "${RESPONSES_DIR}/${AUTORESPONSE_MESSAGE}" else echo "Editing ${RESPONSES_DIR}/${AUTORESPONSE_MESSAGE} aborted!" exit 1 fi #Are we disabling an existing autoresponse message? elif [ "${DISABLE_AUTORESPONSE}" != "unset" ] && [ "${MODE}" = "1" ]; then if [ -f "${RESPONSES_DIR}/${DISABLE_AUTORESPONSE}" ]; then mv -i "${RESPONSES_DIR}/${DISABLE_AUTORESPONSE}" "${RESPONSES_DIR}/${DISABLE_AUTORESPONSE}_DISABLED" elif ! [ -f "${RESPONSES_DIR}/${DISABLE_AUTORESPONSE}" ]; then echo "${RESPONSES_DIR}/${DISABLE_AUTORESPONSE} does not exist thus, it cannot be disabled!" exit 1 fi #Are we enabling an existing autoresponse message? elif [ "${ENABLE_AUTORESPONSE}" != "unset" ] && [ "${MODE}" = "1" ]; then if [ -f "${RESPONSES_DIR}/${ENABLE_AUTORESPONSE}_DISABLED" ]; then mv -i "${RESPONSES_DIR}/${ENABLE_AUTORESPONSE}_DISABLED" "${RESPONSES_DIR}/${ENABLE_AUTORESPONSE}" elif ! [ -f "${RESPONSES_DIR}/${ENABLE_AUTORESPONSE}_DISABLED" ]; then echo "There is no disabled autoresponse for ${ENABLE_AUTORESPONSE}" exit 1 fi #Are we deleting an existing autoresponse message (this does not delete disabled autoresponse messages)? elif [ "${DELETE_AUTORESPONSE}" != "unset" ] && [ "${MODE}" = "1" ]; then if [ -f "${RESPONSES_DIR}/${DELETE_AUTORESPONSE}" ]; then rm "${RESPONSES_DIR}/${DELETE_AUTORESPONSE}" elif ! [ -f "${RESPONSES_DIR}/${DELETE_AUTORESPONSE}" ]; then echo "${RESPONSES_DIR}/${DELETE_AUTORESPONSE} does not exist thus, it cannot be deleted!" exit 1 fi fi #===КОНЕЦ ФАЙЛА===Выполним
sudo useradd -d /var/spool/autoresponse -s `which nologin` autoresponse sudo mkdir -p /var/spool/autoresponse/log /var/spool/autoresponse/responses sudo cp ~/autoresponse /usr/local/sbin/ sudo chown -R autoresponse.autoresponse /var/spool/autoresponse sudo chmod -R 0770 /var/spool/autoresponseОткроем файл /etc/postfix/master.cf
sudo nano /etc/postfix/master.cfи найдем строку
smtp inet n - - - - smtpdсразу после нее вставим
-o content_filter=autoresponder:dummy(она должна начинаться хотя бы с одного пробела)
В конце файла вставляем
autoresponder unix - n n - - pipe flags=Fq user=autoresponse argv=/usr/local/sbin/autoresponse -s ${sender} -r ${recipient} -S ${sasl_username} -C ${client_address}(это две строки, причем вторая строка должна начинаться хотя бы с одного пробела)
Выполняем команды
sudo postconf -e 'autoresponder_destination_recipient_limit = 1' sudo postconf -e 'recipient_delimiter = - 'и перезагружаем postfix
sudo /etc/init.d/postfix restartТеперь для того, чтобы при Вашем отсутствии на работе (например, отпуск) всем, кто послал Вам письмо, автоматически отправлялось сообщение о Вашем отсутствии, нужно послать по адресу <ваш логин>-autoresponse@aaa.ru то письмо, которое Вы хотите установить в качестве автоответчика, например admin-autoresponse@aaa.ru (здесь и далее замените aaa.ru на Ваш домен).
Если все прошло нормально, Вы получите ответ с темой «Out Of Office» следующего содержания: «Autoresponse enabled for admin@aaa.ru by SASL authenticated user: admin@aaa.ru from: x.x.x.x», где x.x.x.x - IP-адрес хоста, с которого было отправлено письмо.
Теперь при посылке Вам письма все автоматически в ответ будут получать то письмо, которое вы установили в качестве автоответчика, сами письма будут сохраняться у Вас в папке «Входящие» как обычно.
Для того, чтобы убрать сообщение автоответчка, пошлите еще раз любое письмо на адрес <ваш логин>-autoresponse@aaa.ru и Вы получите в ответ письмо с темой «Out Of Office» следующего содержания: «Autoresponse disabled for admin@aaa.ru by SASL authenticated user: admin@aaa.ru from: x.x.x.x», где x.x.x.x - IP-адрес хоста, с которого было отправлено письмо.
Каждому корреспонденту автоответ будет отсылаться не чаще, чем раз в сутки, даже если он пошлет Вам несколько писем.
Письма для включения/выключения автоответчика должны быть посланы с Вашего адреса, иначе они не «сработают».
Установка munin
Установим нужные пакеты
Отредактируем файл
sudo apt-get install munin-node munin logtail(если у Вас уже установлен munin на каком-нибудь сервере, то установите только munin-node)
Отредактируем файл
sudo nano /etc/apache2/conf.d/muninи поменяем (если необходимо) строку
# Allow from localhost 127.0.0.0/8 ::1на
Allow from allПерезапустим apache
sudo /etc/init.d/apache2 restartНас интересуют более подробные графики того, что происходит у нас с почтой. Поэтому создаем файлы
sudo nano /usr/share/munin/plugins/amavis-debian
#!/bin/sh # # Plugin to monitor the amavis mail filter for Debian # (based upon a plugin authored by Geoffroy Desvernay) # # This plugin is built and tested on Debian Etch using: # munin 1.2.5-1 # amavisd-new 2.4.2-6.1 # # With some minor modification it should also work on non-debian systems # This, however, is up to you # # Munin graph will sum up: Passed CLEAN, Blocked VIRUS, Blocked SPAM, Other # # Parameters understood: # config (required) # autoconf (optional) # # Config variables: # AMAVIS_LOG - file where amavis logs are written # STATEFILE - file which is needed to keep track of AMAVIS_LOG # LOGTAIL - location of logtail # BC - location of bc # # Enjoy! # Fili Wiese # AMAVIS_LOG=${logfile:-/var/log/mail.log} STATEFILE=/var/lib/munin/plugin-state/amavis.offset LOGTAIL=${logtail:-`which logtail`} BC=${bc:-`which bc`} mktempfile () { mktemp } if [ "$1" = "autoconf" ]; then if [ -f "${AMAVIS_LOG}" -a -n "${LOGTAIL}" -a -x "${LOGTAIL}" -a -n "${BC}" -a -x "${BC}" ] ; then echo yes exit 0 else echo no exit 1 fi fi if [ "$1" = "config" ]; then echo 'graph_title Amavis filter statistics' echo 'graph_category postfix' # echo 'graph_order total clean spam virus other' echo 'graph_order sent clean spammy header spam virus' echo 'graph_vlabel Mails filtered' echo 'graph_scale no' # echo 'total.label Total' # echo 'total.draw AREA' # echo 'total.colour DDDDDD' echo 'sent.label Sent BYPASS' echo 'sent.draw LINE1' echo 'sent.colour 0099FF' echo 'clean.label Passed CLEAN' echo 'clean.draw LINE1' echo 'clean.colour 32FA00' echo 'spammy.label Passed SPAMMY' echo 'spammy.draw LINE1' echo 'spammy.colour FFCC00' echo 'header.label Passed BAD-HEADER' echo 'header.draw LINE1' echo 'header.colour 99CC00' echo 'spam.label Detected SPAM' echo 'spam.draw LINE1' echo 'spam.colour FF0000' echo 'virus.label Blocked VIRUS' echo 'virus.draw LINE1' echo 'virus.colour 880088' # echo 'other.label Other' # echo 'other.draw LINE1' # echo 'other.colour 0099FF' exit 0 fi sent=0 clean=0 virus=0 spam=0 spammy=0 header=0 other=0 total=0 ARGS=0 `$LOGTAIL /etc/hosts 2>/dev/null >/dev/null` if [ $? = 66 ]; then if [ ! -n "$logtail" ]; then ARGS=1 fi fi TEMP_FILE=`mktempfile munin-amavis.XXXXXX` if [ -n "$TEMP_FILE" -a -f "$TEMP_FILE" ] then if [ $ARGS != 0 ]; then $LOGTAIL ${AMAVIS_LOG} $STATEFILE | grep 'amavis\[.*\]:' | grep -v 'TIMED OUT' > ${TEMP_FILE} else $LOGTAIL ${AMAVIS_LOG} $STATEFILE | grep 'amavis\[.*\]:' | grep -v 'TIMED OUT' > ${TEMP_FILE} fi # total=`cat ${TEMP_FILE} | wc -l` sent=`grep 'Passed CLEAN, MYUSERS' ${TEMP_FILE} | wc -l` clean=`grep 'Passed CLEAN,' ${TEMP_FILE} | wc -l` clean=`echo ${clean}-${sent} | ${BC}` spammy=`grep 'Passed SPAMMY,' ${TEMP_FILE} | wc -l` header=`grep 'Passed BAD-HEADER' ${TEMP_FILE} | wc -l` spam=`grep 'Blocked SPAM,' ${TEMP_FILE} | wc -l` virus=`grep 'INFECTED' ${TEMP_FILE} | wc -l` # other=`echo ${total}-${clean}-${virus}-${other}-${spam} | ${BC}` /bin/rm -f $TEMP_FILE fi echo "sent.value ${sent}" echo "clean.value ${clean}" echo "spammy.value ${spammy}" echo "header.value ${header}" echo "spam.value ${spam}" echo "virus.value ${virus}" #echo "other.value ${other}" #echo "total.value ${total}"
udo nano /usr/share/munin/plugins/amavis_
#!/usr/bin/perl -w # # Plugin to monitor amavisd-new statistics. Values are retrieved by querying # the BerkeleyDB database 'snmp.db', in which amavisd-new stores its # statistics. # # The plugin requires the Perl module BerkeleyDB. # # To use, setup /etc/munin/plugin-conf.d/amavis e.g. as follows: # # [amavis_*] # env.amavis_db_home /var/lib/amavis/db # user amavis # # Where env.amavis_db_home is the path to the amavisd-new BerkeleyDB files # (/var/amavis/db by default). # # Then create symlinks in the Munin plugin directory named "amavis_time", # "amavis_cache" and "amavis_content", or use munin-node-configure. # # Parameters: # # config # autoconf # suggest # # Config variables: # # amavis_db_home - where the amavisd-new berkeley db files are located # # Magic markers #%# family=auto #%# capabilities=autoconf #%# capabilities=suggest use strict; no warnings 'uninitialized'; use BerkeleyDB; my($dbfile) = 'snmp.db'; my($db_home) = # DB databases directory defined $ENV{'amavis_db_home'} ? $ENV{'amavis_db_home'} : '/var/amavis/db'; if ($ARGV[0] and $ARGV[0] eq "autoconf") { if (-x "/usr/sbin/amavisd-agent") { print "yes\n"; exit 0; } else { print "no (/usr/sbin/amavisd-agent not found or not executable)\n"; exit 1; } } elsif ($ARGV[0] and $ARGV[0] eq "suggest") { print "time\n"; print "cache\n"; print "content\n"; exit 0; } my $stats_type = ""; if ($0 =~ /^(?:|.*\/)amavis_(cache|content|time)$/) { $stats_type = $1; } else { print "You need to create a symlink to this plugin called either amavis_cache, amavis_time or amavis_content to be able to use it.\n"; exit 2; } if ($ARGV[0] and $ARGV[0] eq "config") { if ($stats_type eq "cache") { print "graph_title Amavis cache hit / miss ratio\n"; print "graph_args --lower-limit 0 --upper-limit 100 --rigid\n"; print "graph_category mail\n"; print "graph_info The ratio of cache hits and misses for AMaViSd-new.\n"; print "graph_order hits misses\n"; print "graph_scale no\n"; print "graph_vlabel %\n"; print "hits.label Cache hits\n"; print "hits.draw AREA\n"; print "hits.max 100\n"; print "hits.min 0\n"; print "misses.label Cache misses\n"; print "misses.draw STACK\n"; print "misses.max 100\n"; print "misses.min 0\n"; } elsif ($stats_type eq "content") { print "graph_title Amavis scanned mails\n"; print "graph_category mail\n"; print "graph_period minute\n"; print "graph_vlabel msgs / \${graph_period}\n"; foreach my $type (qw(total clean spam spammy virus)) { print "$type.label " . ucfirst($type) . " mails \n"; print "$type.type DERIVE\n"; print "$type.min 0\n"; } print "clean.info Legitimate mail.\n"; print "spammy.info Mails with a spam score above the tag2 level.\n"; print "spam.info Mails with a spam score above the kill level for spam.\n"; print "virus.info Mails with a virus.\n"; print "total.info Total number of scanned mails.\n"; } elsif ($stats_type eq "time") { print "graph_title Amavis average scan time\n"; print "graph_info Average time spent in each phase of the mail scanning process, per mail.\n"; print "graph_category mail\n"; print "graph_vlabel sec / mail\n"; print "graph_scale no\n"; print "msgs.label Total number of messages\n"; print "msgs.graph no\n"; print "msgs.type DERIVE\n"; print "msgs.min 0\n"; foreach my $type (qw(decoding receiving sending spamcheck viruscheck total)) { print "${type}.label " . ucfirst($type) . "\n"; print "${type}.type DERIVE\n"; print "${type}.min 0\n"; print "${type}.cdef ${type},1000,/,msgs,/\n"; } } exit 0; } my ($env, $db, @dbstat, $cursor); @dbstat = stat("$db_home/$dbfile"); my $errn = @dbstat ? 0 : 0+$!; $errn == 0 or die "stat $db_home/$dbfile: $!"; $env = BerkeleyDB::Env->new( -Home => $db_home, -Flags => DB_INIT_CDB | DB_INIT_MPOOL, -ErrFile => \*STDOUT, -Verbose => 1, ); defined $env or die "BDB no env: $BerkeleyDB::Error $!"; $db = BerkeleyDB::Hash->new(-Filename => $dbfile, -Env => $env); defined $db or die "BDB no db: $BerkeleyDB::Error $!"; my %values = (); my ($eval_stat, $stat, $key, $val); $cursor = $db->db_cursor; # obtain read lock defined $cursor or die "db_cursor error: $BerkeleyDB::Error"; while (($stat = $cursor->c_get($key, $val, DB_NEXT)) == 0) { $values{$key} = $val; } $stat == DB_NOTFOUND or die "c_get: $BerkeleyDB::Error $!"; $cursor->c_close == 0 or die "c_close error: $BerkeleyDB::Error"; $cursor = undef; $eval_stat = $@; if ($eval_stat ne '') { chomp($eval_stat); die "BDB $eval_stat\n"; } for my $k (sort keys %values) { if ($values{$k} =~ /^(?:C32|C64) (.*)\z/) { $values{$k} = $1; } } if ($stats_type eq "cache") { my $hits = $values{'CacheHits'}; my $misses = $values{'CacheMisses'}; my $misses_ratio = $misses * 100.00 / ($hits + $misses); my $hits_ratio = $hits * 100.00 / ($hits + $misses); printf("hits.value %.1f\n", $hits_ratio); printf("misses.value %.1f\n", $misses_ratio); } elsif ($stats_type eq "content") { printf("total.value %d\n", $values{'InMsgs'}); my $clean = $values{'ContentCleanMsgs'}; if (defined($values{'ContentCleanTagMsgs'})) { $clean += $values{'ContentCleanTagMsgs'}; } printf("clean.value %d\n", $clean); printf("spam.value %d\n", $values{'ContentSpamMsgs'}); printf("spammy.value %d\n", $values{'ContentSpammyMsgs'}); printf("virus.value %d\n", $values{'ContentVirusMsgs'}); } elsif ($stats_type eq "time") { printf("decoding.value %d\n", $values{'TimeElapsedDecoding'}); printf("receiving.value %d\n", $values{'TimeElapsedReceiving'}); printf("sending.value %d\n", $values{'TimeElapsedSending'}); printf("spamcheck.value %d\n", $values{'TimeElapsedSpamCheck'}); printf("viruscheck.value %d\n", $values{'TimeElapsedVirusCheck'}); printf("total.value %d\n", $values{'TimeElapsedTotal'}); printf("msgs.value %d\n", $values{'InMsgs'}); } $db->db_close == 0 or die "BDB db_close error: $BerkeleyDB::Error $!";
sudo nano /usr/share/munin/plugins/postgrey
#!/bin/bash # # Plugin to monitor incoming Postgrey # # Parameters understood: # # config (required) # autoconf (optional) # mktempfile () { mktemp -t } MAIL_LOG=${logfile:-/var/log/mail.log} STATEFILE=/var/lib/munin/plugin-state/postgrey.offset LOGTAIL=${logtail:-`which logtail`} if [ "$1" = "autoconf" ]; then if [ -f "${MAIL_LOG}" -a -n "${LOGTAIL}" -a -x "${LOGTAIL}" ] ; then echo yes exit 0 else echo no exit 1 fi fi if [ "$1" = "config" ]; then echo 'graph_title Postgrey daily filtering' echo 'graph_order delayed passed whitelisted' echo 'graph_category mail' echo 'graph_vlabel Count' echo 'graph_scale no' ## echo 'graph_args --base 1000 -l 0' echo 'delayed.label delayed' # echo 'delayed.type DERIVE' echo 'passed.label passed' # echo 'passed.type DERIVE' echo 'whitelisted.label whitelisted' # echo 'whitelisted.type DERIVE' exit 0 fi delayed=0 passed=0 whitelisted=0 ARGS=0 `$LOGTAIL /etc/hosts 2>/dev/null >/dev/null` if [ $? = 66 ]; then if [ ! -n "$logtail" ]; then ARGS=1 fi fi TEMP_FILE=`mktempfile munin-postgrey.XXXXXX` if [ -n "$TEMP_FILE" -a -f "$TEMP_FILE" ] then if [ $ARGS != 0 ]; then $LOGTAIL ${MAIL_LOG} $STATEFILE | grep 'post[fix|grey]' > ${TEMP_FILE} else $LOGTAIL ${MAIL_LOG} $STATEFILE | grep 'post[fix|grey]' > ${TEMP_FILE} fi delayed=`grep 'Recipient address rejected.*Greylisted' ${TEMP_FILE} | wc -l` # passed=`grep 'postgrey\[[0-9]*\]: delayed [0-9]* seconds:' ${TEMP_FILE} | wc -l` passed=`grep 'postgrey\[[0-9]*\]: action=pass' ${TEMP_FILE} | wc -l` whitelisted=`grep 'postgrey\[[0-9]*\]: whitelisted:' ${TEMP_FILE} | wc -l` /bin/rm -f $TEMP_FILE fi echo "delayed.value ${delayed}" echo "passed.value ${passed}" echo "whitelisted.value ${whitelisted}"
sudo nano /usr/share/munin/plugins/postfix_filtered_awk
#!/bin/bash # # Plugin to monitor incoming Postfix mail. # # Parameters understood: # # config (required) # autoconf (optional) # # requires logtail # If you are using a postfix policy daemon (such as policyd) to track certain block conditions, place a line # in your /etc/munin/plugin-conf.d/munin-node like: # # [postfix_filtered] # env.policy my policy string # # When env.policy is set, this plugin will match the string you supply as env.policy and return the number of instances # of that string as an output called "policy.value". # # If you are NOT using a postfix policy daemon, as above, use the line # # [postfix_filtered] # env.policy none # # and this plugin will suppress output of policy.value POLICY='' [ "${policy}" = 'none' ] || POLICY="${policy}" export POLICY #LOGDIR=${logdir:-/var/log/mail} #MAIL_LOG=$LOGDIR/${logfile:-info} MAIL_LOG=/var/log/mail.info LOGTAIL=${logtail:-`which logtail`} STATEFILE=/var/lib/munin/plugin-state/postfix_mailfiltered_test.offset if [ "$1" = "autoconf" ]; then if [ -f "${MAIL_LOG}" -a -n "${LOGTAIL}" -a -x "${LOGTAIL}" ] ; then echo yes exit 0 else echo no exit 1 fi fi if [ "$1" = "config" ]; then echo 'graph_title Postfix message filtering' echo 'graph_category mail' echo 'graph_vlabel Mails per second' # echo 'graph_args --base 1000 --logarithmic' echo 'graph_args --base 1000 -l 0' if [ -z "$POLICY" ] then echo 'graph_order rbl helo client sender recipient relay allowed' else echo 'graph_order rbl policy helo client sender recipient relay allowed' echo 'policy.label policy blocked' echo 'policy.min 0' echo 'policy.draw LINE1' echo 'policy.type ABSOLUTE' fi echo 'allowed.draw LINE2' echo 'allowed.type ABSOLUTE' echo 'allowed.colour 00ff00' echo 'rbl.draw LINE2' echo 'rbl.type ABSOLUTE' echo 'rbl.colour 1010ff' for i in helo client sender recipient relay; do echo "$i.min 0" echo "$i.type ABSOLUTE" echo "$i.draw LINE1"; done echo 'allowed.label allowed' echo 'rbl.label RBL blocked' echo 'helo.label HELO rejected' echo 'client.label Client rejected' echo 'sender.label Sender rejected' echo 'recipient.label recipient unknown' echo 'relay.label relay denied' exit 0 fi $LOGTAIL ${MAIL_LOG} $STATEFILE | \ awk 'BEGIN { na= 0; nb= 0; nc= 0; nd= 0; ne= 0; nf= 0; ng= 0; nh= 0 ; st= ENVIRON["POLICY"] } { if (index($0, "queued as")) { na++ } else if (index($0, "Relay access denied")) { nb++ } else if (index($0, "blocked using")) { nc++ } else if (index($0, "Helo command rejected")) { nd++ } else if (index($0, "Client host rejected")) { ne++ } else if (index($0, "Sender address rejected")) { nf++ } else if (index($0, "Recipient address rejected")) { ng++ } else if (st && index($0, st)) { nh++ } } END { print "allowed.value " na"\nrelay.value " nb"\nrbl.value " nc"\nhelo.value " nd"\nclient.value " ne"\nsender.value " nf"\nrecipient.value " ng ; if (st) print "policy.value " nh }'Сделаем их исполняемыми
cd /usr/share/munin/plugins sudo chmod a+x amavis_ amavis-debian postgrey postfix_filtered_awk cd ~И создадим нужные ссылки
sudo ln -s /usr/share/munin/plugins/amavis_ /etc/munin/plugins/amavis_cache sudo ln -s /usr/share/munin/plugins/amavis_ /etc/munin/plugins/amavis_content sudo ln -s /usr/share/munin/plugins/amavis_ /etc/munin/plugins/amavis_time sudo ln -s /usr/share/munin/plugins/amavis-debian /etc/munin/plugins/amavis-debian sudo ln -s /usr/share/munin/plugins/postgrey /etc/munin/plugins/postgrey sudo ln -s /usr/share/munin/plugins/postfix_mailstats /etc/munin/plugins/postfix_mailstats sudo ln -s /usr/share/munin/plugins/postfix_filtered_awk /etc/munin/plugins/postfix_filtered_awk sudo ln -s /usr/share/munin/plugins/fail2ban /etc/munin/plugins/fail2banОтредактируем файл /etc/munin/plugin-conf.d/munin-node
sudo nano /etc/munin/plugin-conf.d/munin-nodeи вставим в него строки
[amavis-debian] user root group adm [postgrey] group adm [amavis_*] env.amavis_db_home /var/lib/amavis/db user amavis [postfix_mailstats] group adm [postfix_filtered_awk] group adm [fail2ban] user rootПерезапустим munin-node
service munin-node restartи через 5-10 минут получим графики. Они обновляются раз в пять минут.
Заключение
Все установленные пакеты находятся в работоспособном состоянии, причем
уровень безопасности вполне достаточен. Дальнейшую настройку параметров
всех пакетов и (при необходимости) ужесточение мер безопасности
проводите, руководствуясь доступными в Интернет рекомендациями и
описаниями соответствующих пакетов.
Имеющиеся проблемы
При полной установке почтового сервера по этому документу есть следующие нерешенные проблемы:
1. Установленный автоответчик не дает возможности работать обходу проверки на спам для исходящих писем, т.к. не срабатывает
1. Установленный автоответчик не дает возможности работать обходу проверки на спам для исходящих писем, т.к. не срабатывает
$policy_bank{'MYUSERS'}
в amavis. Соответственно, munin не считает отосланные наружу письма. Решения пока нет.
Приложения
Приложение 1 — управление пользователями через веб
ВНИМАНИЕ! Это только примеры, используйте их на свой страх и риск. Ни в коем случае не открывайте общий доступ к этим скриптам!
Создадим новую директорию:
sudo mkdir /var/www/controlОтредактируем файл
sudo nano /etc/apache2/sites-available/defaultи вставим туда строки
Alias /control /var/www/control <Directory /var/www/control> AllowOverride All </Directory>Отредактируем файл
sudo nano /etc/apache2/sites-available/default-sslи вставим туда строки
Alias /control /var/www/control <Directory /var/www/control> Options Indexes MultiViews FollowSymLinks AllowOverride All </Directory>Создадим файл
sudo nano /var/www/control/.htaccessи добавим в него строки
AuthType Basic AuthName "Restricted access" AuthUserFile /var/www/control/.htpasswd require valid-user SSLOptions +StrictRequire SSLRequireSSL SSLRequire %{HTTP_HOST} eq "oban.aaa.ru" ErrorDocument 403 https://oban.aaa.ru Options +FollowSymLinks(замените oban.aaa.ru на имя своего сервера)
Мы, во-первых, разрешаем доступ к этой директории только для пользователей, чьи имена и пароли записаны в файле /var/www/control/.htpasswd (мы сейчас его создадим) и, во-вторых, требуем, чтобы доступ к этим скриптам шел только с использованием ssl.
Дадим команду
htpasswd -c /var/www/control/.htpasswd admin
New password:
Введем пароль пользователя admin, которому мы даем доступ к скриптам
Re-type new password:
Повторим тот же пароль.
После этого у нас в директории /var/www/control/ появится файл .htpasswd, содержащий в зашифрованном виде наш пароль.
Создадим файл
sudo nano /var/www/control/index.htmlследующего содержания
<html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> <BODY BGCOLOR="#ffffff" text="#000000" link="#000000" vlink="#000000" alink="#000000"> <CENTER> <p><b>Управление пользователями почты</b></p> </center> <table> <tr><td valign=top><p><b>Новый пользователь</b></p> <form method=post action=control.php> e-mail пользователя: <input type="text" name="email" value="" size="50"><br> Пароль пользователя: <input type="password" name="password" value="" size="50"><br> Повторите пароль: <input type="password" name="password1" value="" size="50"><br> Квота пользователя: <input type="text" name="quota" value="0" size="50"><br> <input type="hidden" name="op" value="nu"> <input type="submit" value="New user" class="control"> </form></td> <td valign=top><p><b>Удаление пользователя</b></p> <form method=post action=control.php> e-mail пользователя: <input type="text" name="email" value="" size="50"><br> <input type="hidden" name="op" value="du"> <input type="submit" value="Delete user" class="control"> </form></td></tr> <tr><td valign=top><p><b>Задание пароля пользователя</b></p> <form method=post action=control.php> e-mail пользователя:<input type="text" name="email" value="" size="50"><br> Пароль пользователя: <input type="password" name="password" value="" size="50"><br> Повторите пароль: <input type="password" name="password1" value="" size="50"><br> <input type="hidden" name="op" value="pw"> <input type="submit" value="Set password" class="control"> </form></td></tr> <tr><td valign=top><p><b>Задание алиаса пользователя</b></p> <form method=post action=control.php> e-mail пользователя: <input type="text" name="destination" value="" size="50"><br> Алиас пользователя: <input type="text" name="source" value="" size="50"><br> <input type="hidden" name="op" value="na"> <input type="submit" value="Set alias" class="control"> </form></td> <td valign=top><p><b>Удаление алиаса пользователя</b></p> <form method=post action=control.php> Алиас пользователя: <input type="text" name="source" value="" size="50"><br> <input type="hidden" name="op" value="da"> <input type="submit" value="Delete alias" class="control"> </form></td></tr> <tr><td valign=top><p><b>Задание транспорта</b></p> <form method=post action=control.php> Источник: <input type="text" name="source" value="" size="50"><br> Транспорт: <input type="text" name="destination" value="" size="50"><br> <input type="hidden" name="op" value="nt"> <input type="submit" value="Set transport" class="control"> </form></td> <td valign=top><p><b>Удаление транспорта</b></p> <form method=post action=control.php> Источник: <input type="text" name="source" value="" size="50"><br> <input type="hidden" name="op" value="dt"> <input type="submit" value="Delete transport" class="control"> </form></td> <tr><td valign=top><p><b>Задание виртуального домена</b></p> <form method=post action=control.php> Виртуальный домен: <input type="text" name="source" value="" size="50"><br> <input type="hidden" name="op" value="nd"> <input type="submit" value="Set domain" class="control"> </form></td> <td valign=top><p><b>Удаление виртуального домена</b></p> <form method=post action=control.php> Виртуальный домен: <input type="text" name="source" value="" size="50"><br> <input type="hidden" name="op" value="dd"> <input type="submit" value="Delete domain" class="control"> </form></td></tr> </table> <BODY> </HTML> </body></html>Создадим файл
sudo nano /var/www/control/control.phpследующего содержания
<?php $headers = getallheaders(); $mysql_host="127.0.0.1"; $mysql_user = "mail_admin"; $mysql_password ="<mail_admin_password>"; $mydb_name = "mail"; $password=$_POST["password"]; $password1=$_POST["password1"]; $email=strtolower($_POST["email"]); $quota=$_POST["quota"]; $source=strtolower($_POST["source"]); $destination=strtolower($_POST["destination"]); $op=$_POST["op"]; $link = mysql_connect($mysql_host, $mysql_user, $mysql_password) or die("Could not connect : " . mysql_error()); mysql_select_db($mydb_name) or die("Could not select database"); switch ($op) { case "nu": if(!isemail($email)) { print <<< INVALIDEMAIL <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Введенный email некорректен. </body></html> INVALIDEMAIL; mysql_close($link); exit(1); } $query ="SELECT * FROM users WHERE email='$email'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); $row=mysql_fetch_array($result); if($row) { print <<< USEREXISTS <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Пользователь с указанным email уже существует. </body></html> USEREXISTS; mysql_close($link); exit(1); } if($password<>$password1) { print <<< WRONGPASS <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Введенные пароли не совпадают. </body></html> WRONGPASS; mysql_close($link); exit(1); } $query ="INSERT INTO users (email, password, quota) VALUES ('$email', ENCRYPT('$password'), '$quota');"; $result=mysql_query($query) or die("Query failed : " . mysql_error()); if($result) { print <<< USERADDED <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Пользователь добавлен. </body></html> USERADDED; mysql_close($link); exit(1); } break; case "du": $query ="SELECT * FROM users WHERE email='$email'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); $row=mysql_fetch_array($result); if(!$row) { print <<< NOSUCHUSER <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Пользователя с указанным email не существует. </body></html> NOSUCHUSER; mysql_close($link); exit(1); } $query ="DELETE FROM users WHERE email='$email'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); print <<< USERDELETED <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Пользователь удален. </body></html> USERDELETED; mysql_close($link); exit(1); break; case "pw": $query ="SELECT * FROM users WHERE email='$email'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); $row=mysql_fetch_array($result); if(!$row) { print <<< NOSUCHUSERP <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Пользователь с указанным email не существует. </body></html> NOSUCHUSERP; mysql_close($link); exit(1); } if($password<>$password1) { print <<< WRONGPASSP <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Введенные пароли не совпадают. </body></html> WRONGPASSP; mysql_close($link); exit(1); } $query ="UPDATE users SET password = ENCRYPT('$password') WHERE email='$email';"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); if($result) { print <<< PASSWDSET <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Новый пароль установлен. </body></html> PASSWDSET; mysql_close($link); exit(1); } break; case "na": if(!isemail($source)) { print <<< INVALIDSRC <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Введенный алиас некорректен. </body></html> INVALIDSRC; mysql_close($link); exit(1); } if(!isemail($destination)) { print <<< INVALIDDST <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Введенный адрес пересылки некорректен. </body></html> INVALIDDST; mysql_close($link); exit(1); } $query ="SELECT * FROM forwardings WHERE source='$source'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); $row=mysql_fetch_array($result); if($row) { print <<< ALIASEXISTS <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Указанный алиас уже существует. </body></html> ALIASEXISTS; mysql_close($link); exit(1); } $query ="INSERT INTO forwardings (source, destination) VALUES ('$source', '$destination');"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); if($result) { print <<< ALIASADDED <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Алиас добавлен. </body></html> ALIASADDED; mysql_close($link); exit(1); } break; case "da": $query ="SELECT * FROM forwardings WHERE source='$source'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); $row=mysql_fetch_array($result); if(!$row) { print <<< NOSUCHALIAS <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Указанного алиаса не существует. </body></html> NOSUCHALIAS; mysql_close($link); exit(1); } $query ="DELETE FROM forwardings WHERE source='$source'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); print <<< ALIASDELETED <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Алиас удален. </body></html> ALIASDELETED; mysql_close($link); exit(1); break; case "nt": $query ="SELECT * FROM transport WHERE domain='$source'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); $row=mysql_fetch_array($result); if($row) { print <<< TRANSPEXISTS <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Указанный транспорт уже существует. </body></html> TRANSPEXISTS; mysql_close($link); exit(1); } $query ="INSERT INTO transport (domain, transport) VALUES ('$source', '$destination');"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); if($result) { print <<< TRANSPADDED <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Транспорт добавлен. </body></html> TRANSPADDED; mysql_close($link); exit(1); } break; case "dt": $query ="SELECT * FROM transport WHERE domain='$source'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); $row=mysql_fetch_array($result); if(!$row) { print <<< NOSUCHTRANSP <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Указанного транспорта не существует. </body></html> NOSUCHTRANSP; mysql_close($link); exit(1); } $query ="DELETE FROM transport WHERE domain='$source'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); print <<< TRANSPDELETED <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Транспорт удален. </body></html> TRANSPDELETED; mysql_close($link); exit(1); break; case "nd": $query ="SELECT * FROM domains WHERE domain='$source'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); $row=mysql_fetch_array($result); if($row) { print <<< DOMAINEXISTS <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Указанный домен уже существует. </body></html> DOMAINEXISTS; mysql_close($link); exit(1); } $query ="INSERT INTO domains (domain) VALUES ('$source');"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); if($result) { print <<< DOMAINADDED <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Домен добавлен. </body></html> DOMAINADDED; mysql_close($link); exit(1); } break; case "dd": $query ="SELECT * FROM domains WHERE domain='$source'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); $row=mysql_fetch_array($result); if(!$row) { print <<< NOSUCHDOMAIN <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Указанного домена не существует. </body></html> NOSUCHDOMAIN; mysql_close($link); exit(1); } $query ="DELETE FROM domains WHERE domain='$source'"; $result = mysql_query($query) or die("Query failed : " . mysql_error()); print <<< DOMAINDELETED <html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8"></head><body> Домен удален. </body></html> DOMAINDELETED; mysql_close($link); exit(1); break; } function isemail($email) { return preg_match('|^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]{2,})+$|i', $email); } ?>
Не забудьте поменять пароль пользователя <mail_admin_password>
Изменим права доступа на эти файлы
sudo chown -R www-data /var/www/control sudo chmod -R o-r /var/www/controlи перезапустим apache
sudo /etc/init.d/apache2 restartПосле этого, зайдя браузером на https://oban.aaa.ru/control и введя имя пользователя admin и пароль <mail_admin_password> (который мы ранее для него задали), мы сможем создавать пользователей, удалять их, задавать им пароль (если они его забыли), а также создавать и удалять новые алиасы.
Приложение 2 — фильтрация писем на сервере
Если у Вас есть необходимость использовать фильтрацию писем на сервере, а
не по правилам, которые могут устанавливать сами пользователи в horde, то это можно сделать с помощью procmail.
Установим procmail
Отредактируем файл
Если хотите, чтобы у каждого пользователя велся собственный протокол фильтрации, раскомментируйте строку
Предположим, что у нас есть пользователь, почту которого мы хотим фильтровать по правилам на сервере — test@aaa.ru. Вставим в таблицу transport запись, которая говорит, что почта, поступившая на адрес получателя test@aaa.ru должна передаваться procmail для фильтрации:
Нужная папка создастся сама при первом срабатывании фильтра (т. к. у нас пользователь vmail, от имени которого запускается procmail, имеет право на создание папок в директориях пользователей).
Информацию, как именно писать фильтры для procmail можно найти в Интернет.
Установим procmail
sudo apt-get install procmailОтредактируем файл
sudo nano /etc/postfix/master.cfи вставим в него следующие строки:
procmail unix - n n - - pipe -o flags=RO user=vmail argv=/usr/bin/procmail -t -m USER=${user} EXTENSION=${extension} NEXTHOP=${nexthop} /etc/postfix/procmail.common(вторая строка должна начинаться хотя бы с одного пробела)
Отредактируем файл
sudo nano /etc/postfix/main.cfи вставим в него строку
procmail_destination_recipient_limit = 1Создадим файл
sudo nano /etc/postfix/procmail.common
MAILDIR="$HOME/$NEXTHOP/$USER" DEFAULT="$MAILDIR/" #VERBOSE=ON #each user will set his own log file #LOGFILE="/home/vmail/$NEXTHOP/$USER/procmail.log" NL=" " WS=" " SWITCHRC="$HOME/$NEXTHOP/$USER/.procmail"(значение переменной WS — два символа: пробел и табуляция. Это нужно, чтобы проще было писать правила)
Если хотите, чтобы у каждого пользователя велся собственный протокол фильтрации, раскомментируйте строку
#LOGFILE="/home/vmail/$NEXTHOP/$USER/procmail.log"
(уберите символ # из начала строки).
Предположим, что у нас есть пользователь, почту которого мы хотим фильтровать по правилам на сервере — test@aaa.ru. Вставим в таблицу transport запись, которая говорит, что почта, поступившая на адрес получателя test@aaa.ru должна передаваться procmail для фильтрации:
mysql -u mail_admin -p
Enter password:
Введем пароль
<mail_admin_password>
use mail; INSERT INTO `transport` (`domain`, `transport`) VALUES ('test@aaa.ru', 'procmail:'); quit;Перезапускаем postfix
sudo /etc/init.d/postfix restartИ создаем в папке пользователя test@aaa.ru файл .procmail с нужными нам фильтрами, например:
sudo nano /home/vmail/aaa.ru/test/.procmail
:0 * ^Subject:.*\<testing .testing/Это значит, что при поступлении письма с темой, в которой есть слово testing, письмо будет перемещено в папку .testing. Заметьте, что точка перед названием папки — обязательна, чтобы папка была видна при доступе через IMAP.
Нужная папка создастся сама при первом срабатывании фильтра (т. к. у нас пользователь vmail, от имени которого запускается procmail, имеет право на создание папок в директориях пользователей).
Информацию, как именно писать фильтры для procmail можно найти в Интернет.
Приложение 3 — пользователь без почты
Зачастую необходимо создание такого пользователя, у которого вся
приходящая почта будет уничтожаться (например, от имени такого
пользователя обычно рассылаются сообщения, на которые ответы не
ожидаются) — назовем его noreply@aaa.ru .
Сначала заведем этого пользователя в нашей таблице users (мы предполагаем, что такой пользователь нам в нашей ldap-таблице пользователей не нужен):
Для того, чтобы указать, что почту, приходящую этому пользователю, нужно просто уничтожать, используем таблицу transport:
Сначала заведем этого пользователя в нашей таблице users (мы предполагаем, что такой пользователь нам в нашей ldap-таблице пользователей не нужен):
mysql -u mail_admin -p
Enter password:
Введем пароль
<mail_admin_password>
use mail; INSERT INTO `users` (`email`, `password`, `quota`) VALUES ('noreply@aaa.ru', ENCRYPT('secret'), '0');(вместо secret выберите пароль, который Вам все равно не понадобится, т. к. никакой почты этот пользователь получать не будет)
Для того, чтобы указать, что почту, приходящую этому пользователю, нужно просто уничтожать, используем таблицу transport:
INSERT INTO `transport` (`domain`, `transport`) VALUES ('noreply@aaa.ru', 'discard:'); quit;Теперь вся почта, приходящая на адрес noreply@aaa.ru будет просто уничтожаться.
Приложение 4 — фильтрация писем на сервере при помощи sieve
Есть еще одна возможность фильтровать письма на сервере — так называемые скрипты sieve.
Их отличие в том, что несмотря на то, что фильтрация происходит на
сервере, пользователи могут сами создавать и редактировать правила
фильтрации, причем не только при помощи horde: плагины для управления
скриптами sieve (протокол управления называется managesieve — не правда ли, неожиданно?) существуют для многих почтовых клиентов (например, thunderbird).
Скрипты sieve поддерживаются dovecot, правда, для этого нам придется переложить на dovecot задачу раскладывания писем по папкам (у нас этим занимался postfix).
Отредактируем файл /etc/dovecot/dovecot.conf
Отредактируем файл
Отредактируем файл
Отредактируем файл
Отредактируем файл
Нажмем кнопку Generate Фильтры Configuration, скопируем сгенеренный текст конфигурации и запишем в файл /etc/horde/ingo1/conf.php
Зайдем пользователем, у которого мы хотим использовать скрипты, войдем в Настройки - Фильтры, выберем (установим птичку) параметр «Automatically update the script after each change?» и нажмем кнопку Сохранить настройки.
Теперь в разделе Почта — Фильтры можно активировать, редактировать имеющиеся фильтры или добавлять новые. Все правила, которые Вы будете задавать через horde (ingo) будут записываться в файл правил с именем ingo. Этот файл будет доступен для редактирования с помощью любого другого плагина sieve (например, к thunderbird).
Скрипты sieve поддерживаются dovecot, правда, для этого нам придется переложить на dovecot задачу раскладывания писем по папкам (у нас этим занимался postfix).
Отредактируем файл /etc/dovecot/dovecot.conf
sudo nano /etc/dovecot/dovecot.confизменив следующие параметры
protocols = imap imaps pop3 pop3s managesieve protocol managesieve { listen = *:2000 login_executable = /usr/lib/dovecot/managesieve-login mail_executable = /usr/lib/dovecot/managesieve managesieve_max_line_length = 65536 managesieve_logout_format = bytes=%i/%o managesieve_implementation_string = Cyrus timsieved v2.2.13 } protocol lda { postmaster_address = postmaster@aaa.ru mail_plugins = sieve }В блоке
auth_default {
расскомментируем (и отредактируем) строки
socket listen { master { path = /var/run/dovecot/auth-master mode = 0600 user = vmail #group = } client { path = /var/run/dovecot/auth-client mode = 0660 } }В блоке
plugin {
добавим строки
sieve = ~/sieve/.dovecot.sieve sieve_dir = ~/sieve sieve_extensions = +imapflagsЗдесь мы задаем расположение скриптов sieve относительно «домашней» директории наших пользователей (а также разрешаем использовать устаревшие команды imapflags — они нам нужны для управления фильтрами с помощью horde). В каждый момент времени может быть активным только один файл со скриптами, на него будет (автоматом, при активации файла в том или ином плагине) делаться ссылка .dovecot.sieve. У нас все пользователи — виртуальные, причем часть из них — ldap, остальные же — mysql пользователи, поэтому нам нужно задать домашнюю директорию для обоих типов.
Отредактируем файл
sudo nano /etc/dovecot/dovecot-ldap.confи отредактируем следующие строки
user_attrs = mail=mail=maildir:/home/vmail/aaa.ru/%n/,homeDirectory=home=/home/vmail/aaa.ru/%n\\ user_filter = (&(uid=%n))Здесь мы явно задаем наш домен aaa.ru, т. к. пользователи этого домена авторизуются в ldap без указания домена, а только своим именем.
Отредактируем файл
sudo nano /etc/dovecot/dovecot-sql.confи отредактируем строку
user_query = SELECT email, CONCAT('/home/vmail/',CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1))) AS home, concat('*:storage=', quota) as quota_rule FROM users WHERE email='%u'Теперь настроим postfix на использование dovecot для локальной рассылки писем.
Отредактируем файл
sudo nano /etc/posfix/master.cfи вставим строки
dovecot unix - n n - - pipe flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient}(вторая строка начинается хотя бы с одного пробела)
Отредактируем файл
sudo nano /etc/postfix/main.cfи вставим строки
dovecot_destination_recipient_limit = 1 virtual_transport = dovecotПерезапустим dovecot и postfix
sudo /etc/init.d/dovecot restart sudo /etc/init.d/postfix restart
Не забудьте на шлюзе пробросить TCP порт 2000 на почтовый сервер, чтобы клиенты снаружи могли использовать протокол managesieve.
Для управления sieve в horde установим необходимые пакеты:
sudo apt-get install php-net-sieve ingo1К сожалению, в текущей версии php-net-sieve есть ошибка, которая приводит к выдаче отладочной информации, поэтому нам нужно отредактировать файл
sudo nano /usr/share/horde3/ingo/lib/Driver/timsieved.phpи закомментировать строку (в текущей версии файла это 83-я строка)
// $this->_sieve->setDebug(true, array($this, '_debug'));Теперь настроим ingo. Отредактируем файл
sudo nano /etc/horde/ingo1/backends.phpЗакомментируем все, кроме следующих строк (отредактировав соответственно приведенному примеру):
/* Sieve */ $backends['sieve'] = array( 'driver' => 'timsieved', 'preferred' => 'localhost', 'hordeauth' => full, 'params' => array( // Hostname of the timsieved server 'hostspec' => 'localhost', // Login type of the server 'logintype' => 'PLAIN', // Enable/disable TLS encryption 'usetls' => false, // Port number of the timsieved server 'port' => 2000, // Name of the sieve script 'scriptname' => 'ingo', // The following settings can be used to specify an administration // user to update all users' scripts. If you want to use an admin // user, you also need to disable 'hordeauth' above. You have to use // an admin user if you want to use shared rules. // 'username' => 'cyrus', // 'password' => '*****', ), 'script' => 'sieve', 'scriptparams' => array(), 'shares' => false );Зайдем пользователем-адинистратором на https://oban.aaa.ru и войдем в Управление - Приложения - Фильтры (ingo). В поле «What storage driver should we use?» выберем
Preference System
.
Нажмем кнопку Generate Фильтры Configuration, скопируем сгенеренный текст конфигурации и запишем в файл /etc/horde/ingo1/conf.php
sudo nano /etc/horde/ingo1/conf.php(здесь вставляем скопированный текст со страницы браузера)
Зайдем пользователем, у которого мы хотим использовать скрипты, войдем в Настройки - Фильтры, выберем (установим птичку) параметр «Automatically update the script after each change?» и нажмем кнопку Сохранить настройки.
Теперь в разделе Почта — Фильтры можно активировать, редактировать имеющиеся фильтры или добавлять новые. Все правила, которые Вы будете задавать через horde (ingo) будут записываться в файл правил с именем ingo. Этот файл будет доступен для редактирования с помощью любого другого плагина sieve (например, к thunderbird).
Комментарии
Отправить комментарий