Skip to content

Instantly share code, notes, and snippets.

@hyvanix
Last active March 24, 2021 13:35
Show Gist options
  • Save hyvanix/55c064047709f8d2e8133dd0babc250c to your computer and use it in GitHub Desktop.
Save hyvanix/55c064047709f8d2e8133dd0babc250c to your computer and use it in GitHub Desktop.

Install Postfix

The best place to start is at the beginning, so that means it's time to install Postfix.

pkg install postfix-sasl

Now that wasn't too difficult. Now on with a little bit of housekeeping to make sure Postfix is the default mail server under FreeBSD.

First start by adding the initial directives to /etc/rc.conf:

# sysrc postfix_enable="YES"
# sysrc sendmail_enable="NONE"

Next, we have to setup the mailer.conf:

# mkdir -p /usr/local/etc/mail
# install -m 0644 /usr/local/share/postfix/mailer.conf.postfix /usr/local/etc/mail/mailer.conf

And we should disable the jobs the system would normally run in regards to Sendmail in the periodic.conf file.

# cat /etc/periodic.conf
daily_clean_hoststat_enable="NO"
daily_status_mail_rejects_enable="NO"
daily_status_include_submit_mailq="NO"
daily_submit_queuerun="NO"

If it is not too much trouble, it would be good to reboot the system right about now to make sure all these changes will take effect.

Precautions

Now we are back up and running again, I would like to mention one precaution to take before starting in on any serious changes to the Postfix configuration files.

It is advisable to set set_bounce = yes as this parameter provides a limited safety net for testing. When soft_bounce is enabled, mail will remain queued that would otherwise bounce. This parameter disables locally-generated bounces, and prevents the SMTP server from rejecting mail permanently (by changing 5xx replies into 4xx replies).

The following can be appended to /usr/local/etc/postfix/main.cf.

# --------------------------------
# TEMPORARY TEST SETTINGS         
# --------------------------------
soft_bounce = yes                 

In fact, all the settings made to /usr/local/etc/postfix/main.cf will be made by appending to the file rather than editing the directeves set in the file.

Don't restart Postfix just yet as we will be making more changes to the main.cf file in the next section.

Cyrus SASL Authentication

Before jumpng into setting up Virtual Domains for Postfix, I will take care of making sure SASL Authentication is confifured for Postfix. Later we will test this Authentication, but not just yet.

The configuration of SASL is satisfied with making the following additions to /usr/local/etc/postfix/main.cf

# --------------------------------
# SASL CONFIGURATION
# --------------------------------
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = cyrus
smtpd_sasl_path = smtpd

The smtpd_sasl_path directive references the /usr/local/lib/sasl2/smtpd.conf file. This needs to be created, and should contain the following:

pwcheck_method: auxprop
auxprop_plugin: sasldb
mech_list: PLAIN LOGIN DIGEST-MD5

OK, that is enough appending to the main.cf file for now, but we will be back soon, so no need to restart Postfix just yet.

Let's Add Some Users to the Cyrus SASL Database

# saslpasswd2 pbd@example-1.net
# saslpasswd2 pbd@example-2.net
# saslpasswd2 pbd@example-3.net

Though lacking in creativity, the above takes care of creating our user accounts for multiple domains under Cyrus SASL.

Postfix Virtual Domains Configuration

Ladies & Gentleman, the part we have all been waiting for, this is the main configuration for allowing Virtual Hosts under Posfix.

You guessed it, the following can be appended to /usr/local/etc/postfix/main.cf.

# --------------------------------                                                     
# VIRTUAL DOMAINS CONFIGURATION                                                        
# --------------------------------                                                     
# This is set in anticipation of having a working cyrus imap server running in cahoots 
# with Postfix. For now, mail delivery will not work but that will be resolved in my i
# next post on setting up virtual hosts under Cyrus Imapd.
mailbox_transport = lmtp:unix:/var/imap/socket/lmtp                                    
                                                                                       
# A list of domains that Postfix will accept mail for.          
virtual_mailbox_domains = example-1.net
                          example-2.net
                          example-3.net
                                                                                       
# This is the spool directory for our hosts that we added immeadiately above.
virtual_mailbox_base = /var/mail/vhosts                                                
                                                                                       
# this is a list of mailboxes that  Postfix will deliver too. 
# When we create this file shortly, this directive will become more apparent.
virtual_mailbox_maps = hash:/usr/local/etc/postfix/vmailbox                            

# Optional lookup tables that alias specific mail addresses or domains to other 
# local or remote address. For now, this file needs to be created but will be left
# empty as I will no be configuring such intricate features in this post.
virtual_alias_maps = hash:/usr/local/etc/postfix/virtual                               
                                                                                       
# stuff that needs to be here so Postfix works =)
# Consult http://www.postfix.org/postconf.5.htm for more detail
virtual_minimum_uid = 100                                                               
virtual_uid_maps = static:125                                                           
virtual_gid_maps = static:125                                                           
                                                                                        
# The maximal size in bytes of an individual virtual(8) mailbox or maildir file, 
# or zero (no limit).
virtual_mailbox_limit = 1000000000
                                                                                        
# The default mail delivery transport and next-hop destination for final delivery 
# to domains listed with $virtual_mailbox_domains. This points to the Cyrus transport
# that was set earlier.
virtual_transport=$mailbox_transport                                                    

While I have made some inline comments, it is strongly advised to reference the Postfix VIRTUAL_README document to get a full understanding of these directives.

Hashing Maps

With this now in place, we must create databases that Postfix can read for the virtual_mailbox_maps & virtual_alias_maps directives.

This is done by creating these files and using the postmap command to create the databases, as follows:

The /usr/local/etc/postfix/vmailbox file should be as such for the purposes I am demonstrating:

pbd@example-1.net              example-1.net/pbd/
pbd@example-2.net              example-2.net/pbd/
pbd@example-3.net              example-3.net/pbd/

The /usr/local/etc/postfix/virtual will be an empty file in this instance.

postmap will create the databases as previously mentioned:

# postmap /usr/local/etc/postfix/vmailbox
# postmap /usr/local/etc/postfix/virtual

So far, so good!

... now is the time to issue a restart for Postfix.

# service postfix restart

Testing Cyrus SASL Authentication

Postfix uses base64 encoding so we have to generate our username and password in base64 so we can use in a telnet session to the mail server.

I will be telneting to localhost to avoid sending these passwords over the internet, however, you should renew these passwords after testing, just to keep a sufficient level or paranoia.

On a fresh install of FreeBSD, the program base64 is not available so can be installed as follows:

# pkg install base64

Generate Base 64 Credentials

I have used the same feeble password for all email accounts. Please, don't do this.

# echo -n 'pbd@example-1.net' |base64 
cGJkQGV4YW1wbGUtMS5uZXQ=                               
# echo -n 'pbd@example-2.net' | base64
cGJkQGV4YW1wbGUtMi5uZXQ=                               
# echo -n 'pbd@example-3.net' | base64
cGJkQGV4YW1wbGUtMy5uZXQ=                               
# echo -n 'password-lol' | base64         
cGFzc3dvcmQtbG9s

Test Cyrus SASL with base64 credentials

root@freebsd13:~ # telnet localhost 25                 
Trying 127.0.0.1...                                    
Connected to localhost.                                
Escape character is '^]'.                              
220 freebsd13.localdomain ESMTP Postfix                
AUTH LOGIN cGJkQGV4YW1wbGUtMS5uZXQ=                < AUTH LOGIN + base64 encoded login
334 UGFzc3dvcmQ6                                       
cGFzc3dvcmQtbG9s                                   < Password base64 encoded
235 2.7.0 Authentication successful                    
quit                                               < Quit
221 2.0.0 Bye                                          
Connection closed by foreign host.                     

Actual input entered has been denoted on the same line with < and a comment.

If you do not recieve a Authentication successful reply, you need to go back through this post and make sure that you can authenticate before moving on.

Postfix TLS Configuration

Postfix requires a TLS certificate for the server, and virtual domains it hosts. It is sufficient to issue one certificate for the hostname and then Subject Alternate Names for the virtual hosts.

I am not going to go into creating certificates in this post, but in this day and age, there is no reason to still be using self signed certificates, on public facing services, when you have Let's Encrypt Certificates available to all and for free.

Create bundle pem ceritficate for Postfix

Once we have our certificates, we need to bundle the fullchain and private key into a single file for Postfix to use:

# cp /etc/pki/tls/private/mail.key /etc/pki/tls/private/mail.bundle.pem
# cat /etc/pki/tls/certs/letsencrypt-fullchain.pem >> /etc/pki/tls/private/mail.bundle.pem

This will be stored in a location where Postfix has access and necessary permissions to use this file. The one thing I will mention is that this bundle contains the private key so protect it as you would your private key.

Setings for the SMTP Server & Client

One thing to keep in mind when configuring TLS for Postfix is that:

  • smtp is the client: ie, when your server connects to another mail server
  • smtpd is the server: ie, when a remote server connects to your mail server

Submission is not yet covered in this section, this will be covered later when we edit the /usr/local/etc/postfix/master.cf file.

There is a lot going on here so make sure that you understand what the directives mean. You can get in a whole lot of trouble with an unprotected mail server.

The Postfix TLS_README document is what you should be consulting to help understand the following settings. Another excellent resource is: bettercrypto.org

Onwards! We can now append TLS settings to /usr/local/etc/postfix/main.cf.

# --------------------------------
# TLS CERTIFICATE CONFIGURATION
# --------------------------------

# postfix tls enable-client
smtp_tls_security_level = may
smtp_tls_loglevel = 1
smtp_tls_session_cache_database = btree:/var/db/postfix/smtp_scache
tls_random_source = dev:/dev/urandom

# disable sslv2,sslv3 in smtp --> smtpd connections
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
smtp_tls_protocols = !SSLv2, !SSLv3

# enforce strong ciphers for smtp --> smtpd connections
smtp_tls_mandatory_ciphers = high

# postfix tls enable-server
smtpd_tls_security_level = may
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes

# disable sslv2,sslv3 in smtpd <-- smtp connections
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
smtpd_tls_protocols = !SSLv2, !SSLv3

# enforce strong ciphers for smtpd <-- smtp connections
smtpd_tls_mandatory_ciphers = high

# tls certs and keys
smtpd_tls_chain_files = /etc/pki/tls/private/mail.bundle.pem

# cipher list and settings
tls_high_cipherlist = EDH+aRSA+AES256:EECDH+aRSA+AES256:!SSLv3
tls_preempt_cipherlist = yes

# Enable EECDH key exchange for Forward Security
smtpd_tls_eecdh_grade = ultra

# TLS Options
tls_ssl_options = NO_COMPRESSION

Postfix Submission Configuration

IETF has changed its tune on whether submission should be made as STARTTLS or Implicit TLS. From January 2018, the IETF reccommends in RFC8314 submission should be made as Implicit TLS. I will implement Implicit TLS as follows:

This time we need to edit the file related to SMTPS Submissions. It is simply uncommenting the following lines that are displayed below in the /usr/local/etc/postfix/master.cf file.

...
...
smtps     inet  n       -       n       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
...
...

Now is a good time to restart Postfix so the changes above will be in full effect.

That's it! All the postfix configuration is done, but we do not have a complete mail sytem as yet. We still need to configure Cyrus IMAPD to recieve the mail that has been sent to us. I will cover this in my next post.

BITS THAT ARE REALLY IMPORTANT THAT I DIDN'T COVER

  • DNS: We are not going to recieve any mail if we do not have an MX record that points to the mail server. I leave this to you to configure on which ever DNS System that you use. If you want a primer on ISC-Bind, it is available in the 9.3-RELEASE Handbook handbook. ISC-Bind has not been part of the base install since the 9.3-RELEASE and this documnetation has been now been removed from the current handbook.

  • File Permissions: This is very important and must be done in order to get a working Mail server. You want to make the least privledge permissions possible whilst allowing the mail server to operate. Again I leave this to the reader to make sure that these settings are suffiecient.

To complete virtual hosting with Postfix, click here to setup Cyrus IMAPD.

Until next time...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment