Colobridge WIKI

Установка postfix dovecot postfixadmin в OS Debian

Необходимо поднять почтовый сервер на котором будет крутиться связка Postfix + Dovecot. Виртуальные почтовые домены с индивидуальными (или на домен) квотами. С адекватной проверкой на вирусы и спам (остечение postgrey + на уровне SMTP-сессии + spamassassin). Так же организуем доступ пользователей через веб-интерефейс и управление пользователями так же через вебморду.

Устанавливаем пакеты

Postifx, Dovecot, postgrey, amavis, spamassassin, roundcube, postfixadmin.

Установка

Поставим все необходимые пакеты:

apt-get install postfix postfix-mysql dovecot-mysql dovecot-sieve dovecot-pop3d dovecot-imapd amavisd-new \
libclass-dbi-mysql-perl spamassassin clamav clamav-daemon postgrey
Настройка: В /etc/hostname должно быть имя сервера без доменной части. А в /etc/mailname наоборот - fqdn имя.
root@mx:~# cat /etc/hostname
mx
 root@mx:~# cat /etc/mailname
mx.example.com
Замечание: опытным путем проверенно что hostname может быть любым, главное чтобы в mailname было прописан доменное имя, которое написано в MX-записи домена для которого делаем почту (Например: mail.example.com)

Файлик /etc/hosts

92.122.190.40 mx.example.com mx Создадим пользователя от имени которого будет работать postfix и dovecot.

groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /vmail -m
Необходимо сгенерировать сертификаты для работы почтового сервера. (для подключения пользователей с использованием SSL) Сгенерируем сертификаты
mkdir /etc/postfix/certs
cd /etc/postfix/certs
touch openssl.cnf
Впишем
[req]
default_bits = 4096                     # Длинна ключа в битах.
default_keyfile = key.pem               # Имя файла, в который будет записан закрытый ключ.
encrypt_key = no                        # Нам не нужно шифровать закрытый ключ паролем.
default_md = sha512                     # Алгоритм хеша.
x509_extensions = v3_req                # Включаем расширение V3.
prompt = no                             # Не нужно запрашивать данные у пользователя, мы всё пропишем здесь.
distinguished_name = req_distinguished_name         # Имя секции с данными (может быть любым).

[req_distinguished_name]
C = Country                             # Двухбуквенный код страны
L = Locality                            # Город
O = Organization                        # Название организации
CN = mail.example.com                   # Имя домена
emailAddress = postmaster@example.com   # Адрес электронной почты
# Можно ещё указать следующие поля:
# ST (State - штат, название провинции и т.п.)
# OU (Organizational Unit - название подразделения)

[v3_req]
# Список альтернативных имён. Можно указать прямо здесь, но это не
# удобно, особенно если их много, так что мы указываем название секции
# с именами.
subjectAltName = @alt_names

[alt_names]
# Имена. Можно указать хоть сколько, главное чтобы цифры после точки были разными.
DNS.0 = example.com
DNS.1 = www.example.com
Естественно, заменив значения на свои. Теперь сообственно сгенерируем сами сертификаты
openssl req -new -x509 -days 36500 -config openssl.cnf -out cert.pem -outform PEM -keyout key.pem -keyform PEM
Удалим файл настроек
rm -f openssl.cnf 
Перейдем на настройкам postfix. Приведем main.cf к такому виду
# See /usr/share/postfix/main.cf.dist for a commented, more complete version

# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# =================
# TLS parameters
# =================
smtp_tls_security_level = may
smtpd_tls_security_level = may
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
smtpd_tls_cert_file = /etc/postfix/certs/cert.pem
smtpd_tls_key_file = /etc/postfix/certs/key.pem
smtpd_use_tls = yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
tls_random_source = dev:/dev/urandom

# =================
# GENEREAL
# =================
myhostname = mail.example.com
#alias_maps = hash:/etc/aliases
#alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = $myhostname, localhost.$mydomain, localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_command = procmail -a "$EXTENSION"
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
max_use = 500
disable_vrfy_command = yes
soft_bounce = no

# ================
# SASL
# ================
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_authenticated_header = yes
smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
smtpd_sasl_security_options = noanonymous
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_helo_required = yes
smtpd_delay_reject = yes
smtpd_discard_ehlo_keywords = etrn, silent-discard
smtpd_recipient_limit = 10
smtpd_sender_login_maps = mysql:/etc/postfix/mysql-users.cf

# =================
# VIRTUAL
# =================
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf,mysql:/etc/postfix/mysql-email2email.cf,mysql:/etc/postfix/mysql-virtual-alias-domain-maps.cf
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1

# =================
# LIMITS
# =================
message_size_limit = 51200000
smtpd_client_connection_count_limit = 20
smtpd_client_connection_rate_limit = 30

# =================
# QUEUE
# =================
maximal_queue_lifetime = 1d
bounce_queue_lifetime = 1d

# =================
# RULES
# =================
smtpd_client_restrictions =
        permit_mynetworks,
        check_client_access hash:/etc/postfix/sender_access,
        permit_sasl_authenticated,
        reject_unknown_reverse_client_hostname,
        warn_if_reject reject_unknown_client

smtpd_helo_restrictions =
        permit_mynetworks,
        check_helo_access hash:/etc/postfix/sender_access,
        reject_invalid_helo_hostname,
        reject_unknown_helo_hostname,
        reject_non_fqdn_helo_hostname

smtpd_sender_restrictions =
        permit_mynetworks,
        check_sender_access hash:/etc/postfix/sender_access,
        permit_sasl_authenticated,
        reject_non_fqdn_sender,
        reject_unverified_sender,
        reject_unauthenticated_sender_login_mismatch,
        reject_unknown_sender_domain

smtpd_recipient_restrictions =
        permit_mynetworks,
        check_recipient_access hash:/etc/postfix/recipient_access,
        permit_sasl_authenticated,
        reject_non_fqdn_recipient,
        reject_unknown_recipient_domain,
        reject_multi_recipient_bounce,
        reject_unauth_destination,
        reject_unlisted_recipient,
        check_policy_service inet:127.0.0.1:10023

smtpd_data_restrictions =
        reject_unauth_pipelining

# =================
# AMAVIS
# =================
content_filter = smtp-amavis:[127.0.0.1]:10024
добавим в master.cf поддержку submission (это позволит работать postfix по 587 порту). Добавляем сразу после smtp.

submission inet n       -       n       -       -       smtpd
   -o syslog_name=postfix/submission
   -o smtpd_tls_wrappermode=no
   -o smtpd_tls_security_level=encrypt
   -o smtpd_sasl_auth_enable=yes
   -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
   -o milter_macro_daemon_name=ORIGINATING
так же добавим, что dovecot будет заниматься доставкой писем по ящикам. Добавим в конец файла.

dovecot   unix  -   n   n   -   -   pipe
     flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -d ${recipient}
так же добавим поддержку amavis и postgrey

smtp-amavis unix -     -       n       -       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 mynetworks=127.0.0.0/8
       -o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
       -o smtpd_helo_restrictions=
       -o smtpd_sender_restrictions=
       -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
       -o smtpd_data_restrictions=reject_unauth_pipelining
       -o smtpd_end_of_data_restrictions=
       -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,no_address_mappings
       -o local_header_rewrite_clients=

Добавим файлы с запросами, для работы виртуальных доменов, пользователей, алиасов. Подставьте вместо

HOST = адрес MySQL сервера DB = имя базы данных USER = имя пользоватья для подключения в базе PASSWORD = его пароль Примечание: используйте в DB вместо localhost, 127.0.0.1. Иначе не взлетит!

mysql-email2email.cf

user = USER
password = PASSWORD
hosts = HOST
dbname = DB
query = select username from mailbox where username = '%s'
mysql-users.cf

user = USER
password = PASSWORD
hosts = HOST
dbname = DB
query = select username from mailbox where username='%s' AND active = '1'
mysql-virtual-alias-domain-maps.cf

user = USER
password = PASSWORD
hosts = HOST
dbname = DB
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'
mysql-virtual-alias-maps.cf

user = USER
password = PASSWORD
hosts = HOST
dbname = DB
query = select goto from alias where address='%s'
mysql-virtual-mailbox-domains.cf

user = USER
password = PASSWORD
hosts = HOST
dbname = DB
query = select domain from domain where domain='%s'
mysql-virtual-mailbox-maps.cf

user = USER
password = PASSWORD
hosts = HOST
dbname = DB
query = select username from mailbox where username='%s' AND active = '1'
Наведем порядок с правами на созданные файлы
chgrp postfix /etc/postfix/mysql-*.cf
chmod u=rw,g=r,o= /etc/postfix/mysql-*.cf
Создадим файл белых списков для получателей и отправителей
touch /etc/postfix/sender_access
touch /etc/postfix/recipient_access
postmap /etc/postfix/sender_access
postmap /etc/postfix/recipient_access
Записи в этих файлах должны выглядеть таким образом

example.com REJECT you are not in my local networks example.com OK Перейдем к настройке Dovecot. Приступим к редактированию его конфигов в /etc/dovecot/conf.d

10-auth.conf

disable_plaintext_auth = no
auth_realms = example.com
auth_mechanisms = plain login
#!include auth-system.conf.ext
!include auth-sql.conf.ext
example.com замените на свой домен, который Вы прописывали в /etc/mailname

10-logging.conf

log_path = syslog
syslog_facility = mail
10-mail.conf

mail_location = maildir:/vmail/%d/%n/Maildir
mail_uid = 5000
mail_gid = 5000
mail_plugins = quota

namespace inbox {
  # Namespace type: private, shared or public
  type = private

  # Hierarchy separator to use. You should use the same separator for all
  # namespaces or some clients get confused. '/' is usually a good one.
  # The default however depends on the underlying mail storage format.
  separator = .

  # Prefix required to access this namespace. This needs to be different for
  # all namespaces. For example "Public/".
  prefix =

  # Physical location of the mailbox. This is in same format as
  # mail_location, which is also the default for it.
  #location =

  # There can be only one INBOX, and this setting defines which namespace
  # has it.
  inbox = yes

  # If namespace is hidden, it's not advertised to clients via NAMESPACE
  # extension. You'll most likely also want to set list=no. This is mostly
  # useful when converting from another server with different namespaces which
  # you want to deprecate but still keep working. For example you can create
  # hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/".
  #hidden = no

  # Show the mailboxes under this namespace with LIST command. This makes the
  # namespace visible for clients that don't support NAMESPACE extension.
  # "children" value lists child mailboxes, but hides the namespace prefix.
  #list = yes

  # Namespace handles its own subscriptions. If set to "no", the parent
  # namespace handles them (empty prefix should always have this as "yes")
  #subscriptions = yes
}
10-master.conf

service imap-login {
  inet_listener imap {
    port = 143
  }
  inet_listener imaps {
    port = 993
    ssl = yes
  }

  # Number of connections to handle before starting a new process. Typically
  # the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0
  # is faster. 
  #service_count = 1

  # Number of processes to always keep waiting for more connections.
  #process_min_avail = 0

  # If you set service_count=0, you probably need to grow this.
  #vsz_limit = $default_vsz_limit
}
service pop3-login {
  inet_listener pop3 {
    port = 110
  }
  inet_listener pop3s {
    port = 995
    ssl = yes
  }
}
service auth {
  # auth_socket_path points to this userdb socket by default. It's typically
  # used by dovecot-lda, doveadm, possibly imap process, etc. Users that have
  # full permissions to this socket are able to get a list of all usernames and
  # get the results of everyone's userdb lookups.
  #
  # The default 0666 mode allows anyone to connect to the socket, but the
  # userdb lookups will succeed only if the userdb returns an "uid" field that
  # matches the caller process's UID. Also if caller's uid or gid matches the
  # socket's uid or gid the lookup succeeds. Anything else causes a failure.
  #
  # To give the caller full permissions to lookup all users, set the mode to
  # something else than 0666 and Dovecot lets the kernel enforce the
  # permissions (e.g. 0777 allows everyone full permissions).
  unix_listener auth-userdb {
    #mode = 0666
    #user =
    #group =
  }

  # Postfix smtp-auth
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = vmail
  }

  # Auth process is run as this user.
  #user = $default_internal_user
}
service dict {
  # If dict proxy is used, mail processes should have access to its socket.
  # For example: mode=0660, group=vmail and global mail_access_groups=vmail
  unix_listener dict {
    mode = 0600
    user = vmail
    #group =
  }
}
10-ssl.conf

ssl = yes
ssl_cert = </etc/postfix/certs/cert.pem
ssl_key = </etc/postfix/certs/key.pem
15-lda.conf

postmaster_address = postmaster@example.com
quota_full_tempfail = yes
lda_mailbox_autocreate = yes
lda_mailbox_autosubscribe = yes
mail_plugins = $mail_plugins autocreate sieve
15-mailboxes.conf

  # These mailboxes are widely used and could perhaps be created automatically:
  mailbox Drafts {
    auto = subscribe
    special_use = \Drafts
  }
  mailbox Junk {
    auto = subscribe
    special_use = \Junk
  }
  mailbox Trash {
    auto = subscribe
    special_use = \Trash
  }

  # For \Sent mailboxes there are two widely used names. We'll mark both of
  # them as \Sent. User typically deletes one of them if duplicates are created.
  mailbox Sent {
    auto = subscribe
    special_use = \Sent
  }
20-imap.conf

mail_plugins = $mail_plugins autocreate imap_quota
90-quota.conf

quota_rule = *:storage=1G
quota_warning = storage=95%% quota-warning 95 %u
quota_warning2 = storage=80%% quota-warning 80 %u
service quota-warning {
  executable = script /usr/local/bin/quota-warning.sh
  user = dovecot
  unix_listener quota-warning {
    user = vmail
  }
}
plugin {
  #quota = dirsize:User quota
  #quota = maildir:User quota
  quota = dict:User quota::proxy::quota
  #quota = fs:User quota
}
90-sieve.conf

sieve_default = /vmail/globalsieverc
sieve_before = /vmail/globalsieverc
Теперь вернемся в /etc/dovecot

dovecot-sql.conf.ext

driver = mysql
connect = host=HOST dbname=DB user=USER password=PASSWORD
default_pass_scheme = MD5-CRYPT
password_query = SELECT username as user, password FROM mailbox WHERE username = '%u'
user_query = SELECT '/vmail/%d/%n' AS home, 5000 AS uid, 5000 AS gid, CONCAT('*:bytes=', CAST(quota AS CHAR)) AS quota_rule FROM mailbox WHERE username = '%u' AND active = '1'
dovecot-dict-sql.conf.ext

connect = host=HOST dbname=DB user=USER password=PASSWORD
в connect замените

HOST = адрес MySQL сервера DB = имя базы данных USER = имя пользоватья для подключения в базе PASSWORD = его пароль тут так же заменить в двух местах

table = quota на

table = quota2 так же закомментируем

#map {
#  pattern = shared/expire/$user/$mailbox
#  table = expires
#  value_field = expire_stamp 
#
#  fields {
#    username = $user
#    mailbox = $mailbox
#  }
#}
dovecot.conf

quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext
Создадим скрипт оповещения пользователей о превышении квоты
/usr/local/bin/quota-warning.sh

#!/bin/sh
PERCENT=$1
FROM="postmaster@example.com"
USER=$2
cat << EOF | /usr/sbin/sendmail -f $FROM $USER
From: postmaster@nuft.edu.ua
Subject: quota warning

Your mailbox is now $PERCENT% full.
EOF
chmod +x /usr/local/bin/quota-warning.sh && chown dovecot: /usr/local/bin/quota-warning.sh

Настройка антиспам

Раскоментируем строчки в

/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/20-debian_defaults

$sa_tag2_level_deflt = 4; # add 'spam detected' headers at that level
$sa_kill_level_deflt = 4; # triggers spam evasive actions
$final_spam_destiny       = D_PASS;
Желательно так же добавить виртуальные домены в whitelist, для того чтобы они точно не распознавались как спам
# This are some examples for whitelists, since envelope senders can be forged
# they are not enabled by default.
   { # a hash-type lookup table (associative array)
        '.example.com'  => -20.0,
Так как у нас установлен только ClamAV, оставим только его как основной сканер на вирусы. Приведем конфиг к такому виду.

15-av_scanners

use strict;

##
## AV Scanners (Debian version)
##

@av_scanners = (

# ### http://www.clanfield.info/sophie/ (http://www.vanja.com/tools/sophie/)
# ['Sophie',
#   \&ask_daemon, ["{}/\n", '/var/run/sophie'],
#   qr/(?x)^ 0+ ( : | [\000\r\n]* $)/m,  qr/(?x)^ 1 ( : | [\000\r\n]* $)/m,
#   qr/(?x)^ [-+]? \d+ : (.*?) [\000\r\n]* $/m ],

# ### http://www.csupomona.edu/~henson/www/projects/SAVI-Perl/
# ['Sophos SAVI', \&sophos_savi ],

### http://www.clamav.net/
 ['ClamAV-clamd',
   \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.ctl"],
   qr/\bOK$/m, qr/\bFOUND$/m,
   qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
# NOTE: run clamd under the same user as amavisd, or run it under its own
#   uid such as clamav, add user clamav to the amavis group, and then add
#   AllowSupplementaryGroups to clamd.conf;
# NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
#   this entry; when running chrooted one may prefer socket "$MYHOME/clamd".

);

@av_scanners_backup = (

  ### http://www.clamav.net/   - backs up clamd or Mail::ClamAV
  ['ClamAV-clamscan', 'clamscan',
    "--stdout --no-summary -r --tempdir=$TEMPBASE {}",
    [0], qr/:.*\sFOUND$/m, qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],

);


1;  # ensure a defined return
50-user
перед
#------------ Do not modify anything below this line -------------
1;  # ensure a defined return
вставим

@lookup_sql_dsn = (
        ['DBI:mysql:database=DB;host=HOST;port=3306',
        'USER',
        'PASSWORD']);

$sql_select_policy = 'SELECT domain FROM domain WHERE CONCAT("@",domain) IN (%k)';
Для того чтобы не было проблем с правами доступа, в меняем в файле
/etc/clamav/clamd.conf

User amavis
LocalSocketGroup amavis
а так же в
/etc/clamav/freshclam.conf
DatabaseOwner amavis добавляем пользователя amavis в группу clamav и наоборот, затем меняем владельца папки /var/log/clamav/
usermod -a -G amavis clamav
​usermod -a -G clamav amavis
chown -R amavis:amavis /var/log/clamav
в файл /etc/default/spamassassin

ENABLED=1 Для того чтобы письма класифицированные как спам откладывались в специальную папку и не получались почтовым клиентом, но оставалась возможность их просмотреть с помощью веб-интерфейса, создаем файл

 /vmail/globalsieverc
require ["fileinto"];
# Move spam to spam folder
if header :contains "X-Spam-Flag" ["YES"] {
  fileinto "Junk";
  stop;
}
Файл должен пренадлежать полльзователю vmail.

chown vmail: /vmail/globalsieverc 
попдправим на последок настройки spamassassin и дело в шляпе

/etc/spamassassin/local.cf 
rewrite_header Subject *****SPAM*****
report_safe 0
required_score 4.0
use_bayes 1
bayes_auto_learn 0
bayes_ignore_header X-Bogosity
bayes_ignore_header X-Spam-Flag
bayes_ignore_header X-Spam-Status
 <code>

Перед
<code>
endif # Mail::SpamAssassin::Plugin::Shortcircuit
добавим
score DEAR_SOMETHING 5
score T_DKIM_INVALID 1
score HTML_MESSAGE 0.5
score MISSING_MID 1
score FORGET_MUA_OUTLOOK 2.199 2.199 0.963 1.116
score FH_DATE_PAST_20XX 0.0
score DOS_OE_TO_MX_IMAGE 0.0
score DOS_OE_TO_MX 0.0
score DOT_OUTLOOK_TO_MX 0.0
score TO_NO_BRKTS_DIRECT 0.0
score HELO_LOCALHOST 0.0
score FSL_RU_URL 0.0
score FROM_MISSP_EH_MATCH 1.0
score TVD_RCVD_SINGLE 1.0
score TO_IN_SUBJ 1.0

#
# TUNING
#
score SUBJ_FULL_OF_8BITS 0.00
score HTML_COMMENT_8BITS 0.01
score HEADER_8BITS 0.00
score TO_NO_USER 0.01
score FORGED_MUA_OUTLOOK 0.5
score X_AUTH_WARNING 0.01
score SUBJ_HAS_UNIQ_ID 9.99
score HTTP_USERNAME_USED 9.99
score FORGED_YAHOO_RCVD 9.99
score FORGED_JUNO_RCVD 16
score UNWANTED_LANGUAGE_BODY 1.02
score MLM 5.55
score RCVD_NUMERIC_HELO 4.95

#
# WHITE/BLACK LISTS
#
whitelist_from root@localhost
whitelist_from *@example.com
blacklist_from *@outblaze.com
auto_whitelist_path /etc/mail/spamassassin/auto-whitelist
auto_whitelist_file_mode 0666
В конфиге выше, whitelist_from *@example.com замените example.com на свой домен

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

service clamav-daemon restart
service clamav-freshclam restart
service amavis restart
service spamassassin start
Первые две-три недели spamassassin надо будет пообучать, а потом вместе с postgrey они будут пропускать примерно один спам в день. Данного набора вполне достаточно для эффективной борьбы со спамом. Особенно хочу выразить свою гражданскую позицию относительно спамхауса: у системных администраторов, которые используют спамхаус, бабушки работали вахтерами на заводских проходных!

К слову

В виду базовости настроек postifx'a пришлось сильно его допилить на дополнительные проверки на отсекание спама. Чтобы снизить нагрузку на сервер (amavis жрет нормально так), мы будем проверять средствами postfix входящие письма на соответсвие RFC.

Варианты фильтров

Обратная DNS запись (PTR запись). Считается правилом хорошего тона, когда администратор назначает каждому хосту обратную (PTR) запись. Кроме того, считается таким же хорошим тоном, когда обратная запись запись совпадает с прямой (А) записью.

N.B. При настройке своего почтового сервера потрудитесь, чтобы обратная запись совпадала с прямой. Т.е. если Вы, сделав dig -x (команда для *nix среды), для хоста 256.155.148.244 получили ответ mx.example.com, то и прямая запись mx.example.com должна указывать на 256.155.148.244. В противном случае не удивляйтесь если половина почтовых серверов откажется принимать Ваши письма. PTR запись прописывается у владельца блока IP адресов, скорее всего это Ваш провайдер.

Отсутствие обратной записи у сервера отправителя косвенно указывает на то, что сообщение является спамом. Вы не найдете ни одного сервера gmail, yahoo, mail.ru, yandex.ru и т.д., которые бы не имели обратной записи. И, хотя, теоретически отсутствие обратной записи не может служить критерием для оценки спамности письма, но как показывает практика в 99% случаев обратная запись отсутствует именно у хостов рассылающих спам, поэтому по отсутствию обратной записи у отправителя вполне можно отсеивать спам, а сталкиваясь с оставшимся 1% – заносить их в список исключений. Соответствующие директивы в конфиге postfix: reject_unknown_client.

HELO/EHLO. RFC прямо не обязывает, но рекомендует отправителям начинать SMTP сессию с HELO, в котором указано полноценное доменное имя (fully qualified domain name или сокращенно FQDN, например “smtp.example.com”). И, хотя, нет прямого обязательства это делать, но как и в случае с обратной записью передача в HELO неполноценного доменного имени (например “example”) или передача несуществующего доменного имени де-факто стали косвенными указателями на то, что письмо является спамом. Соответствующие директивы в конфиге postfix: reject_invalid_hostname, reject_non_fqdn_hostname, reject_unknown_hostname.

N.B. При настройке своего почтового сервера потрудитесь, чтобы в HELO Ваш сервер отдавал то, что прописано в PTR записи… Ведь материал выше Вы читали внимательно и PTR запись и А запись у Вас уже совпадают, не так ли? ;)

MAIL FROM. Как мы выяснили, в команде mail from отправитель передаёт получателю имя почтового ящика того, кто отправил письмо. Если в mail from указан почтовый адрес, даже домен которого не существует (напримерuser@sn7y3t5iuhncuhg84dnh4875nf5.com), стоит ли нам принимать такое письмо? Однозначно нет. В ходе SMTP сессии мы можем проверить существование домена и, при его отсутствии, смело отвергнуть сообщение. Кроме того, если окажется что домен существует, мы можем проверить наличие указанного почтового ящика в домене отправителя (практически все MTA это умеют делать, называется “sender verify”). Для этого получатель создает обратную SMTP сессию в сторону отправителя, которая проходит три стадии: helo, mail from, rcpt to и не доходя до data завершается. Представим, что получатель в ходе SMTP сессии получил “mail from:snduser@examplesender.com”. В рамках проверки “sender verify” получатель инициирует SMTP сессию назад в сторону отправителя, где в rcpt to передает “rcpt to:snduser@examplesender.com”. Если он получает ответ 250 (продолжайте), то все ок – отправитель существует. Если же получает “550″ (user unknown), значит отправитель не существует и нам шлют письмо с поддельным адресом отправителя и это письмо можно отвергнуть. Но здесь палка о двух концах: с одной стороны поддельный адрес – это нехорошо, это скорее всего спам. С другой стороны существует немало честных рассылок, правда настроенных непонятно кем, когда рассылка идет с несуществующего адреса. И фильтровать такие рассылки только потому, что они криво настроены тоже не вариант. В общем стоит ли использовать sender verify или нет – мнения разделяются, но я бы рекомендовал все-таки включить sender verify, а сталкиваясь с криво настроенными рассылками – добавлять их в список исключений. Соответствующие директивы в конфиге postfix: reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unverified_sender.

N.B. Если Вы настраиваете почтовую рассылку, которая не требует ответов, то потрудитесь создать почтовый ящик от имени которого идёт рассылка. Можете не читать его, можете планировщиком (например cron для *nix) удалять из него сообщения каждую ночь, можете что хотите делать с сообщениями в этом ящике, ноящик должен существовать.

RCPT TO. На стадии rcpt to мы получаем адрес того, кому предназначено письмо. Данные из rcpt to мы можем точно также подвергнуть проверке, как и helo, и mail from. Что же мы можем проверить? Мы можем проверить правильно ли указан адрес получателя, является ли он FQDN адресом. Обслуживаем ли мы домен, на ящик которого нам собираются передать письмо. Существует ли в обслуживаемом нами домене ящик, на который собираются передать письмо. Если почтовый ящик получателя не являет собой FQDN имя (например rcvuser@examplereceiver вместо rcvuser@examplereceiver.com), то такое письмо можно отклонить. Если нам передают письмо для пользователя из домена, который мы не обслуживаем (напримерsomeuser@somedomain.com), то его мы тоже отклоняем. Тоже самое с несуществующими пользователями в локальных доменах – отклоняем. Соответствующие директивы в конфиге postfix: reject_non_fqdn_recipient,reject_unauth_destination, reject_unlisted_recipient.

DNSBL. Суть работы фильтра DNSBL сводится к тому, принимающая сторона может проверить наличие/отсутствие IP адреса отправляющей стороны в черном списке и принять решения что делать с письмом. При этом, обычно, держателем черных списков выступает третья сторона. Соответствующие директивы в конфиге postfix:reject_rbl_client. Внимание! Никогда не используйте эту опцию!

Greylisting. Серый список. Работа грейлистинга основывается на том, что поведение клиентов рассылающих спам отличается от поведения честных почтовых серверов. В ходе SMTP сессии грейлист отдает клиенту ошибку с кодом (4xx), который означает “временная ошибка, попробуйте повторить позже”. Честный почтовый сервер через время обязательно предпримет попытку повторной доставки, поскольку умеет держать очередь почтовых сообщений. Спамеры же в свою очередь очередей не держат, это продиктовано огромными объемами рассылок, для них держать очередь сообщений просто нецелесообразно. В итоге получается так, что честное письмо немного задерживается (обычно 15-30 мин), затем отправитель заносится в белый список как честный отправитель и в последствии сообщения от него приходят без задержек. Спамеры же отсеиваются, не предпринимая попытки повторной доставки. Соответствующие директивы в конфиге postfix: check_policy_service.

Контент-фильтры. До этого мы рассматривали варианты фильтрации, когда фильтры оперируют данными из начальных стадий SMTP сессии. Контент фильтры же в свою очередь анализируют тело письма. Примеры контент-фильтров: ClamAV, Spamassassin, DSPAM.

Как фильтровать правильно?

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

Проверка

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

антивирус

X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H* антиспам

XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X Postfixadmin

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

Скачаем последнюю версию в сайта

http://sourceforge.net/projects/postfixadmin/

Копирование и настройка виртуального домена под postfixadmin оставляю за вами. Тут я только опишу настройку самого postfixadmin.

config.inc.php

$CONF['configured'] = true;
$CONF['setup_password'] = 'changeme';
$CONF['default_language'] = 'ru';
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'HOST';
$CONF['database_user'] = 'USER';
$CONF['database_password'] = 'PASSWORD';
$CONF['database_name'] = 'DB';
$CONF['admin_email'] = 'admin@example.com';
$CONF['smtp_server'] = 'mail.example.com';
$CONF['page_size'] = '20';
$CONF['default_aliases'] = array (
    'abuse' => 'abuse@nuft.edu.ua',
    'hostmaster' => 'hostmaster@nuft.edu.ua',
    'postmaster' => 'postmaster@nuft.edu.ua',
    'webmaster' => 'webmaster@nuft.edu.ua'
);
$CONF['quota'] = 'YES';
$CONF['used_quotas'] = 'YES';
$CONF['vacation_domain'] = 'autoreply.example.com';
$CONF['footer_text'] = 'Return to example.com';
$CONF['footer_link'] = 'http://example.com';
Где подставим

HOST = адрес MySQL сервера DB = имя базы данных USER = имя пользоватья для подключения в базе PASSWORD = его пароль Еще момент

По умолчанию, postfixadmin не физически удаляет ящики после удаления из базы. В config.inc.php есть опции предусмотренные для исправления такой ситуации, но это будет работать только если postfixadmin установлен на том же сервере где и вся почтовая система. У меня разнесенная архитектура, потому для меня такой вариант не подходит, потому на просторах интернета был найден скрипт, который по cron'у запускается каждую ночь и ищет ящики которых нет в базе, но которые есть на сервере. После такой сверки он «подчищает» после postfixadmin'a следы. Сообщественно установить скрипт можно вот так:

wget http://thelinuxforce.org/upload/files/cleanupdirs.tar
tar xvf cleanupdirs.tar
cp -f cleanupdirs.pl /usr/local/sbin/
chmod +x /usr/local/sbin/cleanupdirs.pl
touch /var/log/removed_maildirs.log
В самом скрипте нужно поправить подключение к базе данных postfixadmin по аналогии как мы делали раньше.

Далее установим задачу для cron

crontab -e добавим туда

30 0 * * * /usr/local/sbin/cleanupdirs.pl