You are here

Secure email servers from scratch with FreeBSD 6 (Part 2)

In the last article we parted ways after configuring a base FreeBSD system, enabling it with upgrades via cvsup and portsupgrade, and securing it with a simple ipfw2 firewall. The previous article created a solid foundation which this article will build on, covering the configuration of Postfix, amavisd-new, ClamAV, SpamAssassin, MySQL and finally SquirrelMail for web mail. The final setup will have all the bells and whistles of a high end-mail setup: web-mail, anti-virus filtering, spam filtering, and hosting unlimited domains with virtual domains and users stored in MySQL.

Postfix is released under the IBM Public License, and not the GNU Public License

Postfix

The first and most important component is Postfix, a well known mail transfer agent developed by Wietse Venema at IBM and initially known as the “IBM Secure Mailer”. Venema, is a respected software engineer who also developed the popular security tool “S.A.T.A.N” (Security Administrator Tool for Analyzing Networks). Postfix is released under the IBM Public License, and not the GNU Public License; the “IPL” has been approved as an open source license by both the Free Software Foundation (“FSF”) and the Open Source Initiative(“OSI”); however, it has been declared incompatible with the GPL. Initially Postfix was created in reaction to a long list of security vulnerabilities in Sendmail, the then dominant “MTA”. The direct result of the “security first” mind, Postfix has a well earned reputation for being easy to setup, fast and secure.

Postfix has two central configuration files:

main.cf: which configures the “properties” of the mail server such as where user and domain information is stored, or which domains to accept mail for.

master.cf: which configures the “behavior” of the Postfix daemon, such as configuring interfaces to non Postfix programs, and other configuration settings for the Postfix daemon itself.

FreeBSD places the configuration files of packages installed from ports under /usr/local/etc; so normally you’ll find the Postfix configuration files under /usr/local/etc/postfix. First of all, you should install Postfix from the ports tree, in the same way that MySQL was installed in the first article.

Installing Postfix using ports

cd /usr/ports/mail/postfix
make install && make clean

You will then be presented with a dialog box: select TLS and MYSQL.

Postfix configuration dialog

Note that when MySQL functionality is selected, the default action is to install the MySQL 4.1 client library. If you plan on running a newer version of MySQL, such as 5.0, simply cancel the Postfix installation, install the MySQL client library of your choice, and then re-run the installation.

Example:

cd /usr/ports/databases/mysql50-client
make install && make clean

During the installation of the client libraries you may be prompted for options to the gettext package. It’s not necessary to select any of the options, but feel free to do so if you wish.

After Postfix is built, you will be prompted asking if you want to activate it in the mailer.conf file: say “yes”:

[Prompt] Would you like to activate Postfix in /etc/mail/mailer.conf [n]? y

Configuring Postfix—main.cf

Now that Postfix is installed, it’s time to dive into the most important of the two configuration files, main.cf. In this one file there are essentially two sets of directives: one for the domains the server will be hosting, which being with the virtual prefix; and one for the mail server itself, with lines that begin with my as in myhostname. I’ll be giving in line commentary, so read the configuration file closely.

# Configure your hostname, and domain names here!
myhostname = myhost.mydomain.mytld
mydomain = mydomain.mytld
myorigin = $mydomain
# Which network interfaces to listen on
inet_interfaces = all
# This allows delivery for mail to root@[host] for system messages
mydestination = myhost, myhost.mydomain.mytld
unknown_local_recipient_reject_code = 550
# For other systems on network?
mynetworks_style = host
# This is what people will see if they telnet to port 25 on your mail server
# it might be worth placing a warning message, for legal reasons. Systems with
# banners outlining acceptable use, and the legal actions that will be taken
# have a slightly stronger case in court.
smtpd_banner = mysqlever.mydomain.mytld ESMTP (Insert witty message here)

The framework for the rest of the article is in place. Even though the system is un-usable in the sense the no users can login to send or receive mail, Postfix is itself configured enough to send and receive mail. The next step I’m going go take will be putting the finishing touches on the master.cf file. The default file may look something like that listed below, but you’ll only need to edit a tiny bit of it, and as such I’ll only show the relevent lines.

Postfix Virtual Maps

Postfix has the notion of “maps”, which is the mechanism used to map data from one form to another. In our case, it’s mapping the data in a MySQL database, using a simple select statement, to certain configuration parameters. The map files contain all the information needed to connect to and query the MySQL database, which contains the user information. Each file contains only one query to the database. Create the files, copy and paste the content, and double check the user name and password used to access the database, which I’ll cover setting up in the MySQL section.

Please note that this article is geared towards Postfix 2.3 or newer; however, if you plan on using the configuration presented with an earlier version, the format for mysql_maps may be different, and broken up into several lines, so make sure to double check which version you are working with.

MySQL

Postfix is extremely flexible, and affords a wide array of options in storing user and domain information. The right choice depends mostly on what’s appropriate for the environment you plan on working in. If you only plan on hosting a single domain, with a handful of users it may make sense to avoid the overhead of maintaining a database; however, if you plan on maintaining multiple domains with hundreds or thousands of users, or simply want the flexibility of manipulating the data in an automated way, LDAP or MySQL is the way to go.

An in depth discussion of either MySQL or the way Postfix interacts with it is beyond the scope of this article. The only key concept is that of maps in Postfix, which is discussed towards the end of the Postfix section.

Installing MySQL

cd /usr/ports/databases/mysql50-server
make install && make clean

You should now have the MySQL database installed. You may need to run the startup script, and make sure it has been enabled in the /etc/rc.conf file.

Creating the mail databases

The SQL listing below creates the three tables used by Postfix. Simply follow the steps, create the mail database, and then copy and paste the table creation statements. After that, use the GRANT command to grant access to the mail_admin user configured in the Postfix maps described earlier.

Adding a new virtual hosted domain:

Amavisd-new acts as a proxy, accepting the mail from Postfix, and filtering it through ClamAV and SpamAssassin

Amavisd-new & SpamAssassin

Amavisd-new is a high performance interface between Postfix and other mail components. Postfix, as well as most other MTAs can only reliably connect to one other content checker such as an anti-virus or spam package, so in order to use both spam and virus filtering we configure Postix to filter content through amavisd-new, which then filters the email through SpamAssassin and ClamAV.

SpamAssassin, is an Apache subproject and is probably the most famous and powerful free software spam filtering program. It uses a wide range of tests to assign an overall score to a piece of mail, if the score is above the acceptable threshold it is considered spam. Amavisd-new comes with SpamAssassin embedded, rather than the stand alone daemon. This simplifies the configuration greatly, since SpamAssassin can be configured in the same place that amavisd-new can. The SpamAssassin directives always begin with sa as in $sa_kill_level_deflt, which sets the threshold above which SpamAssassin will simply drop an email instead of tagging it as spam.

Amavisd-new is under /usr/ports/security/amavisd-new. It should be built with the with the spamassassin option, which will automatically build and install SpamAssassin during the amavisd installation.

Installing amavisd-new

cd /usr/ports/security/amavisd-new
make install && make clean

You’ll be presented with a config dialog. The required options are MySQL, and SpamAssassin. Again, after selecting these, feel free to install other options if you feel adventurous.

Amavisd-new configuration dialog

Tip: If you’ve already installed amavisd-new, and wish to re-configure it, start the process with make config, which will re-present you with the configuration dialog.

Configuring Postfix to work with amavisd-new

It’s simple, yet important to configure Postfix to filter all mail through amavisd-new, which then acts as a broker and filters the mail through both ClamAV and SpamAssassin. To do so add the following lines to the main.cf file:

# filter with amavisd-new which proxies to ClamAV and SpamAssassin
content_filter=smtp-amavis:[127.0.0.1]:10024

Configuring the amavisd-new daemon

Amavisd-new is now installed, and Postfix is filtering to it. The only thing left to do is configure the amavisd-new daemon itself. The ports package doesn’t create an amavisd-new directory under /usr/local/etc, unlike most of the other packages. Instead, the amavisd.conf is directly under /usr/local/etc. Similar to the Postfix configuration block above, I’ll be mixing explanation tid-bits with the configuration, so make sure to read it thoroughly.

# Important lines to check, as I said above, I'm mixing
# in my own comments with the configuration file.
# Make sure these two lines are commented out, as they
# will disable spam and virus filtering
# uncomment to DISABLE anti-virus code
# @bypass_virus_checks_maps = (1);
# uncomment to DISABLE anti-spam code
# @bypass_spam_checks_maps = (1);
# (no default; customary: vscan or amavis), -u
$daemon_user = 'vscan';
# (no default; customary: vscan or amavis), -g
$daemon_group = 'vscan';
# Configure this to your domain
# a convenient default for other settings
$mydomain = 'mydomain.com';
# Configure the FQDN of your mail host
$myhostname = 'myhost.mydomain.com';
# Change the local_domains_maps to include all
# the mail domains you are hosting
@local_domains_maps = ( [ ".$mydomain", '.example2.com'] );
# IF you want email marked as spam to have a different
# subject header, change the following line
$sa_spam_subject_tag = '***SPAM*** ';
# Default is 6.31, if message is above this
# it will be dropped, and nothing sent to the user
$sa_kill_level_deflt = '20';
# Change the default tag level from 2.0 to undef
# This will insure all mail addressed to domains
# in @local_domains will get a spam score in the header, spam or not.
$sa_tag_level_deflt = undef;
# Make sure this matches what's in main.cf
# listen on this local TCP port(s) (see $protocol)
$inet_socket_port = 10024;
# Configure these two lines to receive email alerts
# when mail is blocked
$spam_admin = 'webmaster@mydomain.com';
$virus_admin = 'webmaster@mydomain.com';
### CLAM_AV INTEGRATION ###
['ClamAV-clamd',
\&ask_daemon, ["CONTSCAN {}\n", "/usr/share/clamav/clamd.sock"],
qr/\bOK$/, qr/\bFOUND$/,
qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],

ClamAV comes with `freshclam`, an automated process for staying up to date with the latest virus signatures

ClamAV

ClamAV is a widely used free software anti-virus package. It is released under the GPL license, and is available for most unix-like platforms. It has many features, but its main goal is an integrated attachment scanner for mail servers. ClamAV is used in a production setting across many private companies, large universities, and government agencies such as: Barracuda Networks, Michigan State University, Brandeis University, Webmail.us, Slashmail, and the US state of Vermont.

ClamAV’s configuration file, like that of amavisd-new is directly under /usr/local/etc, and is called clamd.conf. The default configuration is more or less what we need, but it’s good to take a peek through the file anyway.

Make sure that mail scanning is enabled:

# Example
LogFile /var/log/clamd.log
LogFileMaxSize 5M
DatabaseDirectory /usr/share/clamav
# UNIX Socket which other programs will use
# ie: amavisd-new, will use to connect to ClamAV
LocalSocket /usr/share/clamav/clamd.sock
# Obviously, the user who will own the ClamAV process.
User clamav

Courier-IMAP

Courier-IMAP is the IMAP client which allows Squirelmail, and other mail clients such as Mozilla Thunderbird to connect and download messages. There are actually two components installed:

courier-authlib, which manages user authentication; and

courier-imap, which is the actual IMAP server.

However, this dependency is automatically resolved by FreeBSD’s ports, all you need to do is select the AUTH_MYSQL option.

Installing and configuring

/usr/ports/mail/courier-imap
make install && make clean

Make sure to enable the MySQL option, so the authmysql module is built with courier-authlib.

Courier configuration dialog

After the installation is complete, there will be two directories under /usr/local/etc: authlib, and courier-imap.

Webmail with SquirrelMail

SquirrelMail is a flexible, easy-to-configure webmail package written in PHP. Configuring Apache is beyond the scope of this article, and there are many other good tutorials out there, so I’m going to focus on installing the necessary packages, and then on configuring SquirrelMail.

Configuring SquirrelMail

Install Apache:

/usr/ports/www/apache22
make install && make clean

Install PHP:

/usr/ports/lang/php5
make install && make clean

Install SquirrelMail:

/usr/ports/mail/squirrelmail
make install && make clean

Installing SquirrelMail plugins:

/usr/ports/mail/squirrelmail-compatibility-plugin
make install && make clean
/usr/ports/mail/squirrelmail-vlogin-plugin
make install && make clean

Configuring SquirrelMail:

cd /usr/local/www/squirrelmail
./configure

Select 2 to configure the server, make sure to configure the domain name, and the imap server settings.

Conclusion

I’ve shown all the pieces required to put together a secure, full-featured, FreeBSD mail server. It was a lot to cover, and I thank you for staying with me. The first article took you through the steps of installing FreeBSD, managing updates, and installing the core server components for a fully functional and secure email server; this article covered configuring the core components for a robust, spam and virus filtering mail system. The journey is by no means over. I strongly encourage you to take the time to explore the packages used, and learn them thouroughly: they are powerful tools which will serve you well in the future.

Comments

i thing there is an error in the manual.
actualy i was expecting part two with great impatience
now i am testing it and so far i am at the mysql query part
here i am:

Grant privileges
###
Run the following command:

GRANT SELECT on mail.* to mail_admin identified by password ('mail_admin_password');
###
(it is from inside of mysql)
but i get syntax error on this step
"ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '('mail_admin_password')' at line 1"

i am not a mysql specialist, but i tried some variations of that command, but still i got errors

i thing that there is something missing, i dont see where in mysql the user mail_admin is created, and may be this is the reason this command to fail.
forgive me if i am wrong, but please fix it :))

Also, given the FreeBSD project themselves now recommending using portsnap rather than cvsup to keep your ports tree up-to-date (and speaking personally, it's a whole lot easier to work than cvsup) might it be worth mentioning it?

The problem as I see it with portsnap is that you can't upgrade your src tree -- and seamless upgrading from release to release via make buildworld && make buildkernel is one of FreeBSD's strongest points -- and with one extra line to the cvsup config file it (cvsup) can pull down source and documents -- so it's still more attractive in my eyes

Though there are strong advantages to portsnap: faster update, no portsdb -Uu after pulling down the ports tree, more secure (signed with keys...etc)

This doc is by no means even close to a beginners document. there are all kinds of steps left out and missing parts that a newbie would totally screw a system up... So tread lightly and research everything first by looking at other sources especially with the Kernel Make. Its a hopeless mess....

Not that it's of weighing importance, but one should take notice of the error in the filename of the certificate (`main.cf', page #1 of the tutorial). It says `smtpd.cert', whilst the certificate created is named `smtpd.crt'. Naturally, one would stumble across this even at first go, but then again, it might serve well changing it if one wanted a spotless and correct version for print.

In a configuration like that is the saslauthd need to be started also, or it is not necessary.
I am confused because I found many posts starting the saslauthd and others not.
Is the following variables needed smtpd_sasl_application_name, smtpd_sasl_type.

Hello all - I am a complete newbie to FreeBSD and any Unix/Linux based systems. My company has been a Windows only shop until a change in management. I followed this article to the "T" and am having problems. When I start Postfix, I get an error that it cannot perform a lookup using the mysql_virtual_aliases_maps.cf file. I was thinking that maybe the SELECT statement within that file is causing the problem? I do know that I had to insert my own mail_admin password, which has been done.

I am fairly certain that the other components are working. Squirrelmail's "configtest.php" comes back stating that the system is working fine. I can also telnet to amavisd and issue an EHLO command, which returns data, making it seem as though it is working.

One last item - can you give some examples of what data actually goes into the database "mail"? I have added users, a virtual domain and aliases. But some examples would give me a starting point of what the syntax actaully is. Not the INSERT string to add data to the database, but the actaul way the data is setup to be read. For example: if I have a user that has a username of "jdoe1" what would his alias be? And, if the server is currently "server1.mydomain.com" which IS the domain that I am looking to receive mail on, what is the virtual domain?

The ultimate goal of this server is to make it an external smarthost for an internal Microsoft Exchange box. I would appreciate anyone willing to give me some pointers there too once the mail system is actually up and running. I've seen that there are ways to actually pull the AD information using OpenLDAP.