Tuesday, February 08, 2005

Setting up Postfix (TLS) / Courier-IMAP (SSL) / MySQL / Postfixadmin

This is an install guide for setting up a secure mail server using Postfix, Courier-IMAP, MySQL, and Postfixadmin on Debian Woody.

Before we begin here are a few notes regarding how things are handled:
  • Virtual domains - All domains including the local domain are handled as virtual domains. This allows a central location for all mail.
  • All interactions with the server are authenticated and encrypted using libsasl2 and TLS/SSL (Please see the packages section for what to install)
1. Packages to Install

This install guide assumes the following packages are already installed:
  • mysql-client
  • mysql-server
  • openssl (to create the certificate)
  • apache
To add Postfix add the following line to your /etc/apt/sources.list

deb http://www.backports.org/test/postfix/ ./

Install the following packages:
  • Postfix 2.1.4-4
  • Postfix-mysql 2.1.4-4
  • Postfix-pcre 2.1.4-4
  • Postfix-tls 2.1.4-4
  • libsasl2 (the Cyrus SASL library)
  • libsasl2-modules
  • libsasl2-modules-sql
Note: Make sure you use the source above to install the packages. DON'T use the stable version of backports to install Postfix and libsasl. The stable version of Postfix is linked against libsasl1 which does not allow authentication via the libsasl2 sql module.

Comment out the previous package line and add the following line in your sources.list file:

deb http://www.backports.org/debian stable courier

Install the following packages:
  • courier-authdaemon 0.47-2
  • courier-authmysql 0.47.2
  • courier-base 0.47.2
  • courier-imap 3.0.8-2
  • courier-imap-ssl 3.0.8-2
Finally unpack the latest version of Postfixadmin (2.1.0 as of this writing) into your web directory.

2. Create the Tables in MySQL

Go to the postfixadmin directory that you unpacked and run the DATABASE_MYSQL.TXT in MySQL to setup the complete table structure for Postfix.

It should create the following 7 tables under a database called 'postfix':
  • admin
  • alias
  • domain
  • domain_admins
  • log
  • mailbox
  • vacation
3. Create a Mail Directory

Create a directory to have all your virtual users mail dropped in, this directory needs
to be owned by Postfix.
% mkdir /usr/local/virtual

% chown -R postfix:postfix /usr/local/virtual
% chmod -R 771 /usr/local/virtual
4. Postfix Configuration

Use the following /etc/postfix/main.cf file. The items in <> are values you need to change.

myhostname= <your.hostname>
mydomain= <your.domain>
mydestination =
myorigin = /etc/mailname

virtual_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf
virtual_alias_maps = $virtual_maps
virtual_gid_maps = static:<postfix group id from /etc/passwd>
virtual_mailbox_base = </your/mailbox/path>
virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_domains_maps.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_minimum_uid = <postfix user id from /etc/passwd>
virtual_transport = virtual
virtual_uid_maps = static:<postfix user id from /etc/passwd>

# SMTP Authentication
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_security_options = noanonymous
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reje
smtpd_use_tls = yes
smtpd_tls_cert_file = /etc/postfix/smtpd.cert
smtpd_tls_key_file = /etc/postfix/smtpd.key
append_dot_mydomain = no

Notes: Leave mydestination blank if you want your local domain to be considered virtual. If you list your local domain in mydestination, as is commonly the case, you need to have a system user for every email user. Postfix will look for a system user corresponding to the email user and if none is found it will bounce the mail. It will also not deliver to the mailbox path.

Create the following files in /etc/postfix:


user = postfix
password =
hosts = localhost
dbname = postfix
table = alias
select_field = goto
where_field = address


user = postfix
password =
hosts = localhost
dbname = postfix
table = domain
select_field = description
where_field = domain


user = postfix
password =
hosts = localhost
dbname = postfix
table = mailbox
select_field = maildir
where_field = username

Now go to /etc/postfix/master.cf and change first smtp line to the following:

smtp inet n - n - - smtpd

This prevents postfix from running in a chrooted jail.

5. Postfix, Authenticated SMTP and TLS encryption

By default postfix only allows communication between users defined in mynetworks. This prevents an open relay that spammers can abuse to send out spam. This however, also prevents users of your domain to send out email to domains outside your box. So you have to authenticate your users with a username and password to allow them to be part of your circle of trust. Most email cilents such as Thunderbird have this feature included.

Use the following from Christoph Haas's tutorial located in http://workaround.org/articles/ispmail-sarge/ to setup authentication:

As written earlier Postfix uses the Cyrus SASL library for authenticated SMTP. So you need to tell Postfix how to access the data storage that keeps the usernames and passwords. This is easy. Create a directory /etc/postfix/sasl to put the SASL config file there:
mkdir /etc/postfix/sasl

Now you need to create a file smtpd.conf in that directory like this:

pwcheck_method: auxprop

auxprop_plugin: sql
allowanonymouslogin: no
mech_list: plain login cram-md5 digest-md5
sql_engine: mysql
sql_hostnames: localhost
sql_user: postfix
sql_database: postfix
sql_select: select password from mailbox where username='%u@%r'

(If you have trouble with SASL you may consider inserting a line like "log_level: 7" here. It will write more verbose information to the log files and perhaps help to find the cause.)

An important step is to encrypt the SMTP session. Otherwise the username and password could be transmitted in a very insecure way if the mail client chose to use one of plaintext authentication methods). So I encourage you to encrypt that communication using TLS. TLS is short for Transport Layer Security (RFC2246) and in short terms uses SSL (Secure Socket Layer) which encrypts the mail connection between the road-warrior and the mail server.

First you will need an SSL certificate. If you don't want to pay for one from your favorite trustcenter you can well use a self-signed one. (Personal note: I wonder how paying for something makes it more trusted.) The only drawback: the mail client does not know about your CA (certificate authority) and will spit out a warning to the user. Either tell the users to ignore the warning or let them install the certificate on their computers.

For a certificate that is valid for one year for the hostname smtp.domain.tld you would type this:

openssl req -new -outform PEM -out smtpd.cert -newkey rsa:2048 -nodes -keyout smtpd.key -keyform PEM -days 365 -x509

You will then be asked a few question about the fields of the certificate. It does not matter what you enter. Just fill the fields. One exception though - the "Common Name" must be the hostname of your mail server. Example session:

Country Name (2 letter code) [AU]:DE

State or Province Name (full name) [Some-State]:Hamburg
Locality Name (eg, city) []:Hamburg
Organization Name (eg, company) [Internet Widgits Pty Ltd]:workaround.org email services
Organizational Unit Name (eg, section) []:Master of Disaster
Common Name (eg, YOUR name) []:smtp.domain.tld
Email Address []:postmaster@domain.tld

After a short moment you will get two files: "smtpd.key" (the private key file) and "smtpd.cert" (the certificate). Move these two files into /etc/postfix.

Make sure at least the key file is not readable for the whole wide world:
chmod o= /etc/postfix/smtpd.key

6. Configuring Courier-IMAP-SSL

Edit /etc/courier/authdaemonrc and change authmodulelist to "authmysql" like this:

Add or Change /etc/courier/authmysqlrc to contain the following:

MYSQL_SERVER            localhost


#MYSQL_CRYPT_PWFIELD password #Comment this out
MYSQL_HOME_FIELD '/location/to/mail/dir'
Notes: Make sure you have no spaces only tabs. Enclose user id and gid in single quotes.

7. Final Comments

By default libsasl2 only supports clear text passwords so make sure the user passwords in the mysql database are readable. Since our connections are encrypted using TLS/SSL this is not much of an issue. Make sure Postfixadmin is set for clear text passwords. Your config.inc.php in your Postfixadmin directory should have the following:

$CONF['encrypt'] = 'cleartext';

8. Helpful Links and Howto's

Much of the information for this guide was gathered from the following links:



Post a Comment

Links to this post:

Create a Link

<< Home