Mail Server Installation and Configuration
by rey on May.27, 2009, under Linux Tutorial
links http://www.geroleo.com/?p=304
Introduction
With all of the tutorials posted here, this is one of the most complex setup that I want to share
with you. If you haven’t read my previous post regarding “DNS Installation and Configuration”
please have a look at it because mail required a valid MX record. I am not saying that, you need
to install your own name server. You can use name server somewhere but the most important
thing is that, there must be an MX record pointing to the IP address of your mail server.
My mail setup consists of the following software:
1. Postfix – The SMTP Server;
2. Cyrus SASL – SMTP Authentication;
3. pam_pgsql – Pluggable Authentication Module, sits in between Cyrus SASL &
PostgreSQL;
4. Spamassassin – Spam filter which is equipped with:
o DCC – Distributed Checksum Clearinghouses
o Pyzor
o Razor
5. ClamAV – Clam Antivirus;
6. ClamSMTP – An SMTP filter sits in between the SMTP Server and ClamAV;
7. Dovecot – POP3, POP3S, IMAP & IMAPS Server;
8. PostgreSQL – Domain and User database;
9. Squirrelmail – Webmail IMAP client;
10. And my very own cPanel web interface.
The mail server which I am going to build supports multiple domains. Each domain has their
own unique users which means that user@domain1 is totally different from user@domain2, they
have separate mailboxes.
Procedure
1. Database Installation & Configuration;
Install the postgresql database server
# yum -y install postgresql postgresql-server postgresql-
contrib
Enable postgresql to start at boot in runlevel 2,3,4 & 5
# chkconfig ––level 2345 postgresql on
Start the postgresql server now
# service postgresql start
Modify postgresql.conf
# vi /var/lib/pgsql/data/postgresql.conf
listen_addresses = ‘localhost’
port = 5432
datestyle = ’sql, mdy’
Modify pg_hba.conf
# vi /var/lib/pgsql/data/pg_hba.conf
local all all trust
host all all 127.0.0.1/32 trust
host all all ::1/128 trust
Disable selinux protection for postgresql otherwise it will
give us headache;
# setsebool -P postgresql_disable_trans=on
Restart the database server to activate the changes
# service postgresql restart
Create the database user “mail”
# createuser -U postgres mail
Create the database “mail”
# createdb -U postgres -E utf-8 mail
Download the database schema then load to the database
server
# wget -O – http://www.geroleo.com/wp-
content/uploads/2009/05/mail.sql | psql -U postgres -d mail
-f -
Create the admin user to be use for the cpanel web
interface. Please notice the password and changed it with
your own.
# psql -U postgres -d mail -c "INSERT INTO sysusers
(username,password,name) VALUES
('admin',crypt('Pass123',gen_salt('md5')),'System
Administrator')"
Allow access to user admin with read/write permission to the
module “access” in cpanel web interface.
# psql -U postgres -d mail -c "INSERT INTO access
(username,module,read,write,mode) VALUES
('admin','access','true','true','rw')"
2. Web server intallation and configuration and the cPanel web interface
Install the http server and other required softwares
# yum -y install httpd perl-DBI perl-DBD-Pg
Allow httpd to connect to the database server
# setsebool -P httpd_can_network_connect_db=on
Download and uncompress the cPanel
# wget -O – http://www.geroleo.com/wp-
content/uploads/2009/05/cpanel.tgz | tar -zxpf – -C /
Change some selinux attributes
# chcon -R -u system_u -t httpd_sys_content_t
/usr/local/cpanel/
# chcon -t httpd_unconfined_script_exec_t
/usr/local/cpanel/index.cgi
# chcon -R -t httpd_sys_script_exec_t /usr/local/cpanel/bin/
The http configuration file for my webmail and the cpanel
# vi /etc/httpd/conf/httpd.conf
# At line 972 I put this line
NameVirtualHost 192.168.56.2:80
# At line 211 I put this entry
Include vhost.d/*.conf
Create the virtual host directory
# mkdir /etc/httpd/vhost.d
Create my virtual host configuration
# vi /etc/httpd/vhost.d/geroleo.com.conf
Allow http,https,mail,postgres,pop3 & imap traffic, Other
ports entry are:
postgres:tcp,pop3:tcp,imap:tcp
# system-config-securitylevel-tui
Enable httpd to start at boot in runlevel 2,3,4 & 5
# chkconfig ––level 2345 httpd on
Start the httpd server
# service httpd start
3. cPanel is my custom web application to manage domain, users and mail aliases. You can
use this program at your own risk. I will not be liable if your server explodes due to the
use of this program. I want you to know that cPanel runs in suid mode as “root” which
means that even though httpd process is owned by user and group “apache” this program
has the access level as root which has access to everything in the server.
The cPanel login screen;
Setting up the access permission;
See the POSTFIX sub-menu as it appears when you click it.
Once you create a domain, cPanel will add it to the database
in “domains” table and will create a folder in /home.
And here is the User Manager. If you create user on the
selected domain, it will add directory in /home/$(domain)/$
(user) and will served as the user’s mailbox.
4. Dovecot Installation and Configuration;
Install dovecot package with yum
# yum -y install dovecot
Enable dovecot to start at boot in run level 2,3,4 & 5
# chkconfig ––level 2345 dovecot on
Modify /etc/dovecot.conf
# vi /etc/dovecot.conf
Create /etc/dovecot-sql.conf
# vi /etc/dovecot-sql.conf
Start the dovecot daemon
# service dovecot start
My next step is to test dovecot. My nose bleeds struggling
dovecot and selinux because selinux prohibits dovecot to
authenticate user and to access user’s mailbox as well.
After writing and installed tons of semodule and yet keep on
failing, I have no choice but to disable it:
# setsebool -P dovecot_disable_trans=on && service dovecot
restart
The final test for my dovecot. First is for POP3. Note if
telnet is not yet installed, use “yum -y install telnet”;
and then for IMAP.
5. Squirrelmail Installation and Configuration
You can download squirrelmail web client from http://www.squirrelmail.org/ but I have a
copy of squirrelmail which is built with MS Outlook skin and a password changer
designed to fit my PostgreSQL database. The following procedure is applicable if you use
the copy from here;
Download and extract the file;
# wget -O – http://www.geroleo.com/wp-
content/uploads/2009/05/squirrelmail.tgz | tar -zxf – -C /
Fix permissions;
# chown -R root:root /usr/local/squirrelmail/
# chown -R apache:apache /usr/local/squirrelmail/data
# chmod 0755 /usr/local/squirrelmail/data
# chcon -R -u system_u -t httpd_sys_content_t /usr/local/squirrelmail/
Modify the configuration file to fit my needs;
# vi /usr/local/squirrelmail/config/config.php
Install php and restart httpd
# yum -y install php php-pgsql php-pear php-pear-DB
# service httpd restart
Access the webmail now;
The login screen;
and the main screen.
6. We are almost 50% done. Next, we will install and configure ClamAV and ClamSMTP
The easiest way to install ClamAV is to install the rpmforge
repository;
# rpm -ivh
http://apt.sw.be/redhat/el5/en/i386/rpmforge/RPMS/rpmforge-
release-0.3.6-1.el5.rf.i386.rpm
Then install clamav packages using yum;
# yum ––enablerepo=\* -y install clamav clamd clamav-db
clamav-devel
Install the compiler and rpm builder;
# yum -y install rpm-build gcc make automake autoconf
Download ClamSMTP rpm source from
http://www.inet.lt/clamsmtp/. Please always get the latest
version;
# wget http://www.inet.lt/clamsmtp/clamsmtp-1.10-1.src.rpm
Build the source rpm;
# rpmbuild ––rebuild clamsmtp-1.10-1.src.rpm
After successful build, there should be written file
/usr/src/redhat/RPMS/i386/clamsmtp-1.10-1.i386.rpm, If so,
then install it;
# rpm -ivh /usr/src/redhat/RPMS/i386/clamsmtp-1.10-
1.i386.rpm
Configure clamd, normally the default configuration runs
perfectly. If you are curious, just take a look at that
file;
# vi /etc/clamd.conf
Configure clamsmtpd;
# vi /etc/clamsmtpd.conf
# This is my working configuration
OutAddress: 127.0.0.1:10026
Listen: 127.0.0.1:10025
ClamAddress: /var/run/clamav/clamd.sock
Header: X-Virus-Scanned: ClamAV using ClamSMTP
Action: drop
User: clamav
Enable clamd & clamsmtpd at boot process;
# chkconfig ––level 2345 clamd on
# chkconfig ––level 2345 clamsmtpd on
I found no way to deal with selinux and clamav, the only
possible way is to disable protection for it;
# setsebool -P clamd_disable_trans=on
# setsebool -P clamscan_disable_trans=on
# setsebool -P freshclam_disable_trans=on
Start the service now
# service clamd start
# service clamsmtpd start
7. Postfix Installation;
Installing postfix is not just as simple as “yum -y install
postfix” because the default rpm build doesn’t compiled to
support pgsql though postfix does support it;
Here is the source RPM I’d been customized to support pgsql
otherwise, you have to download the source from the distro’s
repo and modify the spec file;
# wget http://www.geroleo.com/wp-
content/uploads/2009/05/postfix-2.3.3-3.src.rpm
Before the build, we need to install all the required
dependencies;
# yum -y install db4-devel pkgconfig zlib-devel openldap-
devel cyrus-sasl-devel pcre-devel openssl-devel postgresql-
devel
The actual build;
# rpmbuild ––rebuild postfix-2.3.3-3.src.rpm
Install postfix now;
# rpm -ivh /usr/src/redhat/RPMS/i386/postfix-2.3.3-
3.i386.rpm
Disable selinux protection for postfix;
# setsebool -P postfix_disable_trans=on
8. Download, compile and install pam_pgsql;
Install the required dependencies;
# yum -y install pam-devel libmhash-devel libmhash
postgresql-devel
Change directory /usr/src;
# cd /usr/src
Download and extract the source, please check the site and
take the latest as possible;
# wget -O –
http://puzzle.dl.sourceforge.net/sourceforge/pam-pgsql/pam-
pgsql-0.7.tar.gz | tar -zxf -
Change directory pam-pgsql-0.7
# cd pam-pgsql-0.7
Start to compile;
# ./configure
# make
Install now;
# make install
Configure pam_pgsql;
# vi /etc/pam_pgsql.conf
host = localhost
database = mail
user = mail
table = users
user_column = userid
pwd_column = password
expired_column = expired
newtok_column = newtok
debug = 0
pw_type = crypt
Configure /etc/pam.d/smtp, use tabs to align;
# vi /etc/pam.d/smtp
#%PAM-1.0
#auth include system-auth
#account include system-auth
auth required pam_pgsql.so
account required pam_pgsql.so
Configure /usr/lib/sasl2/smtpd.conf;
# vi /usr/lib/sasl2/smtpd.conf
pwcheck_method: saslauthd
mech_list: login plain
9. Install, configure and test Cyrus SASL;
Install cyrus sasl package and its dependencies;
# yum -y install cyrus-sasl cyrus-sasl-plain
Configure saslauthd start-up config;
# vi /etc/sysconfig/saslauthd
SOCKETDIR=/var/run/saslauthd
MECH=pam
FLAGS=-r
Disable selinux protection for saslauthd;
# setsebool -P saslauthd_disable_trans=on && service
saslauthd restart
Enbale saslauthd to start at boot in run level 2,3,4 &5;
# chkconfig ––level 2345 saslauthd on
Start saslauthd now;
# service saslauthd start
Test SASL;
# testsaslauthd -u [email protected] -p 1234 -s smtp
10. Postfix Configuration, the heart of the system. Please read the documents located
in /usr/share/doc/postfix*/ to learn more about postfix and to know how it works.
# cd /etc/postfix
Create/modify postfix main configuration file
# vi main.cf
# Postfix General Config
transport_maps = pgsql:/etc/postfix/transport.cf
virtual_uid_maps = pgsql:/etc/postfix/uids.cf
virtual_gid_maps = pgsql:/etc/postfix/gids.cf
virtual_mailbox_base = /home
virtual_mailbox_maps = pgsql:/etc/postfix/mailboxes.cf
virtual_mailbox_domains =
pgsql:/etc/postfix/virtual_domains.cf
virtual_alias_maps =
pgsql:/etc/postfix/virtual_aliases.cf
# Don’t just invent this one, If you’re using an
unregistered domain/hostname,
# you can simple add it to /etc/hosts bound to the IP
address of your
# network interface card.
myhostname = mail.geroleo.com
myorigin = $myhostname
mynetworks = localhost.localdomain $myhostname
mydestination = localhost.localdomain $myhostname
mailbox_size_limit = 0
message_size_limit = 0
virtual_mailbox_limit = 0
#Cyrus SASL
smtp_sasl_auth_enable = no
smtpd_sasl_auth_enable = yes
smtpd_sasl_authenticated_header = yes
broken_sasl_auth_clients = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $mydomain
unknown_local_recipient_reject_code = 450
# SpamAssassin
strict_rfc821_envelopes = yes
disable_vrfy_command = yes
smtpd_helo_required = yes
# ClamAV
content_filter = scan:[127.0.0.1]:10025
receive_override_options = no_address_mappings
# Others
header_checks = regexp:/etc/postfix/regexp_header
# Added by postfix
readme_directory = /usr/share/doc/postfix-
2.3.3/README_FILES
sample_directory = /usr/share/doc/postfix-2.3.3/samples
sendmail_path = /usr/sbin/sendmail
html_directory = no
setgid_group = postdrop
command_directory = /usr/sbin
manpage_directory = /usr/share/man
daemon_directory = /usr/libexec/postfix
newaliases_path = /usr/bin/newaliases
mailq_path = /usr/bin/mailq
queue_directory = /var/spool/postfix
mail_owner = postfix
unknown_local_recipient_reject_code = 450
# vi transport.cf
user=mail
password=”
dbname=mail
table=transport
select_field=transport
where_field=domain
hosts=localhost
# vi uids.cf
user=mail
password=”
dbname=mail
table=users
select_field=uid
where_field=userid
hosts=localhost
# vi gids.cf
user=mail
password=”
dbname=mail
table=users
select_field=gid
where_field=userid
hosts=localhost
# vi mailboxes.cf
user=mail
password=”
dbname=mail
table=mailboxes
select_field=mailbox
where_field=userid
hosts=localhost
# vi virtual_domains.cf
user=mail
password=”
dbname=mail
table=domains
select_field=domain
where_field=domain
hosts=localhost
# vi virtual_aliases.cf
user=mail
password=”
dbname=mail
table=aliases
select_field=address
where_field=userid
hosts=localhost
As specified in main.cf “header_checks =
regexp:/etc/postfix/regexp_header” this file will decide to
those emails marked as Spam. For me, I have no time to check
those spam. My rule is to discard those emails without
informing the sender that his email was discarded.
# vi regexp_header
/^X-Spam-Flag: YES/ DISCARD
Modify the master.cf file
# vi master.cf
This is the beginning of the file. This tells postfix to
pass the email to the spamassassin content filter after
performing access check;
Then under the “spamassassin” service, we will do the actual
filtering by calling an external program
“/usr/local/bin/spamfilter.sh” passing all the required
parameters. Spamassassin job is to check and mark the email
either spam or not then send it back to postfix.
Postfix will then pass the email to the antivirus filter
service “scan” which is according to main.cf is on port
10025. Remember that, it is the ClamSMTP who is listening on
this port. ClamSMTP after receiving the email will perform
scan through the help of Clam Antivirus which is listening
on unix local socket “/var/run/clamav/clamd.sock”. All
infected emails will be discarded immediately while clean
emails will go out at port 10026 which is again a postfix
owned socket. The email will then proceed to its final
destination finally!.
Create /usr/local/bin/spamfilter.sh
# vi /usr/local/bin/spamfilter.sh
#!/bin/bash
spamassassin -e | /usr/sbin/sendmail.postfix -i “$@”
exit $?
# chmod 0755 /usr/local/bin/spamfilter.sh
Install spamassassin using yum because postfix will cry
without it and it is not neccessary to start the daemon. We
will call spamassassin directly, this is for fastest process
as possible;
# yum -y install spamassassin
Add user & group spamassassin with uid/gid 106, this is for
security reasons;
# groupadd -g 106 spamassassin
# useradd -g 106 -u 106 spamassassin
Afterwards, we will start now the postfix mail server;
# service postfix start
# chkconfig ––level 2345 postfix on
If everything is done accordingly, postfix should be up and
running now and we need to test it;
First, we will generate an encoded base 64 string to be use
for smtp authentication;
# perl -MMIME::Base64 -e 'print
encode_base64("test\@geroleo.com\000test\@geroleo.com\000123
4");'
The above command is in the form of
"username\000username\000password" (\000 is a null byte
and \@ is a escape sequence for perl because perl interprets
@ as an array. The output for this command is:
dGVzdEBnZXJvbGVvLmNvbQB0ZXN0QGdlcm9sZW8uY29tADEyMzQ=
We can start the test now;
# telnet localhost 25
Checking the email in Squirrelmail, look at the mail
headers;
/etc/hosts – Plays an important part for your postfix mail
transport agent, it must be setup correctly. The above
main.cf configuration file will work with /etc/hosts setup
below:
# Do not remove the following line, or various programs
# that require network functionality will fail.
192.168.56.2 mail.geroleo.com mail
127.0.0.1 localhost.localdomain localhost
::1 localhost6.localdomain6 localhost6
Postfix should now working with the default spamassassin
rules. Our final step is to configure spamassassin to make
it smarter.
11. Spamassassin Configuration/Add-ons Installation and Configuration;
We need 2 terminals to accomplish this task. On first
terminal, we must switch to user “spamassassin” to be use
for testing. On the other terminal, we must stay as root to
do the compilation;
Download, compile and install DCC. Do it on the second
terminal with root user logged in;
# cd /usr/src
# wget -O – http://www.dcc-servers.net/dcc/source/dcc.tar.Z
| tar -zxf -
# cd dcc-1.3.105
# ./configure
# make
# make install
# chown -R spamassassin:spamassassin /var/dcc
# vi /etc/mail/spamassassin/v310.pre
Remove the comment “#”;
loadplugin Mail::SpamAssassin::Plugin::DCC
Switch on first terminal with “spamassassin” user;
# su – spamassassin
$ cdcc “delete 127.0.0.1″
$ crontab -e
0 5 * * * /var/dcc/libexec/cron-dccd
Download, compile & install Pyzor (on terminal 2);
# cd /usr/src
# wget -O –
http://softlayer.dl.sourceforge.net/sourceforge/pyzor/pyzor-
0.5.0.tar.bz2 | tar -jxf -
# cd pyzor-0.5.0
# python setup.py build
# python setup.py install
Switch to terminal 1;
$ pyzor discover
Download, compile & install Razor (on terminal 2);
# cd /usr/src/
# wget -O –
http://puzzle.dl.sourceforge.net/sourceforge/razor/razor-
agents-2.84.tar.bz2 | tar -jxf -
# cd razor-agents-2.84
# perl Makefile.PL
# make
# make install
# cd ../
# wget -O –
http://puzzle.dl.sourceforge.net/sourceforge/razor/razor-
agents-sdk-2.07.tar.bz2 | tar -jxf -
# cd razor-agents-sdk-2.07
# perl Makefile.PL
# make
# make install
Switch to terminal 1;
$ razor-admin -d -create
$ ls -la
This directories should be present;
.pyzor
.razor
Switch to terminal 2;
# vi /etc/mail/spamassassin/local.cf
# This is my required hits, change it according to your
requirements
required_hits 3.5
use_bayes 1
bayes_auto_learn 1
bayes_auto_learn 1
bayes_path /var/lib/spamassassin/bayes/bayes
bayes_file_mode 0666
use_razor2 1
use_pyzor 1
use_dcc 1
dcc_path /usr/local/bin/dccproc
dcc_body_max 999999
dcc_timeout 10
dcc_fuz1_max 999999
dcc_fuz2_max 999999
dcc_home /var/dcc
# mkdir /var/lib/spamassassin/bayes/
# touch /var/lib/spamassassin/bayes/bayes
# chown -R spamassassin:spamassassin
/var/lib/spamassassin/bayes/
Test spamassassin on terminal 1;
$ spamassassin < /usr/share/doc/spamassassin-3.2.5/sample-
spam.txt
NOTE: Don’t forget to consult your log files if something
goes wrong or in any way your mail server is keep on
failing. It is a good practice to watch the logs while you
are configuring your system. In my case, I opened 2 ssh
sessions with PuTTY just for the log. On first session, I
execute the command:
# tail -f /var/log/messages
and on the other window:
# tail -f /var/log/maillog
I am so lazy to type those commands and I frequently use
them so, I added those commands in my .bashrc file.
# vi ~/.bashrc
# User specific aliases and functions
alias rm=’rm -i’
alias cp=’cp -i’
alias mv=’mv -i’
alias ls=’ls -Fa –color=always’
alias log=’tail -n 23 -f /var/log/messages’
alias maillog=’tail -n 23 -f /var/log/maillog’
Now, I can easily type “log” or “maillog” whenever I need
them.
CONGRATULATIONS!!! You have now a complete and secured mail server.