Last updated Februari 10 2013
Full-fledged Postfix using MySQL HOWTO
Postfix, MySQL, IMAP, WebMail, Virus- and spamscanning/checking mail system
by Tom Scholten and authors of likewise documents
v1.0
Special thanks to Remco from WellnessAndConsultancy for testdriving this tutorial
As my PostfixLDAP howto is getting agy and less used with a request from a fellow web-company and one of the main CT customers I’ve decided to write down a comprehensive guide on how to install a mailserver using Postfix based on MySQL – obviously with all the things I think you’ll need with that!
This howto will  – if succesfully deployed – give you an (FreeBSD) Postfix MySQL ViMbAdmin setup with Dovecot, RoundCube and MailScanner. Say what?
- Postfix; main mailserver (as in SMTP, so for server traffic and sending mail)
- MySQL; database
- ViMbAdmin; web-gui to administer (or give someone partial rights) your mail-addresses
- Dovecot; main mailserver (as in POP/IMAP, for fetching, storing your mail) including SIEVE (through pigeonhole) to have customer rule processing
- RoundCube; webmail frontend
- MailScanner + MailWatch; virus and spam-checks, the MailWatch is a front-end to which you can also have people de-quarantine their mail
Rules of engagement
This only describes how to build a mail-host on a secure, trusted, local network. We are not dealing with some of the things you should have in place first
- working and active pf.conf
- ssl-certificates for your web- and mail servers
- (note that you DO need the ‘pem’ format for the mailservers in this document, revert to google and ‘cacert mailserver pem’ for more information
- ensure your apache webserver has the certificates (or test-certificates) working and the production php.ini applied (see /usr/local/etc/php.ini-production)
We do not take any responsibility for your setup – this howto serves as a recipe on how you could do it. Read it and interpret it but create your own secure solution!
Documentation sources
FreeBSD 9.1 base install
install ‘plain’ (no lib32/games/doc) with ports
# freebsd-update fetch
# portsnap fetch
# cd /usr/ports/ports-mgmt/portmaster
# make install
Add to /etc/rc.conf
sendmail_enable=”NO”
sendmail_submit_enable=”NO”
sendmail_outbound_enable=”NO”
sendmail_msp_queue_enable=”NO”
mysql_enable=”YES”
apache22_enable=”YES”
postfix_enable=”YES”
dovecot_enable=”YES”
Edit /etc/make.conf
WITHOUT_X11=yes
Prepare ports
Fetch the below /var/db/ports contents
http://www.compa.nl/tmp/mailserver.ports.tgz
Build the following
# portmaster mail/postfix databases/mysql55-server mail/roundcube mail/dovecot2 mail/dovecot2-pigeonhole www/apache22 lang/php5 lang/php5-extensions devel/git devel/subversion www/smarty3 www/zend-framework databases/pear-Doctrine12 ftp/wget shells/bash mail/mailscanner databases/p5-DBD-mysql
Note; do not build MailScanner with bdc!
Prepare database environment
# mysql -uroot
> use mysql;
> update user SET password=password(‘mastersecret0’) where user=‘root’;
> flush privileges;
> quit;
# mysql -uroot -p
> create database webmail;
> grant ALL ON webmail.* to ‘roundcube’@localhost IDENTIFIED by ‘secret0’;
> create database mailscanner;
> grant ALL ON mailscanner.* to ‘mailwatch’@localhost IDENTIFIED by ‘secrety’;
> grant file on *.* to mailwatch@localhost identified by ‘secrety’;
> create database postfixmail;
> grant ALL ON postfixmail.* to ‘vimbadmin’@localhost IDENTIFIED by ‘secret1’;
> grant SELECT ON postfixmail.* to ‘dovecot’@’localhost’ IDENTIFIED by ‘secret2’;
> grant SELECT ON postfixmail.* to ‘postfix’@’localhost’ IDENTIFIED by ‘secret3’;
> grant SELECT, RELOAD, LOCK TABLES ON *.* to ‘backup’@’localhost’ IDENTIFIED by ‘secret4’;
> flush privileges;
> quit;
# mkdir -p /home/vmail
# chmod 770 /home/vmail
# vi /etc/group
Add a group ‘vmail’ with id 2000
# useradd
> “vmail†as username
> “Virtual Mailbox†as description
> id 2000
> /home/vmail as directory
> group = vmail
> additional groups = mail
> nologin
# chown -R vmail:mail /home/vmail
Dovecot:
# cp -pfr /usr/local/share/doc/dovecot/example-configs/* /usr/local/etc/dovecot/
Adjust according to
http://www.compa.nl/tmp/mailserver.dovecott.diff.txt
Postfix:
Add to /usr/local/etc/postfix/master.cf
# Dovecot LDA
dovecot unix – n n – – pipe
flags=DRhu user=vmail:mail argv=/usr/local/libexec/dovecot/deliver -d ${recipient}
Add the contents of http://www.compa.nl/tmp/mailserver.postfix.main.cf.add.txt to main.cf
Create the mysql_ files as shown in http://www.compa.nl/mailserver.postfix.mysql.files.txt
Add header_checks = regexp:/usr/local/etc/postfix/header_checks to main.cf
Create the file and have it contain
/^Received:/ HOLD
Apache:
In /usr/local/etc/apache22/httpd.conf
- Find the ‘DirectoryIndex’ declaration and add ‘index.php’ behind index.html (with a space separating them)
- ‘untick’ the ‘vhost’ file inclusion near the bottom
- add the following somewhere near there
# PHP settings
Include etc/apache22/extra/httpd-php.conf
Create an ./extra/httpd-php.conf containing
#
# This is the Apache server configuration file providing PHP support.
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
Create a file in ./Includes named ‘yourhost.conf’
<Virtualhost *:80>
ServerName yourhost.example.com
DocumentRoot /usr/local/www/apache22/data/
Alias /vimbadmin /usr/local/vimbadmin/public
<Directory /usr/local/vimbadmin/public>
Options FollowSymLinks
AllowOverride None
Order allow,deny
allow from all
SetEnv APPLICATION_ENV production
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ – [NC,L]
RewriteRule ^.*$ /vimbadmin/index.php [NC,L]
</Directory>
</VirtualHost>
Vimbadmin
# cd /usr/local/
# wget {url to latest version from https://github.com/opensolutions/ViMbAdmin/archives/develop}
# tar xfvz {file you got}
# ln -s {dir it created} vimbadmin
# cd /usr/local/vimbadmin
# cp application/configs/application.ini.dist application/configs/application.ini
# vi application/configs/application.ini
Set resources.frontController.params.displayExceptions = 0 to 1
Adjust ID’s to 2000
Adjust connection to
resources.doctrine.connection_string = “mysql://vimbadmin:supersecret@localhost/postfixmail”
DO NOT FORGET TO RESET displayExceptions back to 0 if vimbadmin GUI works!
Next switch to the /usr/local/vimbadmin/library directory and create symlinks
# ln -s /usr/local/share/pear/Doctrine Doctrine
# ln -s /usr/local/share/smarty3/ Smarty
# ln -s /usr/local/share/ZendFramework/library/Zend Zend
Now initialize the vimbadmin database
# cd /usr/local/vimbadmin
# bin/doctrine-cli.php create-tables
Putting it together
Stage1
Start your webserver
# /usr/local/etc/rc.d/apache22 start
Browse to http://192.168.0.1/vimbadmin
Get the “salt†from this page
Put that in the application.ini file mentioned above + reset the displayExceptions to 0
Reload the page
Put in the salt
Put in a mailaddress en password
Congratulations, you can now login again 🙂
Now create a test-domain (example.org) + mailbox (tester@example.org)
Stage2
Initiate a tail (-f) on /var/log/maillog
# /usr/local/etc/rc.d/dovecot start
Look for any errors and correct them (did you do your certificates!)
Check postfix config (warnings are OK-ish for now)
# postfix check
If all is well start postfix
# /usr/local/etc/rc.d/postfix start
Again, same thing (warnings are OK-ish for now)
Check resolving
# postmap -q testuser@example.org mysql:/usr/local/etc/postfix/mysql_virtual_mailbox_maps.cf
Then start a telnet session to verify delivery
$ telnet localhost 25
you> ehlo host
250-something
you> mail from: johndoe
250 2.1.0 Ok
you> rcpt to: johndoe
THIS ONE SHOULD FAIL
you> rcpt to: johndoe@example.org
THIS ONE SHOULD FAIL
you> rcpt to: testuser@example.org
THIS ONE SHOULD GO OK
250 2.1.5 Ok
you> data
354 End data with .
you> test
you> .
250 2.0.0 Ok: queued as 9729067C17
you> quit
221 2.0.0 Bye
Connection closed by foreign host.
Check your postfix/dovecot output in maillog for delivery
# ls -lR /home/mail/example.org
There should be some mail in the maildir there 🙂
Congratulations you now have a working, basic, setup for your mailserver
Next up
Apache config for PHP
# cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
# vi /usr/local/etc/php.ini
adjust error_log to /var/log/php.log
adjust date.timezone to ‘CET’
# touch /var/log/php.log
# chown www:www /var/log/php.log
Add php.log to /etc/newsyslog
Restart apache /usr/local/etc/rc.d/apache22 restart
MailScanner (and Postfix)
In /usr/local/etc/postfix add header_checks = regexp:/usr/local/etc/postfix/header_checks to main.cf
Create the file header_checks and have it contain
/^Received:/ HOLD
Next create Mailscanners’ directories
# mkdir -p /var/spool/MailScanner/incoming
# mkdir -p /var/spool/MailScanner/incoming/Locks
# mkdir -p /var/spool/MailScanner/quarantine
# mkdir -p /var/spool/mqueue
# mkdir -p /var/spool/mqueue.in
Getting ‘mailwatch’ from http://sourceforge.net/projects/mailwatch/files/
# mkdir /tmp/src
# cd /tmp/src
# wget {url}
# tar xfvz {file from url}
# cd mailw*
*HINT* if the below command fails, replace “TYPE=MyISAM†with “Engine=MyISAM†through the create file and look for “timestamp(14)†and set this to “timestampâ€
#mysql -umailwatch -p mailscanner < create.sql
#vi MailScanner_perl_scripts/MailWatch.pm
Edit the file for your database connections
# cp MailScanner_perl_scripts/MailWatch.pm /usr/local/lib/MailScanner/MailScanner/CustomFunctions/
Create the admin user
#mysql mailscanner -u mailwatch -p
> INSERT INTO users SET username = ‘youruser’, password = md5(‘secret2much’), fullname = ‘Me Myself and I’, type =’A’
> \q
# mkdir {/wwwroot}/mailwatch
# cp -pfr mailscanner/* {/wwwroot}/mailwatch/
# cp {/wwwroot}/mailwatch/conf.php.example {/wwwroot}/mailwatch/conf.php
# vi {/wwwroot}/mailwatch/conf.php
Set your DB-user and Password & change below lines
define(‘MAILWATCH_HOME’, ‘{/wwwroot}/mailwatch’);
define(‘MS_CONFIG_DIR’, ‘/usr/local/etc/MailScanner/’);
define(‘MS_LIB_DIR’, ‘/usr/local/lib/MailScanner/’);
define(‘SA_RULES_DIR’, ‘/usr/local/share/spamassassin/’);
Edit /usr/local/etc/MailScanner/MailScanner.conf
Change
- Always Looked Up Last = &MailWatchLogging
- Detailed Spam Report = yes
- Quarantine Whole Message = yes
- Quarantine Whole Message As Queue Files = no
- Include Scores In SpamAssassin Report = yes
- Quarantine User = root
- Quarantine Group = apache (this should be the same group as your web server)
- Quarantine Permissions = 0660
- Incoming Work Permissions = 0640
Clean up
# rm -r /tmp/src/mailwatch*
Set groups
# vi /etc/group
Add “clamav” to the postfix group
Now add to your /etc/rc.conf
mailscanner_enable=â€yesâ€
clamav_clamd_enable=”YES”
clamav_freshclam_enable=”YES”
# /usr/local/etc/rc.d/clamav-freshclam start
{wait for a bit}
# /usr/local/etc/rc.d/clamav-clamd start
{make sure it’s succesfull, or wait some more and retry}
{If taking too long, run ‘freshclam’ and wait for it to download}
# /usr/local/etc/rc.d/mailscanner start
Watch for the output and try sending out a testmail to root – see if logging and processing work again
Add the following lines to your apache configuration, we’ve included the rules for vimbadmin just to be sure 🙂
<Virtualhost *:80> ServerName newmail.example.org DocumentRoot /usr/local/www/apache22/data/ Alias /vimbadmin /usr/local/vimbadmin/public <Directory /usr/local/vimbadmin/public> Options FollowSymLinks AllowOverride None Order allow,deny allow from all SetEnv APPLICATION_ENV production RewriteEngine On RewriteCond %{REQUEST_FILENAME} -s [OR] RewriteCond %{REQUEST_FILENAME} -l [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^.*$ - [NC,L] RewriteRule ^.*$ /vimbadmin/index.php [NC,L] </Directory> Alias /mailscanner /www/example.org/newmail/secure/mailwatch <Directory /www/example.org/newmail/secure/mailwatch> Options FollowSymLinks AllowOverride None Order allow,deny allow from all SetEnv APPLICATION_ENV production </Directory> </VirtualHost>
Todo:
Roundcube config
Before going live
Check firewall (pf.conf), and it’s activation
Install tripwire, monitoring and all that kind of stuff!
Tom Scholten is consultant with Snow B.V., a Dutch Technical Consultancy Company supplying specialists in the fields of Storage, Networking and Unix