Using Postfix as MTA for Virtual Hosting Domains

Posted on August 8th, 2007 by ice.
Categories: Gentoo.

In this article I’ll report my experience in migrating from qmail to Postfix, so let’s start with the reasons that let me do this:

  1. Postfix is a Free Software (IBM Public License 1.0 - Not GPL Compatible)
  2. TLS (Transport Layer Security)
  3. Different Databases for Maps (Berkeley DB, CDB, DBM, LDAP, MySQL and PostgreSQL)
  4. mbox-style and Maildir-style mailboxes
  5. Great support for virtual domains.
  6. Address rewriting (envelope and header), VERP, SMTP-AUTH via SASL, and much more.
  7. Can be compilead in many Unix-Like systems (AIX, BSD, HP-UX, IRIX, Linux, Mac OS X, Solaris, Tru64 UNIX)
  8. Very easy and centralized configuration
  9. Now I have a install script to do this in gentoo ;)

Many people here should say that “qmail already have that feature”, but the focus of this article is show WHY I moved to Postfix, not compare this two MTA, certanly QMail has good points that I could forget, so let’s continue.

Now I’ll show how to install a system that handles many virtual domains, virtual mail users that don’t require a shell account, can authenticate via web, imap, smtp and pop3 clients with all database centralized in a single database, using ssl as transport layer, and at last, will install a webmail frontend and a manager (postfixadmin).

Clink in the link below to see the entire tutorial (portuguese version)

Before start the installation, should be better to check your USE flag, and if you have another MTA installed in your system. If you wish to have 2 or more MTAs installed you need to use the mailwrapper USE flag that will do this for you, otherwise you need to uninstall any MTA already installed like sendmail ou ssmtp.

The USE flag that I recommend is
USE=”apache2 authdaemond imap libwww maildir mailwrapper mysql sasl ssl vhosts”

The Base of Postfix
First of all, let’s install Postfix
emerge postfix
(as I said this article [and maybe this blog] is based on Gentoo, so you can check what package your distribution uses so you can install and do the configuration)

After Postfix is installed now needs to configure (the better part in configuration, just one file), you could write here the final configuration, but I think it’s better to do it step by step to understand what is happening, solve any problem or if you wish to do any change later.

vi /etc/postfix/main.cf
myhostname = $host.domain.name
mydomain = $domain.name
inet_interfaces = all
mydestination = $myhostname, localhost
mynetworks = my.ip.net.work/24, 127.0.0.0/8
home_mailbox = .maildir/
local_destination_concurrency_limit = 2
default_destination_concurrency_limit = 10
smtpd_banner = $host.domain.name ESMTP $mail_name

Next step is change our smtp to be more verbose, don’t forget that his can increase your mail.* log files very fast, so after you MTA is running fine, I suggest you disable the smtp verbosity.

vi /etc/postfix/master.cf
(Just add the “-v” after the smtpd in the following line)
smtp inet n - n - - smtpd -v

Next we need to configure the aliases for your system, if any person is responsable for each server you can configure one alias for each, or just change the root alias like this how to:

vi /etc/mail/aliases
root: your@email.address

Then the final steps to put postfix base running is generate the aliases and start the service:
/usr/bin/newaliases
/etc/init.d/postfix start
(this is using the init.d init system, may change to your distro)
ps: It’s good to test if postfix is delivering mails to your local mailboxes using some console mail client like mutt or other.

Courier-imap
Install both services
emerge courier-imap courier-authlib

Change the C, ST, L, CN, and email parameters to match your server and generate the certs correctly.
vi /etc/courier-imap/pop3d.cnf
vi /etc/courier-imap/nano -w imapd.cnf

mkpop3dcert
mkimapdcert

(if you experience any issue about the secure protocol when connecting a mail client in this server, try make this change)
vi /etc/courier-imap/imapd-ssl
TLS_PROTOCOL=TLS1

Starting the courier services
/etc/init.d/courier-imapd start
/etc/init.d/courier-imapd-ssl start
/etc/init.d/courier-pop3d start
/etc/init.d/courier-pop3d-ssl start

Verify that all connections you’ve started work for receiving and sending mail with your prefered mail client, you won’t be able to log on to any of the services because authentication hasn’t been configured yet, but it is wise to check if the connections themselves work or not.

Cyrus-sasl
Install cyrus-sasl. Sasl is going to play the role of actually passing your auth variables to courier-auth, which will in turn pass that information to mysql for authentication of smtp users. For this howto, we’ll not even try to verify that sasl is working until mysql is set up and contains a test user. Which is fine since we’ll be authenticating against mysql in the end anyway.

emerge cyrus-sasl

Starting sasl

vi /etc/sasl2/smtpd.conf
mech_list: PLAIN LOGIN
pwcheck_method: saslauthd

vi /etc/conf.d/saslauthd
SASLAUTHD_OPTS=”${SASLAUTH_MECH} -a rimap -r”
SASLAUTHD_OPTS=”${SASLAUTHD_OPTS} -O localhost”

Start the cyrus-sasl service
/etc/init.d/saslauthd start

SSL Certs for Postfix and Apache
Next we’re going to generate a set of ssl certificates for postfix and apache.

vi /etc/ssl/openssl.cnf
countryName_default
stateOrProvinceName_default
localityName_default
0.organizationName_default
commonName_default
emailAddress_default.

(If the variables are not already present, just add them in a sensible place.)

cd /etc/ssl/misc
./CA.pl -newreq-nodes
./CA.pl -newca
./CA.pl -sign
cp newcert.pem /etc/postfix
cp newkey.pem /etc/postfix
cp demoCA/cacert.pem /etc/postfix

(Now we do the same thing for apache.)

openssl req -new > new.cert.csr
openssl rsa -in privkey.pem -out new.cert.key
openssl x509 -in new.cert.csr -out new.cert.cert -req -signkey new.cert.key -days 365

(Just leave the resulting certificates here for now. We’ll install them after Apache is installed.)

Adding SSL and SASL support to Postfix
Now edit the postfix config’s to make it aware of your new sasl and ssl capabilities. Add the following parameters to the end of the file where they will be easy to find.

vi /etc/postfix/main.cf
smtpd_sasl_auth_enable = yes
smtpd_sasl2_auth_enable = yes
smtpd_sasl_security_options = noanonymous
broken_sasl_auth_clients = yes
smtpd_sasl_local_domain =

smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination

smtp_use_tls = yes
smtp_tls_note_starttls_offer = yes
smtpd_use_tls = yes
smtpd_tls_auth_only = yes
smtpd_tls_key_file = /etc/postfix/newkey.pem
smtpd_tls_cert_file = /etc/postfix/newcert.pem
smtpd_tls_CAfile = /etc/postfix/cacert.pem
smtpd_tls_loglevel = 3
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom

smtpd_recipient_restrictions =
#reject_non_fqdn_recipient
#reject_non_fqdn_sender
reject_unknown_recipient_domain
permit_mynetworks
permit_sasl_authenticated
#check_policy_service inet:127.0.0.1:2501, needed for sqlgrey and optional
reject_unauth_destination
permit

# additional spam fighting checks, optional
#smtpd_helo_restrictions = reject_unknown_helo_hostname
#smtpd_sender_restrictions = reject_unknown_sender_domain
#smtpd_data_restrictions = reject_unauth_pipelining

(smtpd_tls_auth_only is commented out to ease testing the system. You can turn this on later if you desire.)

postfix reload

Next, let’s verify that both TLS and SASL support are enable at Postfix using the telnet (provided by package net-misc/netkit-telnetd), so execute the command and check if they are:

telnet localhost 25
Trying 127.0.0.1…
Connected to localhost.
Escape character is ‘^]’.
220 host.domain.name ESMTP Postfix
EHLO host.domain.name
250-host.domain.name
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN^]
telnet> quit

Verify that the above AUTH and STARTTLS lines now appear in your postfix install.

The vmail user
Before we set up our virtual mailhosting environment, we create a functional user under which the virtual mailboxes will be hosted

Adding the vmail user
adduser -d /home/vmail -s /bin/false -m vmail

MySQL Database
(Here we suppose the you have mysql configured and running, because it’s not the goal of this article cover this)
Please get the file postfix_database.sql before continue the tutorial

mysql -uroot_user -proot_password < postfix_database.sql
(please don’t forget to change the default pass of the users used to manage the database (user: postfixadmin) at line 3 and the one used by postfix to access the data on the database (user: postfix) at line 6.

Your new database has the following tables are included:
(you don’t need to change any data on the database yet, postfixadmin will do it for you).

* admin - information about admins of postfixadmin.
* alias - stores the aliases of postfix and the destination of each.
* domain - information about the virtual domains that are added to postfix.
* domain_admins - information about the admins of each domain.
* log - log of transactions done by postfixadmin.
* mailbox - stores the information of every mailbox of postfix
* vacation - used to manage the auto-reply messages when user go on vacation

Apache Certs
(Likely in mysql, here we suppose the you have apache and php configured and running, because it’s not the goal of this article cover this)

Now we’re going to install the Apache certificates we made previously. The Apache-SSL directives that you need to use the resulting cert are:

* SSLCertificateFile /etc/ssl/misc/newcert.pem
* SSLCertificateKeyFile /etc/ssl/misc/newkey.pem

Install Apache SSL certificates
cp /etc/ssl/misc/newcert.pem /etc/apache2/ssl/
cp /etc/ssl/misc/newkey.pem /etc/apache2/ssl/
cd /etc/apache2/vhosts.d

(Check if you have an ssl-vhost template already. Copy that one instead of the default_vhost if that is the case)
cp 00_default_vhost.conf ssl-vhost.conf

vi ssl-vhost.conf
NameVirtualHost host.domain.name:443

<VirtualHost host.domain.name:443>
ServerName host.domain.name
ServerAdmin your@email.address

DocumentRoot “/var/www/localhost/htdocs/phpmyadmin”;
<Directory “/var/www/localhost/htdocs/phpmyadmin”>

</Directory>

SSLCertificateFile /etc/apache2/ssl/newcert.pem
SSLCertificateKeyFile /etc/apache2/ssl/newkey.pem
SSLEngine on

</VirtualHost>

vi /etc/conf.d/apache2
(Add -D SSL to the APACHE2_OPTS)

/etc/init.d/apache2 restart

Postfixadmin
Postfixadmin is keyword masked, so you’ll need to unmask it doing:
echo “www-apps/postfixadmin ~x86″ >> /etc/portage/portage.keywords (maybe ~amd64 depending on your architeture)

Since it’s done all you need to do is emerge
emerge postfixadmin

then install in a vhost (localhost is used as example)
webapp-config -I -h localhost -d /postfixadmin postfixadmin 2.1.0

then edit the config file:
vi /var/www/localhost/htdocs/postfixadmin/config.inc.php
$CONF['database_type'] = ‘mysql’;
$CONF['database_host'] = ‘localhost’;
$CONF['database_user'] = ‘postfixadmin’;
$CONF['database_password'] = ‘$DBPOST_PASS’;
$CONF['database_name'] = ‘postfix’;
$CONF['database_prefix'] = ”;

$CONF['domain_path'] = ‘YES’;
$CONF['domain_in_mailbox'] = ‘NO’;

Squirrelmail
It’s the same procedure as postfixadmin, so let’s be quickly (don’t this how-to finish?! ;))

emerge squirrelmail
webapp-config -I -h localhost -d /webmail squirrelmail 1.5.1-r6

cd /var/www/localhost/htdocs/mail/config
perl ./conf.pl

(Change your Organization, Server, and Folder settings for squirrelmail. Now you should be able to login to squirrelmail, again - with your full email address, and use your new webmail setup.)

postfix reload
rc-update add courier-authlib default
rc-update add courier-imapd default
rc-update add courier-pop3d default
rc-update add postfix default
rc-update add saslauthd default

Configuring MySQL Authentication for vhosts
Our postfix is running, our authentication methods are done, our database is already created (ok, no data I know, YET ;) ), so here you’ll configure the transport methods that tells to postfix get the information on our database, and courier-sasl too.

vi /etc/courier/authlib/authdaemonrc
authmodulelist=”authmysql authpam”

vi /etc/courier/authlib/authmysqlrc
#DEFAULT_DOMAIN domain.tld
MYSQL_CRYPT_PWFIELD password
MYSQL_DATABASE postfix
MYSQL_GID_FIELD ‘$VMAIL_GID’ # group id of vmail group
MYSQL_HOME_FIELD ‘/home/vmail’
MYSQL_LOGIN_FIELD username
MYSQL_MAILDIR_FIELD maildir
MYSQL_NAME_FIELD name
MYSQL_OPT 0
MYSQL_PASSWORD $DBPOST_PASS # the password you configured in postfix_database.sql for user postfix
# Uncomment below if you want quota support.
MYSQL_QUOTA_FIELD quota
MYSQL_SERVER localhost
MYSQL_UID_FIELD ‘$VMAIL_UID’ # user id of user vmail
MYSQL_USERNAME postfix
MYSQL_USER_TABLE mailbox
#MYSQL_WHERE_CLAUSE server=’example.domain.com’

/etc/init.d/courier-authlib restart
/etc/init.d/saslauthd restart

Let’s create the transport files (it’s boring, I know)
Change $DBPOST_PASS for your postfix mysql user password

vi /etc/postfix/mysql_relay_domains_maps.cf
# you only need this if you plan to act as a backup mx for various domains.
user = postfix
password = $DBPOST_PASS
hosts = localhost
dbname = postfix
query = SELECT domain FROM domain WHERE domain=’%s’ AND backupmx = ‘1′ AND active = ‘1′

vi /etc/postfix/mysql_virtual_alias_maps.cf
user = postfix
password = $DBPOST_PASS
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias WHERE address=’%s’ AND active = ‘1′

vi /etc/postfix/mysql_virtual_domains_maps.cf
user = postfix
password = $DBPOST_PASS
hosts = localhost
dbname = postfix
query = SELECT description FROM domain WHERE domain=’%s’ AND active = ‘1′

vi /etc/postfix/mysql_virtual_mailbox_limit_maps.cf
# you only need this if you plan to enforce quotas on mail users.
user = postfix
password = $DBPOST_PASS
hosts = localhost
dbname = postfix
query = SELECT quota FROM mailbox WHERE username=’%s’ AND active = ‘1′

vi /etc/postfix/mysql_virtual_mailbox_maps.cf
user = postfix
password = $DBPOST_PASS
hosts = localhost
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username=’%s’ AND active = ‘1′

vi /etc/postfix/mime_header_checks.regexp
/^\s*Content-(Disposition|Type).*name\s*=\s*\”?(.+\.(ad[ep]|asd|ba[st]|c[ho]m|cmd|cpl|crt|dbx|dll|exe|hlp|hta|in[fs]|isp|js|jse|lnk|md[etw]|ms[cipt]|nws|ocx|ops|pcd|pi|pif|prf|reg|scf|scr|sct|sh[bms]|uue|vb|vb[esx]|vxd|wab|ws[cfh]))\”?\s*$/ REJECT Files attached to emails that contain or end in \”\$3\” are prohibited on this server as they may contain viruses. The file named \”\$2\” was rejected.

It’s a good one to change the permission of transport files for security reasons doing:
chmod 640 /etc/postfix/mysql_*.cf
chgrp postfix /etc/postfix/mysql_*.cf

vi /etc/postfix/main.cf (last time I swear ;))
#
# Transport Methods
#

virtual_alias_maps = proxy:mysql:/etc/postfix/mysql_virtual_alias_maps.cf
virtual_gid_maps = static:$VMAIL_GID
virtual_mailbox_base = /home/vmail/
virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql_virtual_domains_maps.cf
virtual_mailbox_limit = 112400000
virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_minimum_uid = $VMAIL_UID
virtual_transport = virtual
virtual_uid_maps = static:$VMAIL_UID

Reload postfix to read the tables and use the transport methods
postfix reload

Ohhhhh we finished.. I did this how to on my server and everything goes fine (after some research on how to integrate everything well) and I hope things go fine for you too, and after read this how-to you can understand the process of installation of postfix and do any changes you wish, not just “copy-paste” commands.

Now I finished this article the next step is to write an article on how to fight virus and spam on the mail server, and write the article about the script that I wrote (and is a beta yet) that try to automate this how to on a gentoo server (You wouldn’t like to do this about 10 or 100 times). The script is very useful, but I need to improve the checks about any error during the process and I really wanna to make something like a resume in the script in case of some failure, so that’s all, hope you enjoy the first really big post here.

Based on the article: Virtual Mailhosting System with Postfix Guide

0 comments.

Leave a comment

Comments can contain some xhtml. Names and emails are required (emails aren't displayed), url's are optional.