Pull to refresh

how-to: postfix

Данная конфигурация легко справляется со «средней» сетью. В моём конкретном примере: 60 доменов, 500 ящиков, около 500 мб корреспонденции в сутки. how-to создвалось в личных целях для «скоростного» развёртывания на местности.


postfix/main.cf:

# пути
queue_directory = /var/spool/postfix
command_directory = /usr/local/sbin
daemon_directory = /usr/local/libexec/postfix
sendmail_path = /usr/local/sbin/sendmail
newaliases_path = /usr/local/bin/newaliases
html_directory = /usr/share/doc/postfix-2.3.6/html
manpage_directory = /usr/local/man
sample_directory = /usr/local/etc/postfix
mailq_path = /usr/local/bin/mailq
data_directory = /var/db/postfix
readme_directory = no

# пользователь под которым запускаем postfix
# запись в /etc/passwd: [postfix:*:125:125:Postfix Mail System:/var/spool/postfix:/usr/sbin/nologin]
mail_owner = postfix
setgid_group = maildrop
default_privs = nobody

unknown_local_recipient_reject_code = 550
maps_rbl_reject_code = 554

debug_peer_level = 4

# список подсетей которым разрешено пользоваться smtp сервером
mynetworks = 127.0.0.0/8, a.b.c.d/19, e.f.g.h/24

# банер
smtpd_banner = Mail server

# используем множество доменов
virtual_transport = virtual
virtual_uid_maps = mysql:/usr/local/etc/postfix/sql/uids.cf
virtual_gid_maps = mysql:/usr/local/etc/postfix/sql/gids.cf
virtual_alias_maps = mysql:/usr/local/etc/postfix/sql/aliases.cf
virtual_mailbox_domains = mysql:/usr/local/etc/postfix/sql/domains.cf
virtual_mailbox_maps = mysql:/usr/local/etc/postfix/sql/users.cf
# укажем где будут распологаться почтовые ящики
virtual_mailbox_base = /opt/mail
# объём ящика по умолчанию
virtual_mailbox_limit = 501200000
virtual_create_maildirsize = yes
virtual_mailbox_extended = yes
virtual_mailbox_limit_maps = mysql:/usr/local/etc/postfix/sql/quotas.cf
virtual_mailbox_limit_override = yes
virtual_maildir_limit_message = Sorry, the user's maildir has overdrawn his diskspace quota, please try again later.
virtual_overquota_bounce = yes
relay_domains = $virtual_mailbox_domains, mysql:/usr/local/etc/postfix/sql/mysql_relay_domains_maps.cf

# т.к. мы не хотим являться публичными пересыльщиками почты
smtpd_recipient_restrictions =
permit_mynetworks,
# тут будем указывать кому разрешать доступ к нашему smtp
check_recipient_access pcre:/usr/local/etc/postfix/recipient_access.pcre,
check_sender_access pcre:/usr/local/etc/postfix/sender_access.pcre
check_client_access pcre:/usr/local/etc/postfix/client_checks.pcre,
# остальные идут лесом
reject_unknown_sender_domain,
reject_unauth_destination,
reject_unknown_client,
# spamcop-ы нам в помощь, заодно разгрузим наш spamassassin
reject_rbl_client list.dsbl.org,
reject_rbl_client blackholes.mail-abuse.org,
reject_rbl_client sbl.spamhaus.org,
reject_rbl_client cbl.abuseat.org,
reject_unknown_sender_domain

# требуем от всех обязательно представляться нашему серверу
smtpd_helo_required = yes
smtpd_helo_restrictions =
permit_mynetworks,
reject_non_fqdn_hostname

# шлём всех "неизвестных" посыльщиков и почту "неизвестным" адресатам
smtpd_sender_restrictions =
reject_non_fqdn_sender,
reject_unknown_sender_domain

# максимальный размер сообщения
message_size_limit = 30690000
# время жизни отложенных писем на нашем сервере
maximal_queue_lifetime = 1d

# просматриваем заголовки (письма помеченные как спам будут идти в специально отведённый ящик)
header_checks = regexp:/usr/local/etc/postfix/header_checks

# для работы spamassassin-а нужны три правила
forwarder_destination_recipient_limit = 1
genocide_destination_recipient_limit = 1
spamfilter_destination_recipient_limit = 1

# я не использую SASL
# но вдруг кому пригодится
#SASL
#broken_sasl_auth_clients = yes
#smtpd_sasl_auth_enable = yes
#smtpd_sasl_security_options = noanonymous
#New with sasl
#smtpd_sasl_auth_enable = yes
#smtpd_sasl_security_options = noanonymous
#smtpd_sasl_local_domain = $mydestination
#smtpd_client_restrictions = permit_sasl_authenticated
#smtpd_sender_restrictions = permit_sasl_authenticated
#smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, permit_auth_destination, reject_unauth_destination

# проведём письмо через цепочку фильтров
content_filter = scan:[127.0.0.1]:10026


postfix/master.cf:

smtp inet n - n - - smtpd
pickup fifo n - n 60 1 pickup
cleanup unix n - n - 0 cleanup
qmgr fifo n - n 300 1 qmgr
#qmgr fifo n - n 300 1 oqmgr
tlsmgr unix - - n 1000? 1 tlsmgr
rewrite unix - - n - - trivial-rewrite
bounce unix - - n - 0 bounce
defer unix - - n - 0 bounce
trace unix - - n - 0 bounce
verify unix - - n - 1 verify
flush unix n - n 1000? 0 flush
proxymap unix - - n - - proxymap
smtp unix - - n - - smtp
relay unix - - n - - smtp
-o fallback_relay=
showq unix n - n - - showq
error unix - - n - - error
retry unix - - n - - error
discard unix - - n - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - n - - lmtp
anvil unix - - n - 1 anvil
scache unix - - n - 1 scache

scan unix - - n - 5 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes

127.0.0.1:10026 inet n - n - - smtpd
-o content_filter=spamfilter
-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 smtpd_error_sleep_time=0
-o smtpd_soft_error_limit=1001
-o smtpd_hard_error_limit=1000

# отдадим письмо на проверку антиспаму
spamfilter
unix - n n - 5 pipe
flags=R
user=spamd
argv=/usr/local/etc/postfix/filters/spam.pl "127.0.0.1:10027" "antispam" "${sender}" "${recipient}" "/usr/local/bin/spamc"

127.0.0.1:10027 inet n - n - - smtpd
-o content_filter=
-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 smtpd_error_sleep_time=0
-o smtpd_soft_error_limit=1001
-o smtpd_hard_error_limit=1000

proxywrite unix - - n - 1 proxymap


К сожалению, не удалось найти автора нижеприведённого скрипта. От себя хочу добавить, что данный скрипт работает быстрее всех других проверенных мною способов, даже при большой спам рассылке.

postfix/filters/spam.pl:

#!/usr/bin/perl -w
use strict;
use Net::SMTP;
my $host = &sall_ch(shift(@ARGV), '"');
my $ehlo = &sall_ch(shift(@ARGV), '"');

my $mail_from = &sall_ch(shift(@ARGV), '"');
my $rcpt_to = &sall_ch(shift(@ARGV), '"');
my $spamc = &sall_ch(shift(@ARGV), '"');

if (!defined($host)||!defined($ehlo)||!defined($mail_from)||!defined($rcpt_to))
{
die("use $0 <mail_from> <rcpt_to> [cmd]\n");
}

if (defined($spamc)) {
open(CF, "$spamc |") or undef($spamc);
}

my $smtp = Net::SMTP->new($host);
$smtp->hello($ehlo);
$smtp->mail($mail_from);
$smtp->to($rcpt_to);

$smtp->data();
if (defined($spamc)) {
while() {
next if (/^delivered\-to\:/i);
$smtp->datasend($_);
}
}
else {
while(<>) {
next if (/^delivered\-to\:/i);
$smtp->datasend($_);
}
}
$smtp->dataend();
close(CF) if defined($spamc);

$smtp->quit;
exit 0;

############################################################
sub sall_ch($$) {
my($string, $chars) = (shift(), shift());
return(undef) unless defined($string);
$string =~ s/^[\Q$chars\E]+//;
$string =~ s/[\Q$chars\E]+$//;
return($string);
}

Если письмо помечено spamassassin-ом, как спам, то шлём его куда надо. Можно и удалить, но не исключаем случай что наш антиспам может отправить туда нужное письмо. В таком случае его всегда можно будет вернуть.

postfix/header_checks:

/^X-SPAM-FLAG: YES/ REDIRECT spam@domen.ru


Подружим postfix и mysql

postfix/sql/aliases.cf:

user = наш юзер в БД
password = наш пароль в БД
dbname = имя нашей БД
table = alias
select_field = goto
where_field = address
hosts = localhost


postfix/sql/domains.cf:

user = наш юзер в БД
password = наш пароль в БД
hosts = localhost
dbname = имя нашей БД
table = domain
select_field = domain
where_field = domain


postfix/sql/gids.cf:

user = наш юзер в БД
password = наш пароль в БД
dbname = имя нашей БД
table = mailbox
select_field = 125
where_field = username
additional_conditions = and active = '1'
hosts = localhost


postfix/sql/mysql_relay_domains_maps.cf:

user = наш юзер в БД
password = наш пароль в БД
hosts = localhost
dbname = имя нашей БД
table = domain
select_field = domain
where_field = domain
additional_conditions = and backupmx = '1'


postfix/sql/quotas.cf:

user = наш юзер в БД
password = наш пароль в БД
hosts = localhost
dbname = имя нашей БД
table = mailbox
select_field = quota
where_field = username
additional_conditions = and active = '1'


postfix/sql/transport.cf:

user = наш юзер в БД
password = наш пароль в БД
dbname = имя нашей БД
table = domain
select_field = transport
where_field = domain
hosts = localhost


postfix/sql/uids.cf:

user = наш юзер в БД
password = наш пароль в БД
dbname = имя нашей БД
table = mailbox
select_field = 125
where_field = username
additional_conditions = and active = '1'
hosts = localhost


postfix/sql/users.cf:

user = наш юзер в БД
password = наш пароль в БД
hosts = localhost
dbname = имя нашей БД
table = mailbox
select_field = maildir
where_field = username
additional_conditions = and active = '1'


Здесь можем разрешить или запретить адресатов.
/(xxx.yyy.aaa.bbb)/ OK - формат для добавления IP в список разрешённых
/(client@domen.ru)/ OK - формат для добавления email в список разрешённых
И проверяем хостнейм регуляркой, в итоге отсекаем уйму спама.

postfix/client_checks.pcre:

/(modem|dia(l|lup)|cable|catv|poo(l|les)|pppoe|dhcp|client|customer|user|host|[0-9]{4,})(-|_|\.|[0-9])/ REJECT Invalid hostname (client)
/[0-9]+-[0-9]+/ REJECT Invalid hostname (D-D)


Становимся "пересыльщиком" для определённых почтовых адресов

postfix/recipient_access.pcre:

/(@domen_recipient.ru)/ OK
/(name@domen_recipient.ru)/ OK


Здесь можем разрешить или запретить отправителей.
/(xxx.yyy.aaa.bbb)/ OK - формат для добавления IP в список разрешённых
/(client@domen.ru)/ OK - формат для добавления email в список разрешённых

postfix/sender_access.pcre

/(sender@domen.ru)/ OK

authlib/authdaemonrc

authmodulelist="authmysql"
authmodulelistorig="authmysql"
daemons=5
authdaemonvar=/var/lib/courier/authdaemon
DEBUG_LOGIN=2
DEFAULTOPTIONS="wbnodsn=1"
LOGGEROPTS=""


authlib/authmysqlrc

MYSQL_SERVER localhost
MYSQL_USERNAME Пользователь БД
MYSQL_PASSWORD Пароль БД
MYSQL_SOCKET /tmp/mysql.sock
MYSQL_PORT 3306
MYSQL_OPT 0
MYSQL_DATABASE Имя БД
MYSQL_USER_TABLE mailbox
MYSQL_CRYPT_PWFIELD password
MYSQL_UID_FIELD '125'
MYSQL_GID_FIELD '125'
MYSQL_LOGIN_FIELD username
# указываем где находится "дерево почтовых ящиков" в нашей фс
MYSQL_HOME_FIELD '/opt/mail/'
MYSQL_NAME_FIELD name
MYSQL_MAILDIR_FIELD maildir
MYSQL_QUOTA_FIELD quota
MYSQL_WHERE_CLAUSE active='1'


В настройках courier менять обычно ничего не требуется.

courier-imap/imapd

ADDRESS=0
PORT=143
MAXDAEMONS=40
MAXPERIP=4
PIDFILE=/var/run/imapd.pid
TCPDOPTS="-nodnslookup -noidentlookup"
LOGGEROPTS="-name=imapd"
IMAP_CAPABILITY="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE"
IMAP_KEYWORDS=1
IMAP_ACL=1
IMAP_CAPABILITY_ORIG="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA AUTH=CRAM-MD5 AUTH=CRAM-SHA1 AUTH=CRAM-SHA256 IDLE"
IMAP_PROXY=0
IMAP_PROXY_FOREIGN=0
IMAP_IDLE_TIMEOUT=60
IMAP_MAILBOX_SANITY_CHECK=1
IMAP_CAPABILITY_TLS="$IMAP_CAPABILITY AUTH=PLAIN"
IMAP_CAPABILITY_TLS_ORIG="$IMAP_CAPABILITY_ORIG AUTH=PLAIN"
IMAP_DISABLETHREADSORT=0
IMAP_CHECK_ALL_FOLDERS=0
IMAP_OBSOLETE_CLIENT=0
IMAP_UMASK=022
IMAP_ULIMITD=65536
IMAP_USELOCKS=1
IMAP_SHAREDINDEXFILE=/usr/local/etc/courier-imap/shared/index
IMAP_ENHANCEDIDLE=0
IMAP_TRASHFOLDERNAME=Trash
IMAP_EMPTYTRASH=Trash:7
IMAP_MOVE_EXPUNGE_TO_TRASH=0
SENDMAIL=/usr/sbin/sendmail
HEADERFROM=X-IMAP-Sender
IMAPDSTART=NO
MAILDIRPATH=Maildir


courier-imap/imapd-ssl

SSLPORT=993
SSLADDRESS=0
SSLPIDFILE=/var/run/imapd-ssl.pid
SSLLOGGEROPTS="-name=imapd-ssl"
IMAPDSSLSTART=NO
IMAPDSTARTTLS=YES
IMAP_TLS_REQUIRED=0
COURIERTLS=/usr/local/bin/couriertls
TLS_KX_LIST=ALL
TLS_COMPRESSION=ALL
TLS_CERTS=X509
TLS_CERTFILE=/usr/local/share/courier-imap/imapd.pem
TLS_TRUSTCERTS=/etc/ssl/cert.pem
TLS_VERIFYPEER=NONE
TLS_CACHEFILE=/usr/local/var/couriersslcache
TLS_CACHESIZE=524288
MAILDIRPATH=Maildir


courier-imap/pop3d

PIDFILE=/var/run/pop3d.pid
MAXDAEMONS=40
MAXPERIP=4
POP3AUTH=""
POP3AUTH_ORIG="PLAIN LOGIN CRAM-MD5 CRAM-SHA1 CRAM-SHA256"
POP3AUTH_TLS=""
POP3AUTH_TLS_ORIG="LOGIN PLAIN"
POP3_PROXY=0
PORT=110
ADDRESS=0
TCPDOPTS="-nodnslookup -noidentlookup"
LOGGEROPTS="-name=pop3d"
POP3DSTART=NO
MAILDIRPATH=Maildir


courier-imap/pop3d-ssl

SSLPORT=995
SSLADDRESS=0
SSLPIDFILE=/var/run/pop3d-ssl.pid
SSLLOGGEROPTS="-name=pop3d-ssl"
POP3DSSLSTART=NO
POP3_STARTTLS=YES
POP3_TLS_REQUIRED=0
COURIERTLS=/usr/local/bin/couriertls
TLS_STARTTLS_PROTOCOL=TLS1
TLS_KX_LIST=ALL
TLS_COMPRESSION=ALL
TLS_CERTS=X509
TLS_CERTFILE=/usr/local/share/courier-imap/pop3d.pem
TLS_TRUSTCERTS=/etc/ssl/cert.pem
TLS_VERIFYPEER=NONE
TLS_CACHEFILE=/usr/local/var/couriersslcache
TLS_CACHESIZE=524288
MAILDIRPATH=Maildir


mail/spamassassin/local.cf

# Пометим заголовок спамовских писем...
rewrite_header Subject *****SPAM***** ( _HITS_ )

# Оставим спам как есть (0: off, 2: use text/plain instead)
report_safe 1

# Заведомо хорошая подсеть (не спам)
trusted_networks 172.22.1.0/24

# Самое важное число, уровень реагирования на спам
# чем меньше тем более "жестокая" политика
required_score 5.0
skip_rbl_checks 1

# используем BAYES
# Для справки: Томас Байес - математик который занимался теорией вероятности
# и придумал теорему Байеса. На основе которой мы и определяем спам. use_bayes 1

# Автообучение
bayes_auto_learn 1
#bayes_path /etc/spamassassin/bayes/
bayes_ignore_header X-Bogosity
bayes_ignore_header X-Spam-Flag
bayes_ignore_header X-Spam-Status

# Белые и черные списки
#bayes_ignore_from
#bayes_ignore_to
#bayes_ignore_from
#bayes_ignore_to
#whitelist_from
#whitelsit_to
#blacklist_to
#blacklist_from

ok_locales ru en
report_charset utf8
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.