Difference between revisions of "Postfix (2.9)"
Line 10: | Line 10: | ||
While it does not solve all spam, it makes what is left a great deal more manageable. The resulting successful spam-friendly providers get addressed in one fashion or another. | While it does not solve all spam, it makes what is left a great deal more manageable. The resulting successful spam-friendly providers get addressed in one fashion or another. | ||
+ | |||
+ | To start, after postfix is installed, run | ||
+ | postalias /etc/aliases | ||
+ | |||
+ | We will still be using these (occasionally). | ||
== /etc/postfix/main.cf == | == /etc/postfix/main.cf == | ||
Line 52: | Line 57: | ||
alias_maps = hash:/etc/aliases | alias_maps = hash:/etc/aliases | ||
alias_database = hash:/etc/aliases | alias_database = hash:/etc/aliases | ||
+ | # If you have multiple servers across the Internet, but want them all to send mail to the same machine, | ||
+ | # be sure to set myorigin to the one primary domain you want to use. | ||
myorigin = example.com | myorigin = example.com | ||
mydestination = examplename, localhost, , | mydestination = examplename, localhost, , | ||
+ | # Leave this blank if this is your main mx, otherwise, set it to your primary mailserver where you are directing mail: | ||
+ | # relayhost = mail.example.com | ||
+ | # Assuming mail.example.com is your highest-priority mx. | ||
relayhost = | relayhost = | ||
# In mynetworks, IPv6 addresses need to be in brackets, like so. | # In mynetworks, IPv6 addresses need to be in brackets, like so. | ||
mynetworks = 127.0.0.0/8 [::1]/128 198.51.100.187 [2001:db8::4]/128 | mynetworks = 127.0.0.0/8 [::1]/128 198.51.100.187 [2001:db8::4]/128 | ||
+ | # Make sure the ips of any secondary mxes are listed in mynetworks. | ||
mailbox_size_limit = 0 | mailbox_size_limit = 0 | ||
# Having a nonstandard recipient delimiter is exceedingly handy. | # Having a nonstandard recipient delimiter is exceedingly handy. | ||
recipient_delimiter = _ | recipient_delimiter = _ | ||
+ | # You may not want all of them on. | ||
inet_interfaces = all | inet_interfaces = all | ||
html_directory = /usr/share/doc/postfix/html | html_directory = /usr/share/doc/postfix/html |
Revision as of 21:40, 7 May 2014
The following describes a postfix site installation, using MySQL as a backend and Dovecot as the MDA. You will want to get nearly everything else regarding your mail working first - MySQL, the tables, and any components you may be using (ClamAV, Spamassassin, OpenDKIM), etc.
This installation is somewhat involved - but between it and the Spamassassin configuration given, you will have very little spam to deal with. Barely a piece of spam a day even makes it to spamassassin - and this is with e-mail addresses that have been public for years. About than one in a thousand make it through Spamassassin. My gmail accounts are let more spam through than this.
There are three key rules that drastically cut down on spam:
- Requiring forward-confirmed reverse DNS (reject_unknown_client_hostname in the following config)
- Block generic domain names that pass the above test.
- Block spammers claiming to be your users.
While it does not solve all spam, it makes what is left a great deal more manageable. The resulting successful spam-friendly providers get addressed in one fashion or another.
To start, after postfix is installed, run
postalias /etc/aliases
We will still be using these (occasionally).
/etc/postfix/main.cf
# There's not much left of Debian's default postfix configuration here.
smtpd_banner = $myhostname ESMTP $mail_name 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 = /usr/share/doc/postfix
# TLS parameters # This should probably be done master.cf, but that file is ugly enough. smtpd_tls_cert_file=/etc/maincert/example.crt smtpd_tls_key_file=/etc/maincert/example.key smtpd_use_tls=yes smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache smtpd_sasl_security_options = noanonymous smtpd_tls_protocols = TLSv1, SSLv3 smtp_tls_block_early_mail_reply = yes smtp_tls_mandatory_ciphers = high smtp_tls_exclude_ciphers = aNULL, NULL, MD5, ADH # smtpd_sasl_auth_enable = yes
# Because we will be using dovecot... smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth
# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for # information on enabling SSL in the smtp client.
myhostname = mail.example.com # Most providers still use IPv4. Mailservers prefer to use IPv6 if they can, Google's among them. smtp_bind_address = 68.233.227.82 smtp_bind_address6 = 2604:4500:0:7:3::2 alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases # If you have multiple servers across the Internet, but want them all to send mail to the same machine, # be sure to set myorigin to the one primary domain you want to use. myorigin = example.com mydestination = examplename, localhost, , # Leave this blank if this is your main mx, otherwise, set it to your primary mailserver where you are directing mail: # relayhost = mail.example.com # Assuming mail.example.com is your highest-priority mx. relayhost = # In mynetworks, IPv6 addresses need to be in brackets, like so. mynetworks = 127.0.0.0/8 [::1]/128 198.51.100.187 [2001:db8::4]/128 # Make sure the ips of any secondary mxes are listed in mynetworks. mailbox_size_limit = 0 # Having a nonstandard recipient delimiter is exceedingly handy. recipient_delimiter = _ # You may not want all of them on. inet_interfaces = all html_directory = /usr/share/doc/postfix/html
# Be strict. Somewhat. smtpd_hard_error_limit = 3 smtpd_soft_error_limit = 1 smtpd_junk_command_limit = 20 smtpd_helo_required = yes disable_vrfy_command = no strict_rfc821_envelopes = no
# The next five lines were when I was dealing with Yahoo headaches. The defaults are probably fine. maximal_backoff_time = 19200s qmgr_message_active_limit = 65000 qmgr_message_recipient_limit = 65000 bounce_queue_lifetime = 1w maximal_queue_lifetime = 1w
message_size_limit = 33554432
authorized_submit_users = !banusera, !banusertoo, static:all
# Milters milter_default_action = accept milter_protocol = 2 smtpd_milters = local:/var/run/opendkim/opendkim.sock non_smtpd_milters = local:/var/run/opendkim/opendkim.sock
# Blocking non-FCrDNS hostnames stops about 300 pieces of spam per day, generic hostnames about 100. This would be much worse if they weren't blocked. smtpd_client_restrictions = permit_mynetworks, reject_unknown_client_hostname, reject_unauth_pipelining, check_client_access pcre:/etc/postfix/valid-domains, check_client_access pcre:/etc/postfix/reject-domains, permit
# reject-mydomains got hit hundreds of times per day just after turning it on. Have not had a peep lately. smtpd_helo_restrictions = permit_mynetworks, check_helo_access pcre:/etc/postfix/reject-nomailfrom, check_helo_access mysql:/etc/postfix/reject-mydomains.cf, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, permit
smtpd_sender_restrictions = permit_mynetworks, check_sender_access pcre:/etc/postfix/reject-nomailfrom, check_sender_access mysql:/etc/postfix/reject-mydomains.cf, reject_non_fqdn_sender, reject_unknown_sender_domain, permit
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination, check_recipient_access pcre:/etc/postfix/reject-users, reject_non_fqdn_recipient, permit
# Currently such a rare occurance that I don't see the need to discriminate yet. Saved for posterity, though. # These block 'new' domains. See spameatingmonkey.net for details. # reject_rhsbl_client fresh15.spameatingmonkey.net, # reject_rhsbl_helo fresh15.spameatingmonkey.net, # reject_rhsbl_sender fresh15.spameatingmonkey.net,
smtpd_data_restrictions = permit_mynetworks, reject_multi_recipient_bounce, permit
virtual_mailbox_base = /var/vmail/ virtual_mailbox_limit = 536870912 virtual_minimum_uid = 999 virtual_uid_maps = static:999 virtual_gid_maps = static:999 virtual_mailbox_domains = mysql:/etc/postfix/virtual-domains.cf smtpd_sender_login_maps = mysql:/etc/postfix/virtual-accounts.cf virtual_mailbox_maps = mysql:/etc/postfix/virtual-users.cf virtual_alias_maps = mysql:/etc/postfix/virtual-aliases.cf virtual_transport = dovecot
dovecot_destination_recipient_limit = 1 spamassassin_destination_recipient_limit = 1
sender_dependent_default_transport_maps = pcre:/etc/postfix/sdd_transport_maps
/etc/postfix/master.cf
# Some of this stuff covers a few odd things you may want to do, I will highlight # them in these comments. # # Postfix master process configuration file. For details on the format # of the file, see the master(5) manual page (command: "man 5 master"). # # Do not forget to execute "postfix reload" after editing this file. # # ========================================================================== # service type private unpriv chroot wakeup maxproc command + args # (yes) (yes) (yes) (never) (100) # ========================================================================== localhost:smtp inet n - n - - smtpd -o smtpd_sasl_auth_enable=yes # Run spamassassin and clamav only on incoming mail. 198.51.100.187:smtp inet n - n - - smtpd -o content_filter=spamassassin -o smtpd_milters=local:/var/run/clamav/clamav-milter.ctl [2001:db8::4]:smtp inet n - n - - smtpd -o content_filter=spamassassin -o smtpd_milters=local:/var/run/clamav/clamav-milter.ctl # I use the submission port to actually accept mail from users, including my own forums. # They need different rules, obviously. 198.51.100.187:submission inet n - n - - smtpd -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_client_recipient_rate_limit=60 -o smtpd_client_message_rate_limit=60 -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o smtpd_helo_restrictions=permit -o smtpd_sender_restrictions=reject_sender_login_mismatch,permit -o smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject -o smtpd_data_restrictions=permit -o cleanup_service_name=submission_cleanup -o milter_macro_daemon_name=ORIGINATING [2001:db8::4]:submission inet n - n - - smtpd -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_client_recipient_rate_limit=60 -o smtpd_client_message_rate_limit=60 -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o smtpd_helo_restrictions=permit -o smtpd_sender_restrictions=reject_sender_login_mismatch,permit -o smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject -o smtpd_data_restrictions=permit -o cleanup_service_name=submission_cleanup -o milter_macro_daemon_name=ORIGINATING # Some policies may suggest that you setup a second mailing ip to segregate e.g. marketing mail from your # more mission-critical mail. 'secondmailer' here and in sdd_transport_maps shows how to go about this. secondmailer unix - - n - - smtp -o smtp_bind_address=secondmaileripv4address -o smtp_bind_address6=secondmaileripv6address -o myhostname=example.com -o myorigin=example.com -o smtp_helo_name=example.com -o syslog_name=postfix-example # The second mailer acts as its own mailserver, down to receiving mail. secondmaileripv4address:smtp inet n - n - - smtpd -o content_filter=spamassassin -o myhostname=example.com -o myorigin=example.com -o syslog_name=postfix-example -o smtpd_milters=local:/var/run/clamav/clamav-milter.ctl [secondmaileripv6address]:smtp inet n - n - - smtpd -o content_filter=spamassassin -o myhostname=example.com -o myorigin=example.com -o syslog_name=postfix-example -o smtpd_milters=local:/var/run/clamav/clamav-milter.ctl #smtp inet n - - - - smtpd #smtp inet n - - - 1 postscreen #smtpd pass - - - - - smtpd #dnsblog unix - - - - 0 dnsblog #tlsproxy unix - - - - 0 tlsproxy #submission inet n - - - - smtpd # -o syslog_name=postfix/submission # -o smtpd_tls_security_level=encrypt # -o smtpd_sasl_auth_enable=yes # -o smtpd_client_restrictions=permit_sasl_authenticated,reject # -o milter_macro_daemon_name=ORIGINATING #smtps inet n - - - - smtpd # -o syslog_name=postfix/smtps # -o smtpd_tls_wrappermode=yes # -o smtpd_sasl_auth_enable=yes # -o smtpd_client_restrictions=permit_sasl_authenticated,reject # -o milter_macro_daemon_name=ORIGINATING #628 inet n - - - - qmqpd pickup fifo n - - 60 1 pickup cleanup unix n - n - 0 cleanup # Cleanup for header checks. This prevents user's IP addresses from leaking # out to nosy people. submission_cleanup unix n - n - 0 cleanup -o header_checks=pcre:/etc/postfix/header_checks -o syslog_name=postfix/submission/cleanup qmgr fifo n - n 300 1 qmgr #qmgr fifo n - n 300 1 oqmgr tlsmgr unix - - - 1000? 1 tlsmgr rewrite unix - - n - - trivial-rewrite bounce unix - - - - 0 bounce defer unix - - - - 0 bounce trace unix - - - - 0 bounce verify unix - - - - 1 verify flush unix n - - 1000? 0 flush proxymap unix - - n - - proxymap proxywrite unix - - n - 1 proxymap smtp unix - - - - - smtp relay unix - - - - - smtp # -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 showq unix n - - - - showq error unix - - - - - error retry unix - - - - - error discard unix - - - - - discard local unix - n n - - local virtual unix - n n - - virtual lmtp unix - - - - - lmtp anvil unix - - - - 1 anvil scache unix - - - - 1 scache # # ==================================================================== # Interfaces to non-Postfix software. Be sure to examine the manual # pages of the non-Postfix software to find out what options it wants. # # Many of the following services use the Postfix pipe(8) delivery # agent. See the pipe(8) man page for information about ${recipient} # and other message envelope options. # ==================================================================== # # maildrop. See the Postfix MAILDROP_README file for details. # Also specify in main.cf: maildrop_destination_recipient_limit=1 # maildrop unix - n n - - pipe flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient} # # ==================================================================== # # Recent Cyrus versions can use the existing "lmtp" master.cf entry. # # Specify in cyrus.conf: # lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4 # # Specify in main.cf one or more of the following: # mailbox_transport = lmtp:inet:localhost # virtual_transport = lmtp:inet:localhost # # ==================================================================== # # Cyrus 2.1.5 (Amos Gouaux) # Also specify in main.cf: cyrus_destination_recipient_limit=1 # #cyrus unix - n n - - pipe # user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user} # # ==================================================================== # Old example of delivery via Cyrus. # #old-cyrus unix - n n - - pipe # flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user} # # ==================================================================== # # See the Postfix UUCP_README file for configuration details. # uucp unix - n n - - pipe flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) # # Other external delivery methods. # ifmail unix - n n - - pipe flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) bsmtp unix - n n - - pipe flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient scalemail-backend unix - n n - 2 pipe flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension} mailman unix - n n - - pipe flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user} # The following are for dovecot and spamassassin, obviously. # -m ${extension} lets us sent delimited mail straight to the appropriate folder. dovecot unix - n n - - pipe flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${user}@${nexthop} -m ${extension} spamassassin unix - n n - - pipe user=debian-spamd argv=/usr/bin/spamc -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
Supporting Files
You might have noticed that the above configuration refers to a lot of supporting map files. Some of these are optional, others are highly recommended.
/etc/postfix/header_checks
# This gets run through on cleanup, via cleanup_submission. You can see the chain for this in master.cf # Here we delete a few common identifying marks, and replace the Received header with something explanatory. /^Received: from/ REPLACE Received: from localhost (::1) (authenticated client) /^X-Originating-IP:/ IGNORE /^User-Agent:/ IGNORE /^X-Mailer:/ IGNORE
/etc/postfix/valid-domains
# Some large mailer domains are starting to use names that are beginning # to look a lot like generic names. Here we have a couple of catch-alls, # covering Google, Yahoo, AoL, Amazon, and many common providers. # Hotmail is off in lalaland, so they need their own entry. # Note that the goal here is in general to be forgiving - so long as we # know that someone owning an ip and a domain name gave some thought to it. /(^|-|\.)mail(\-|\.)/i OK /(^|-|\.)mx(\-|\.)/i OK /(^|-|\.)smtp(\-|\.)/i OK /\.hotmail\.com$/ OK
/etc/postfix/reject-domains
# The first two represend the overwhelming majority of these blocks. # Some legitimate people have not bothered to give themselves a proper domain name, # but frankly I'm not opening myself up again just to put up with their ignorance. /(^|-|\.)[0-9a-f]{2}(\-+|\.)[0-9a-f]{2}(\-+|\.)[0-9]*[a-z]+/i REJECT 554 Dynamic or Generic Hostname /(^|-|\.)[0-9]+(\-+|\.)[0-9]+(\-+|\.)[0-9]*[a-z]+/i REJECT 554 Dynamic or Generic Hostname /(^|-|\.)(vps)[0-9]{2,}/i REJECT 554 Dynamic or Generic Hostname /(^|-|\.)[a-z]?[0-9a-f]{4,}(\-+|\.)(dip|dyn|pool)/i REJECT 554 Dynamic or Generic Hostname
/etc/postfix/reject-nomailfrom
This is a completely optional file. If you have a big site that generates a lot of e-mail, you may want to use this on typoed domains, alternate tlds, etc. that you own. My server sends nearly a quarter-million e-mails per month - I almost never see this get hit.
/(^|@)([a-z0-9-]+\.)*example\.org$/ REJECT 554 Domain does not send mail. /(^|@)([a-z0-9-]+\.)*example\.net$/ REJECT 554 Domain does not send mail. /(^|@)([a-z0-9-]+\.)*example\.biz$/ REJECT 554 Domain does not send mail. /(^|@)([a-z0-9-]+\.)*example\.info$/ REJECT 554 Domain does not send mail.
/etc/postfix/reject-users
# I use this to hide my admin user or users - those with su access (whether to root or not). /^admin1@(local|example)\./ REJECT 550 User unknown /^admin2@(local|example)\./ REJECT 550 User unknown /^admin4@(local|example)\./ REJECT 550 User unknown
/etc/postfix/sdd_transport_maps
# This lets you run what amounts to multiple mailservers off of a single postfix instance, # in the event that you want to segregate classes of mail. /@example\.com$/ secondmailerexample: #/@example\.org$/ exampleorgmailer:
/etc/postfix/reject-mydomains.cf
# Some of the most revolting spam is stuff that gets sent claiming to be you. It confuses users # who don't know what's going on and pisses off those who do. Shut that down. hosts = unix:/var/run/mysqld/mysqld.sock user = vmreader password = passforvmreader dbname = mail query = SELECT CONCAT('REJECT 554 You are not ',domain_name) FROM mail_domains WHERE active=1 AND domain_name='%s' OR '%s' LIKE CONCAT('%%.',domain_name)
/etc/postfix/virtual-accounts.cf
# WARNING! # The underscore passed to SUBSTRING_INDEX here is because I'm using that as the recipient delimiter. If you use a different one in main.cf, you will want to # change it in SUBSTRING_INDEX here. This allows people to send mail as their aliases, delimited addresses included. hosts = unix:/var/run/mysqld/mysqld.sock user = vmreader password = passforvmreader dbname = mail query = (SELECT DISTINCT(CONCAT(u.username,'@',d.domain_name)) AS account FROM mail_users AS u, mail_domains AS d WHERE u.isactive >= 1 AND d.ID_DOMAIN=u.ID_DOMAIN AND d.domain_name='%d' AND u.username=SUBSTRING_INDEX('%u', '_', 1)) UNION (SELECT DISTINCT(CONCAT(u.username,'@',d.domain_name)) AS account FROM mail_aliases AS v, mail_users AS u, mail_domains AS d, mail_domains AS da WHERE v.ID_USER=u.id_USER AND u.ID_DOMAIN=d.ID_DOMAIN AND v.ID_DOMAIN=da.ID_DOMAIN AND da.domain_name='%d' AND v.alias_local='%u')
/etc/postfix/virtual-aliases.cf
# Sortof the inverse of the above - instead of letting us know who can send from a given address, this tells us where mail for a given address goes to. hosts = unix:/var/run/mysqld/mysqld.sock user = vmreader password = passforvmreader dbname = mail query = SELECT DISTINCT(CONCAT(u.username,v.alias_ext,'@',d.domain_name)) FROM mail_aliases AS v, mail_users AS u, mail_domains AS d, mail_domains AS da WHERE v.ID_USER=u.id_USER AND u.ID_DOMAIN=d.ID_DOMAIN AND v.ID_DOMAIN=da.ID_DOMAIN AND da.domain_name='%d' AND v.alias_local='%u'
/etc/postfix/virtual-domains.cf
# By far the simplest of these. hosts = unix:/var/run/mysqld/mysqld.sock user = vmreader password = passforvmreader dbname = mail query = SELECT 1 FROM mail_domains WHERE active=1 AND domain_name='%s'
/etc/postfix/virtual-users.cf
# Like above - just checks if a user exists. hosts = unix:/var/run/mysqld/mysqld.sock user = vmreader password = passforvmreader dbname = mail query = SELECT 1 FROM mail_users AS u, mail_domains AS d WHERE u.isactive >= 1 AND d.ID_DOMAIN=u.ID_DOMAIN AND d.domain_name='%d' AND u.username='%u'