Postfix Virtual Hosts- FreeBSD

Share on:

Over the last few weeks I have been consolidating some mail servers that I look after onto one systetm. I had been using Sendmail and Postfix but have decided on setting them all up under Postfix using Virtual Domain Hosting. Virtual Domain Hosting works in effect like Virtual Hosts in NGINX but then again not the same. In many ways it is less complicated and if you choose, you do not even have to issue TLS certificates for each domain, as TLS can be authenicated from the main mailhost.

So, over the next few weeks, I am going to post about the notes on configuration that I have taken. These are not thorough guides but I hope, if you have similar needs, it can be a quick jump start to get you up and running. FreeBSD and Postfix has excellent documentation and this should be your main reference to accompany this post.

So without further ado, let's get started...

Install Postfix

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

1# 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:

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

Next, we have to setup the mailer.conf:

1# mkdir -p /usr/local/etc/mail
2# 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.

1# cat /etc/periodic.conf

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.


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.

The following can be appended to /usr/local/etc/postfix/

1# --------------------------------
3# --------------------------------
5soft_bounce = yes                 

In fact, all the settings made to /usr/local/etc/postfix/ 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 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 configured 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/

1# --------------------------------
3# --------------------------------
5smtpd_sasl_auth_enable = yes
6smtpd_sasl_type = cyrus
7smtpd_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:

1pwcheck_method: auxprop
2auxprop_plugin: sasldb

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

Let's Add Some Users to the Cyrus SASL Database

1# saslpasswd2
2# saslpasswd2
3# saslpasswd2

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/

 1# --------------------------------                                                     
 2# VIRTUAL DOMAINS CONFIGURATION                                                        
 3# --------------------------------                                                     
 5# This is set in anticipation of having a working cyrus imap server running in cahoots 
 6# with Postfix. For now, mail delivery will not work but that will be resolved in my i
 7# next post on setting up virtual hosts under Cyrus Imapd.
 9mailbox_transport = lmtp:unix:/var/imap/socket/lmtp                                    
11# A list of domains that Postfix will accept mail for.          
13virtual_mailbox_domains =
17# This is the spool directory for our hosts that we added immeadiately above.
19virtual_mailbox_base = /var/mail/vhosts                                                
21# this is a file that contains a list of mailboxes that Postfix will deliver to. 
22# When we create this file shortly, this directive will become more apparent.
24virtual_mailbox_maps = hash:/usr/local/etc/postfix/vmailbox                            
26# Optional lookup tables that alias specific mail addresses or domains to other 
27# local or remote address. For now, this file needs to be created but will be left
28# empty as I will no be configuring such intricate features in this post.
30virtual_alias_maps = hash:/usr/local/etc/postfix/virtual                               
32# stuff that needs to be here so Postfix works =)
33# Consult for more detail
35virtual_minimum_uid = 100                                                               
36virtual_uid_maps = static:125                                                           
37virtual_gid_maps = static:125                                                           
39# The maximal size in bytes of an individual virtual(8) mailbox or maildir file, 
40# or zero (no limit).
42virtual_mailbox_limit = 1000000000
44# The default mail delivery transport and next-hop destination for final delivery 
45# to domains listed with $virtual_mailbox_domains. This points to the Cyrus transport
46# that was set earlier.

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 Virtual Host configuration now entered, we must create databases that Postfix can read from the virtual_mailbox_maps & virtual_alias_maps directives that were created.

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:            

This is a list of each user that we created with the saslpasswd2 command.

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

postmap will create the databases as previously mentioned:

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

So far, so good! Everything is setup for Postfix and Virtual hosts. We are just missing TLSconfiguration but we will return to this shortly. First we will test the Cyrus SASL Authentication.

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

1# 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:

1# pkg install base64

Generate Base 64 Credentials

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

1# echo -n '' |base64 
3# echo -n '' | base64
5# echo -n '' | base64
7# echo -n 'password-lol' | base64         

Test Cyrus SASL with base64 credentials

 1root@freebsd13:~ # telnet localhost 25                 
 3Connected to localhost.                                
 4Escape character is '^]'.                              
 5220 freebsd13.localdomain ESMTP Postfix                
 6AUTH LOGIN cGJkQGV4YW1wbGUtMS5uZXQ=                < AUTH LOGIN + base64 encoded login
 7334 UGFzc3dvcmQ6                                       
 8cGFzc3dvcmQtbG9s                                   < Password base64 encoded
 9235 2.7.0 Authentication successful                    
10quit                                               < Quit
11221 2.0.0 Bye                                          
12Connection 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:

1# cp /etc/pki/tls/private/mail.key /etc/pki/tls/private/mail.bundle.pem
2# 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.

Settings 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/ 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: Also a neat tool is the Mozilla SSL Configuration Generator.

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

 1# --------------------------------
 3# --------------------------------
 5# postfix tls enable-client
 6smtp_tls_security_level = must
 7smtp_tls_loglevel = 1
 8smtp_tls_session_cache_database = btree:/var/db/postfix/smtp_scache
 9tls_random_source = dev:/dev/urandom
11# disable sslv2 ,sslv3, tlsv1, tlsv1.1  in smtp --> smtpd connections
12smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
13smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
15# enforce strong ciphers for smtp --> smtpd connections
16smtp_tls_mandatory_ciphers = high
18# postfix tls enable-server
19smtpd_tls_security_level = must
20smtpd_tls_loglevel = 1
21smtpd_tls_received_header = yes
23# disable sslv2, sslv3, tlsv1, tlsv1.1 in smtpd <-- smtp connections
24smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
25smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 
27# enforce strong ciphers for smtpd <-- smtp connections
28smtpd_tls_mandatory_ciphers = high
30# tls certs and keys
31smtpd_tls_chain_files = /etc/pki/tls/private/mail.bundle.pem
33# cipher list and settings
34tls_high_cipherlist = EDH+aRSA+AES256:EECDH+aRSA+AES256:!SSLv3
35tls_preempt_cipherlist = yes
37# Enable EECDH key exchange for Forward Security
38smtpd_tls_eecdh_grade = ultra
40# TLS Options
41tls_ssl_options = NO_COMPRESSION

NOTE: I have used smtp_tls_security_level = must & smtpd_tls_security_level = must which is technically against the standard recommendations, however, all reputable e-mail sites will support encryption, and anyone sending in plain is probably a spammer.

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/ file.

3smtps     inet  n       -       n       -       -       smtpd
4  -o syslog_name=postfix/smtps
5  -o smtpd_tls_wrappermode=yes
6  -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.


  • 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.

  • SPAM Prevention: Very soon I will make a couple of posts outlining what can be done to prevent spam. This will cover directives that can be set in the, Postfix tools such as postscreen and external tools such as using Spamassassin with a Milter.

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

Until next time...