This is an old revision of the document!
Configuration: postfix
We need to configure Postfix properly, and link it to the SQLite database we created so that it will read domains and accounts from there.
Postfix configuration files are located under /etc/postfix and can be summarized as:
- main.cf: contains all the oeprative directives of Postfix
- master.cf: contains the services started by Postfix
- sql/*.cf: the specific SQLite link files. You need to create this folder.
The concept of virtual delivery comes from the legacy idea that the mail server delivers mail to local users on the local server. Of course, this has not been true for the last (too many) decades, but the concept still stand and Postfix talks about virtual delivery to differentiate from delivery mail to local server users.
Please note that Postfix configuration is deeply connected to Dovecot, Spamassassin, OpenDKIM and OpenDMARC. The following configuration assumes you have already configured them all. So before you start Postfix you will need to set them up as well. See the relevant pages.
Before configuring Postfix, it is recomended to read this page.
SQL Link
Postfix support all kinds of SQL databases, including SQLite. To integrate it, you need to create a few cf files and specify associated directives in the main.cf.
Create the sql folder:
mkdir /etc/postfix/sql
Drop all the following files in the sql folder.
File: /etc/postfix/sql/virtual_mailbox_domains.cf which fetch the list of domains:
- virtual_mailbox_domains.cf
dbpath = /home/vmail/database/vmail.sqlite3 query = SELECT domain FROM domain WHERE domain = '%s' AND backupmx = '0' AND active = '1';
File: /etc/postfix/sql/virtual_mailbox_maps.cf which fetch the list of mailboxes:
- virtual_mailbox_maps.cf
dbpath = /home/vmail/database/vmail.sqlite3 query = SELECT maildir FROM mailbox WHERE local_part='%u' AND domain='%d' AND active='1';
File: /etc/postfix/sql/virtual_alias_maps.cf which fetch the list of accounts and aliases:
- virtual_alias_maps.cf
dbpath = /home/vmail/database/vmail.sqlite3 query = SELECT goto FROM alias WHERE address='%s' AND active='1';
To ensure the above files are used by postfix, the following lines need to be added to the main.cf config file:
# A list of all virtual domains serviced by this instance of postfix. virtual_mailbox_domains = sqlite:/etc/postfix/sql/virtual_mailbox_domains.cf # Look up the mailbox location based on the email address received. virtual_mailbox_maps = sqlite:/etc/postfix/sql/virtual_mailbox_maps.cf # Any aliases that are supported by this system virtual_alias_maps = sqlite:/etc/postfix/sql/virtual_alias_maps.cf
The example files at the bottom of this page will include those lines as well.
main.cf: configuration
Setting up Postfix properly is not an easy task. I will guide you trough my experience and will try to describe the main stuff you need to setup here.
I will list and try to describe all the settings in the example file below here:
- compatibility_level: refer to the syntax used in the configuration and the minimum Postfix version.
- soft_bounce: if yes, local generated emails that bounce will not be discarded. This is useful during testing of the server, until everything is properly setup. You should set it to no afterward.
- queue_directory, command_directory, daemon_directory, data_directory, sendmail_path, newaliases_path, mailq_path: do not edit, these are postfix standard paths.
- mail_owner: the user used my postfix to run. Do not change it. Don't, really.
- setgid_group: do not edit, like above
- myhostname: set this to the domain part of your FQDN. If you host more than one domain, pick the main one.
- mydomain: set this to the domain part of your FQDN. If you host more than one domain, pick the main one (yes, the same as above).
- myorigin: set for local generated mail. Set it to your main domain.
- inet_interfaces: on which interfaces postfix should listen on. All is the usual default.
- mydestination: which email destination domains should be delivered to this server. This does not include the virtual domains. On modern servers, leave it to localhost.localdomain.
- local_recipient_maps: leave this commented, you do not want to deliver emails to local users of the server.
- unknown_lo#relay_domainscal_recipient_reject_code: 550 will cause messages to be discarded, while 450 will have upstream servers try again to send the mail, when the destination user does not exist. Since you will use the SQLite virtual maps, it's safe to use 550 here.
- mynetworks_style: leave it as host. This means that trusted hosts will only be the server itself
- relay_domains: for which domains this server will relay mail. Leave it blank or don't set it at all!
- in_flow_delay: throttle incoming mails to 1 per second under heavy loads. It's a good idea to set it to at least 1 (maximum is 10).
- home_mailbox: name of folder where to store incoming messages. This will then be picked up by Dovecot later on for IMAP access.
- smtpd_banner: define how Postfix will reply to other servers connecting to it. It's a good choice not to reply with software version or postfix.
- html_directory, readme_directory: leave to no, you don't want to expose postfix documentation
- inet_protocols: which protocol to use. ipv4 is the typical one. You can feel lucky and enable also IPv6.
- meta_directory, shlib_directory: don't touch them
- virtual_mailbox_domains, virtual_mailbox_maps, virtual_alias_maps: see the SQL link section above
- virtual_mailbox_base: where postfix will store the incoming emails
- local_transport: set to virtual, since you want virtual delivery
- biff: enable or disable the use of biff to notify local users of incoming email. There are no local users as already stated, so disable it.
- message_size_limit: set maximum email message size. 0 to disable any size check.
- disable_vrfy_command: prevent email harvesting via VRFY command. Set to yes.
- local_recipient_maps: allow local delivery for your users. Set to your virtual map
- virtual_transport: which transport to use for virtual delivery. Set as below to use dovecot delivery.
- virtual_uid_maps, virtual_gid_maps: UID and GID to use for virtual maps. Match your vmail user.
Also check the SASL and TLS related rows, as enabling encryption layer and authentication is mandatory from a security point of view. For the TLS settings, smtpd_tls_auth_only should be set to yes to prevent unencrypted transfer of passwords.
The spam filtering rows require you to have setup spamassassin too.
For more details on all the possible options, see Postfix documentation.
This is the overall file. Do not copy it blindly, double check everything:
- main.cf
compatibility_level = 3.9 soft_bounce = yes queue_directory = /var/spool/postfix command_directory = /usr/sbin daemon_directory = /usr/libexec/postfix data_directory = /var/lib/postfix mail_owner = postfix myhostname = mydomain.com mydomain = mydomain.com myorigin = $mydomain inet_interfaces = all mydestination = localhost.localdomain unknown_local_recipient_reject_code = 550 mynetworks_style = host in_flow_delay = 1s home_mailbox = .maildir/ smtpd_banner = $myhostname ESMTP NO UCE sendmail_path = /usr/sbin/sendmail newaliases_path = /usr/bin/newaliases mailq_path = /usr/bin/mailq setgid_group = postdrop html_directory = no readme_directory = no inet_protocols = ipv4 meta_directory = /etc/postfix shlib_directory = /usr/lib64/postfix/${mail_version} virtual_mailbox_domains = sqlite:/etc/postfix/sql/virtual_mailbox_domains.cf virtual_mailbox_maps = sqlite:/etc/postfix/sql/virtual_mailbox_maps.cf virtual_alias_maps = sqlite:/etc/postfix/sql/virtual_alias_maps.cf virtual_mailbox_base = /home/vmail/storage local_transport = virtual biff = no message_size_limit = 0 disable_vrfy_command = yes local_recipient_maps = $alias_maps $virtual_mailbox_maps virtual_transport = lmtp:unix:private/dovecot-lmtp virtual_uid_maps = static:5000 virtual_gid_maps = static:5000 # SASL - The following rows for SASL authentication smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_auth_enable = yes smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = broken_sasl_auth_clients = no smtpd_sasl_authenticated_header = yes # Setup TLS - use Let's Encrypt certificates smtpd_tls_cert_file = /etc/letsencrypt/live/mail.mydomain.com/fullchain.pem smtpd_tls_key_file = /etc/letsencrypt/live/mail.mydomain.com/privkey.pem smtpd_tls_loglevel = 0 smtpd_tls_security_level = may smtpd_tls_auth_only = yes smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_scache # Some ANTISPAM smtpd_delay_reject = yes smtpd_helo_required = yes smtpd_helo_restrictions = permit_mynetworks, reject_invalid_hostname, permit smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unknown_sender_domain, reject_non_fqdn_sender, permit smtpd_recipient_restrictions = reject_unauth_pipelining, reject_unknown_recipient_domain, permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, reject_non_fqdn_recipient, check_policy_service unix:private/policy-spf, permit smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated #, reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net body_checks = regexp:/etc/postfix/body_checks # DKIM, SPF, DMARC connection smtpd_milters = unix:/var/run/opendkim/opendkim.sock,unix:/var/run/opendmarc/opendmarc.sock non_smtpd_milters = unix:/var/run/opendkim/opendkim.sock,unix:/var/run/opendmarc/opendmarc.sock # Some lmits and timeouts (adapt as needed) #policy-spf_time_limit = 3600s #default_process_limit = 200 #smtpd_timeout = 60s #smtputf8_enable = no #smtp_data_done_timeout = 1800 #maximal_queue_lifetime = 60m #bounce_queue_lifetime = 60m #smtp_connect_timeout = 15s #smtp_helo_timeout = 60s # Logging defaults syslog_facility = mail syslog_name = postfix #smtpd_relay_before_recipient_restrictions = no
The following file implements some basic checks to discard spam or worse. It's needed if you specified body_checks above.
File /etc/postfix/body_checks:
- body_checks
/Listed in Razor2/ DISCARD /RBL: Received via a relay in Spamhaus XBL/ DISCARD /Delivered to internal network by a host with no rDNS/ DISCARD /Listed in Pyzor/ DISCARD /URIBL_BLACK/ DISCARD /Content-Type only seen in 419 spam/ DISCARD /BODY: Mentions millions of/ DISCARD /BODY: Dear Beneficiary/ DISCARD /Advance Fee fraud/ DISCARD /FILL_THIS_FORM_FRAUD_PHISH/ DISCARD /RBL: Received via a relay in PSBL/ DISCARD /Delivered to internal network by a host with no rDNS/ DISCARD /Forged mail pretending to/ DISCARD /Message-Id is not valid, according to RFC 2822/ DISCARD /RCVD_IN_PSBL/ DISCARD
master.cf: configuration
The master.cf contains a list of the services (and ports) managed by Postfix on startup.
- master.cf
# # 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) (no) (never) (100) # ========================================================================== smtp inet n - n - - smtpd -o content_filter=spamassassin submission inet n - n - - smtpd -o smtpd_sasl_auth_enable=yes -o smtpd_tls_security_level=may -o smtpd_client_restrictions=permit_sasl_authenticated,reject pickup fifo n - n 60 1 pickup cleanup unix n - n - 0 cleanup qmgr fifo n - n 300 1 qmgr 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 proxywrite unix - - n - 1 proxymap smtp unix - - n - - smtp relay unix - - n - - smtp 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 policy-spf unix - n n - - spawn user=nobody argv=/usr/bin/policyd-spf spamassassin unix - n n - - pipe user=spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient} spamassassin unix - n n - - pipe user=spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
Aliases
Before starting postfix you need to generate the aliases database:
newaliases
that's it.
Generate password for auth: https://www.mailslurp.com/tools/plain-authentication-encoder/