HOWTO, чтобы самому не забыть, и предоставить информацию для тех, у кого возникают проблемы.
Что будет включать в себя почтовая система:
Тестовая система: Ubuntu 11.04 server. Работаю под рутом, поэтому sudo опускаем.
Доменное имя для примера: example.com
1. Установка пакетов и создание пользователя для доступа к виртуальным почтовым ящикам
apt-get install postfix postfix-mysql maildrop apache2 php5 php5-cli php5-mysql php5-imap \
php5-mcrypt php5-intl amavisd-new spamassassin clamav clamav-daemon dovecot-imapd \
dovecot-pop3d mysql-server
# Почта будет храниться здесь в виде /home/vmail/DOMAINNAME/USERNAME
# Удаленные через PostfixAdmin домены/ящики буду храниться в /home/vmail/DELETED
mkdir -p /home/vmail/DELETED
# !!! UID 111 должен быть свободен, если он занят то выбираем свободный, и везде далее не забываем его поменять !!!
useradd -r -u 111 -g mail -d /home/vmail -s /sbin/nologin -c "Virtual mailbox" vmail
chown -R vmail:mail /home/vmail
chmod 770 /home/vmail
2. Установка PostfixAdmin
PostfixAdmin — веб-интерфейс управления виртуальными почтовыми доменами и пользователями.
Скачиваем последнюю версию с http://sourceforge.net/projects/postfixadmin:
cd /var/www
wget POSTFIXADMIN_URL.tar.gz
tar -xvzf postfixadmin-2.x.x.tar.gz
mv postfixadmin-2.x.x postfixadmin
chown -R www-data:www-data postfixadmin
Создаем базу данных:
mysql -u root -p
CREATE DATABASE postfix;
GRANT ALL ON postfix.* TO postfix@localhost IDENTIFIED BY 'postfixpass';
FLUSH PRIVILEGES;
Правим /var/www/postfixadmin/config.inc.php:
...
$CONF['configured'] = true;
...
$CONF['postfix_admin_url'] = 'http://example.com/postfixadmin';
$CONF['database_user'] = 'postfix';
$CONF['database_password'] = 'postfixpass';
$CONF['database_name'] = 'postfix';
...
$CONF['admin_email'] = 'postmaster@example.com';
...
$CONF['default_aliases'] = array (
'abuse' => 'abuse@example.com',
'hostmaster' => 'hostmaster@example.com',
'postmaster' => 'postmaster@example.com',
'webmaster' => 'webmaster@example.com'
);
...
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
...
$CONF['fetchmail'] = 'NO';
...
$CONF['mailbox_postcreation_script']='/usr/bin/sudo -u vmail /usr/local/bin/postfixadmin-mailbox-postcreation.sh';
$CONF['mailbox_postdeletion_script']='/usr/bin/sudo -u vmail /usr/local/bin/postfixadmin-mailbox-postdeletion.sh';
$CONF['domain_postdeletion_script']='/usr/bin/sudo -u vmail /usr/local/bin/postfixadmin-domain-postdeletion.sh';
...
// Остальные параметры можно изменить по вкусу
Заходим на http://example.com/postfixadmin/setup.php:
Проверяем секцию «Checking for dependencies: «, там все должно быть «ОК».
Задаем «Setup password» и меняем $CONF['setup_password'] на полученный хеш.
Затем вводим новый Setup password, детали суперадмина и добавляем его.
Теперь можно зайти на http://example.com/postfixadmin, используя созданного суперадмина.
Добавляем в /etc/sudoers:
...
www-data ALL=(vmail) NOPASSWD: /usr/local/bin/postfixadmin-mailbox-postdeletion.sh
www-data ALL=(vmail) NOPASSWD: /usr/local/bin/postfixadmin-domain-postdeletion.sh
www-data ALL=(vmail) NOPASSWD: /usr/local/bin/postfixadmin-mailbox-postcreation.sh
...
Копируем скрипты, которые физически создают/удаляют домены/почтовые ящики после соответственных действий в PostfixAdmin:
cp /var/www/postfixadmin/ADDITIONS/postfixadmin-domain-postdeletion.sh /usr/local/bin
cp /var/www/postfixadmin/ADDITIONS/postfixadmin-mailbox-postcreation.sh /usr/local/bin
cp /var/www/postfixadmin/ADDITIONS/postfixadmin-mailbox-postdeletion.sh /usr/local/bin
Правим в этих скриптах параметры basedir и trashbase(где есть):
basedir=/home/vmail
...
trashbase=/home/vmail/DELETED
После этого нужно создать первый виртуальный домен example.com и хотя бы один ящик (приветственное письмо можно пока не отсылать, все равно не дойдет).
2. Настройка Postfix
Небольшое отступление. Я сознательно отказался от родного в postfix VDA и выбрал Dovecot LDA, поскольку для поддержки квот нужныпатч и пересборка deb-пакета. С патчем квоты тоже работают хорошо, но обновление Postfix становится более затруднительным.
Правим /etc/postfix/main.cf:
...
myhostname = mail.example.com
myorigin = /etc/mailname
mydestination = $myhostname, localhost.example.com, localhost
...
# Таблица просмотра виртуальных доменов
virtual_mailbox_domains = proxy:mysql:/etc/postfix/sql/mysql_virtual_domains_maps.cf
# Таблицы просмотра почтовых псевдонимов для виртуальных почтовых доменов/ящиков
virtual_alias_maps =
proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_maps.cf,
proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf,
proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf
# Таблицы просмотра каталогов для хранения почты
virtual_mailbox_maps =
proxy:mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf,
proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf
# !!! GID для группы mail, если он отличается, то здесь и далее меняем !!!
virtual_gid_maps = static:8
virtual_mailbox_base = /home/vmail
virtual_minimum_uid = 111
dovecot_destination_recipient_limit = 1
# Транспорт для виртуальных доменов в virtual_mailbox_domains - Dovecot LDA
virtual_transport = dovecot
virtual_uid_maps = static:111
broken_sasl_auth_clients = yes
# Небольшие ограничения для отсылки, можно добавить и DNSBL, и т.д., кому как хочется
smtpd_recipient_restrictions =
permit_mynetworks,
reject_non_fqdn_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unauth_destination,
reject_unauth_pipelining,
reject_invalid_hostname
# Добавляем проверку на вирусы и спам через amavisd-new
content_filter = smtp-amavis:[127.0.0.1]:10024
receive_override_options=no_address_mappings
message_size_limit = 10485760
strict_rfc821_envelopes = yes
disable_vrfy_command = yes
smtpd_helo_required = yes
Создаем файлы для таблиц просмотра MySQL, тем самым, связывая Postfix и базу данных для PostfixAdmin.
mkdir /etc/postfix/sql
/etc/postfix/sql/mysql_virtual_domains_maps.cf:
user = postfix
password = postfixpass
hosts = localhost
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
#query = SELECT domain FROM domain WHERE domain='%s'
#optional query to use when relaying for backup MX
#query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'
#expansion_limit = 100
/etc/postfix/sql/mysql_virtual_alias_maps.cf:
user = postfix
password = postfixpass
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
#expansion_limit = 100
/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf:
user = postfix
password = postfixpass
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf:
user = postfix
password = postfixpass
hosts = localhost
dbname = postfix
query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' AND mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = 1 AND alias_domain.active='1'
/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf:
# handles catch-all settings of target-domain
user = postfix
password = postfixpass
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' AND alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
/etc/postfix/sql/mysql_virtual_mailbox_maps.cf:
user = postfix
password = postfixpass
hosts = localhost
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
#expansion_limit = 100
Немного безопасности:
chmod 640 /etc/postfix/sql/*
chown -R postfix /etc/postfix/sql
Правим /etc/postfix/master.cf:
...
pickup fifo n - - 60 1 pickup
-o content_filter=
-o receive_override_options=no_header_body_checks
...
smtp-amavis unix - - - - 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes
-o max_use=20
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_delay_reject=no
-o smtpd_client_restrictions=permit_mynetworks,reject
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o smtpd_data_restrictions=reject_unauth_pipelining
-o smtpd_end_of_data_restrictions=
-o mynetworks=127.0.0.0/8
-o smtpd_error_sleep_time=0
-o smtpd_soft_error_limit=1001
-o smtpd_hard_error_limit=1000
-o smtpd_client_connection_count_limit=0
-o smtpd_client_connection_rate_limit=0
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks
dovecot unix - n n - - pipe
flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${user}@${nexthop} -n -m ${extension}
3. Настройка Amavisd-new+ClamAV+SpamAssassin
Правим /etc/amavis/conf.d/05-node_id:
...
$myhostname = "mail.example.com"
...
Правим /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/21-ubuntu_defaults в соответствиями со своими желаниями:
...
$final_virus_destiny = D_DISCARD;
$final_banned_destiny = D_DISCARD;
$final_spam_destiny = D_PASS; # Только помечаем обнаруженный спам
$final_bad_header_destiny = D_PASS; # Только помечаем письмо с плохими заголовками
...
Правим /etc/amavis/conf.d/50-user:
...
# Добавляем поддержку виртуальных доменов в MySQL
@lookup_sql_dsn = (
['DBI:mysql:database=postfix;host=127.0.0.1;port=3306',
'postfix',
'postfixpass']);
.....
$sql_select_policy = 'SELECT domain FROM domain WHERE CONCAT("@",domain) IN (%k)';
...
Немного безопасности:
chmod 640 /etc/amavis/conf.d/50-user
Добавляем в /etc/clamav/freshclam.conf:
...
NotifyClamd /etc/clamav/clamd.conf
Добавляем сервисных пользователей в группы:
adduser clamav amavis
adduser amavis clamav
Правим /etc/default/spamassassin:
ENABLED=1
...
CRON=1
Перезапускаем сервисы:
/etc/init.d/postfix restart
/etc/init.d/amavis restart
/etc/init.d/clamav-freshclam restart
/etc/init.d/clamav-daemon restart
4. Настройка Dovecot (IMAP,POP3,LDA)
Правим /etc/dovecot/dovecot.conf:
...
protocols = imap imaps pop3 pop3s
disable_plaintext_auth = no
...
mail_location = maildir:/home/vmail/%d/%u
...
# !!! Не забываем проверить uid для vmail и gid для mail !!!
mail_uid = 111
mail_gid = 8
...
first_valid_uid = 111
last_valid_uid = 111
first_valid_gid = 8
last_valid_gid = 8
...
protocol imap {
...
mail_plugins = quota imap_quota
imap_client_workarounds = delay-newmail netscape-eoh
}
protocol pop3 {
...
mail_plugins = quota
pop3_client_workarounds = outlook-no-nuls oe-ns-eoh
}
protocol lda {
...
postmaster_address = postmaster@example.com
mail_plugins = quota
}
...
auth_default_realm = example.com
auth default {
mechanisms = plain login
passdb sql {
args = /etc/dovecot/dovecot-sql.conf
}
userdb sql {
args = /etc/dovecot/dovecot-sql.conf
}
...
socket listen {
path = /var/run/dovecot/auth-master
mode = 0600
user = vmail
group = mail
}
}
...
plugin {
quota = maildir:User quota
# Квота по умолчанию, затем переопределяется SQL-запросом userdb
quota_rule = storage=50M:messages=1000
# Дополнительная квота к корзине, чтобы можно было удалять сообщения при превышении квоты
quota_rule2 = Trash:storage=10M
# Сообщение об исчерпании 80% квоты
quota_warning = storage=80%% /usr/local/bin/quota-warning.sh 80
...
}
Правим /etc/dovecot/dovecot-sql.conf:
...
driver = mysql
connect = host=127.0.0.1 dbname=postfix user=postfix password=postfixpass
# Не забываем про uid и gid
password_query = SELECT username as user, password, concat('/home/vmail/', maildir) as userdb_home, concat('maildir:/home/vmail/', maildir) as userdb_mail, 111 as userdb_uid, 8 as userdb_gid FROM mailbox WHERE username = '%u' AND active = '1'
user_query = SELECT concat('/home/vmail/', maildir) as home, concat('maildir:/home/vmail/', maildir) as mail, 111 AS uid, 8 AS gid, concat('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND active = '1'
...
Копируем dovecot.conf в dovecot-nowarning.conf и комментируем строчку:
...
# Необходимо во избежание цикла
#quota_warning = storage=80%% /usr/local/bin/quota-warning.sh 80
...
Создаем /usr/local/bin/quota-warning.sh:
#!/bin/sh
PERCENT=$1
cat << EOF | /usr/lib/dovecot/deliver -d $USER -c /etc/dovecot/dovecot-nowarning.conf
From: postmaster@example.com
Subject: quota warning
Your mailbox is now $PERCENT% full. Please delete unnecessary emails.
EOF
На всякий случай устанавливаем бит выполнения на скрипты:
chmod +x /usr/local/bin/*.sh
Перезапускаем сервис:
/etc/init.d/dovecot restart
5. Установка Roundcube
Качаем и распаковываем последнюю версию:
cd /var/www
wget ROUNDCUBE_URL
tar -xvzf roundcubemail-X.X.X.tar.gz
mv roundcubemail-X.X.X mail
chown -R www-data:www-data mail
Создаем базу данных для Roundcube:
mysql -u root -p
>CREATE DATABASE roundcubemail /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
>GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost IDENTIFIED BY 'password';
>FLUSH PRIVILEGES;
cd /var/www/mail
mysql -u root -p roundcubemail < SQL/mysql.initial.sql
Идем на http://example.com/mail/installer/ и следуем инструкциям.
Удаляем каталог installer:
rm -r /var/www/mail/installer
Правим /var/www/mail/config/main.inc.php в соответствии с нуждами, например:
...
$rcmail_config['default_host'] = 'localhost';
$rcmail_config['smtp_server'] = 'localhost';
$rcmail_config['smtp_port'] = 25;
$rcmail_config['smtp_user'] = '';
$rcmail_config['smtp_pass'] = '';
$rcmail_config['enable_caching'] = false;
$rcmail_config['login_lc'] = true;
$rcmail_config['auto_create_user'] = true;
$rcmail_config['dont_override'] = array('skin','default_imap_folders','keep_alive');
$rcmail_config['identities_level'] = 3;
$rcmail_config['create_default_folders'] = true;
$rcmail_config['protect_default_folders'] = true;
$rcmail_config['spellcheck_languages'] = array('en'=>'English');
$rcmail_config['preview_pane'] = true;
$rcmail_config['skip_deleted'] = true;
...
По умолчанию, Apache в Ubuntu не обрабатывает .htaccess в директории /var/www, поэтому правим /etc/apache2/sites-available/default:
<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
Перезапускаем Apache:
/etc/init.d/apache2 restart
На этом основная настройка почтовой системы закончена, остается создавать домены, почтовые ящики, проверить отсылку/чтение почты. Важное DNS-замечание: необходимо не забыть прописать MX-запись для домена (example.com) в виде mail.example.com и A-запись для mail.example.com, чтобы почта корректно стала ходить извне.
Естественно, что эта почтовая система начального уровня для небольших нагрузок, хотя дальнейшие усовершенствования обязательно нужны, будь то SMTP-аутентификация, DNSBL, грейлистинг, проверка заголовков и др., тем более, что реализуются они сравнительно просто.