Debian Email Server Setup

This guide will get you down the road with a Debian Squeeze based Email server.  In this setup IMAP and STMP reside on the same machine.   Wall-of-text warning: this is the whole shebang. 

### Install the needed packages
apt-get install postfix postfix-mysql mysql-server mysql-client dovecot-pop3d libsasl2-2 libsasl2-modules\
libsasl2-modules-sql sasl2-bin libpam-mysql openssl telnet mailutils
 
Select Internet Site for your postfix install and add the FQDN of your server when prompted.
 
Set the mysql root password when prompted (pick a good one, nothing like password1234). 
 

Setup MySQL

 
Login to mysql as root with the password you just set:
 
mysql -u root -p
 
Create a database for postfix to use:
 
create database mail
use mail;

grant select, insert, update, delete on mail.* to 'mailadmin'@'localhost' identified by 'areallygoodpassword';
grant select, insert, update, delete on mail.* to 'mailadmin'@'localhosthost.localdomain' identified by 'areallygoodpassword';
flush privileges;


create table domains (domain varchar(50) NOT NULL, PRIMARY KEY (domain) );
create table forwardings (source varchar(80) NOT NULL, destination TEXT NOT NULL, PRIMARY KEY (source) );
create table users (email varchar(80) NOT NULL, password varchar(20) NOT NULL, PRIMARY KEY (email) );
create table transport ( domain varchar(128) NOT NULL default '', transport varchar(128) NOT NULL default '', UNIQUE KEY domain (domain) );

Configure Postfix

Create a file /etc/postfix/mysql-virtual\_domains.cf and add the following lines:
 
user = mailadmin
password = lolnotarealpassword
dbname = mail
query = SELECT domain AS virtual FROM domains WHERE domain='%s'
hosts = 127.0.0.1
 
Create a file /etc/postfix/mysql-virtual\_domains.cf and add the following lines:
 
user = mailadmin

password = lolnotarealpassword
dbname = mail
query = SELECT destination FROM forwardings WHERE source='%s'
hosts = 127.0.0.1
 
Create a file /etc/postfix/mysql-virtual\_mailboxes.cf and add the following lines:
 
user = mailadmin
password = lolnotarealpassword
dbname = mail
query = SELECT CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/') FROM users WHERE email='%s'
hosts = 127.0.0.1
 
Create a file /etc/postfix/mysql-virtual\_email2email.cf and add the following lines:
 
user = mailadmin
password = lolnotarealpassword
dbname = mail
query = SELECT email FROM users WHERE email='%s'
hosts = 127.0.0.1
 
Set the correct permissions for the mysql postfix config files:
 
chmod o= /etc/postfix/mysql-virtual_*.cf
chgrp postfix /etc/postfix/mysql-virtual_*.cf
 
Next, we\'ll need to create a user to handle virtual mail.  All virtual mailboxes will be stored in this user\'s home directory.
 
groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /home/vmail -m
 
Edit /etc/postfix/main.cf
 
myhostname = fqdn.example.com
mydestination = fqdn.exmaple.com, localhost.example.com,localhost, localhost.localdomain
mailbox_size_limit = 0
message_size_limit = 30720000
virtual_alias_domains =
virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual_forwardings.cf, mysql:/etc/postfix/mysql-virtual_email2email.cf
virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual_domains.cf
virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailboxes.cf
virtual_mailbox_base = /home/vmail
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_authenticated_header = yes
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_use_tls = yes
smtpd_tls_cert_file = /etc/certs/mail.cert
smtpd_tls_key_file = /etc/certs/mail.key
virtual_create_maildirsize = yes
virtual_maildir_extended = yes
proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $virtual_mailbox_limit_maps
virtual_transport=dovecot
dovecot_destination_recipient_limit=1

You can also use postconf -e to add these lines.

In order to allow smtps with sasl authentication open /etc/postfix/master.cf and comment out the following lines:

smtps     inet  n       -       -       -       -       smtpd
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
 
Create a self signed certificate for postfix, dovecot and nginx to use. If you\'re going to purchase a certificate please stop at the CSR generation and send it off to your CA. 
 
mkdir /etc/certs
cd /etc/certs
openssl req -nodes -newkey rsa:2048 -keyout mail.key -out mail.csr
 
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:North Carolina
Locality Name (eg, city) []:Boone
Organization Name (eg, company) [Internet Widgits Pty Ltd]:lolcompany
Organizational Unit Name (eg, section) []:lolcompany section
Common Name (eg, YOUR name) []:fqdn.example.com
Email Address []:support@example.com

Protect the key file with proper permissions:

chmod o= mail.key
 
Now sign the request, unless you wish to send it off:
 
openssl x509 -req -days 3650 -in mail.csr -signkey mail.key -out mail.cert
 
I highly recommend sending off for an actual SSL certificate.  Using a self signed certificate will teach your users bad habits.  
 
Configure saslauthd to use MySQL
 
mkdir -p /var/spool/postfix/var/run/saslauthd
 
Backup the default saslauthd config file:
 
cp -a /etc/default/saslauthd /etc/default/saslauthd.bak
 
Edit the following lines:
START=yes
OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd -r"
 
Create a file at /etc/pam.d/smtp and add the following lines:
 
auth    required   pam_mysql.so user=mailadmin passwd=lolpassword host=127.0.0.1 db=mail table=users usercolumn=email passwdcolumn=password crypt=1
account sufficient pam_mysql.so user=mailadmin passwd=lolpassword host=127.0.0.1 db=mail table=users usercolumn=email passwdcolumn=password crypt=1
 
Create a file at /etc/postfix/sasl/smtpd.conf and add the following lines:
 
pwcheck_method: saslauthd
mech_list: plain login
allow_plaintext: true
auxprop_plugin: mysql
sql_hostnames: 127.0.0.1
sql_user: mailadmin
sql_passwd: lolpassword
sql_database: mail
sql_select: select password from users where email = '%u'
 
Set correct ownership and permissions:
 
chmod o= /etc/pam.d/smtp
chmod o= /etc/postfix/sasl/smtpd.conf
 
Add the postfix user to the sasl group:
 
adduser postfix sasl
\ Restart the services:
 
service postfix restart
service saslauthd restart
 
Postfix and SASL are now ready to go.
 

Dovecot Configuration

 
Enable dovecot support in /etc/postfix/master.cf:
 
dovecot   unix  -       n       n       -       -       pipe
    flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -d ${recipient}
 
Backup original config file:
 
cp -a /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.bak
 
Replace the contents of the dovecot.conf file with the following, replacing exmaple.com with your domain name where necessary: 
 
protocols = imap imaps pop3 pop3s
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_location = maildir:/home/vmail/%d/%n/Maildir
ssl_cert_file = /etc/certs/mail.cert
ssl_key_file = /etc/certs/mail.key

namespace private {
    separator = .
    prefix = INBOX.
    inbox = yes
}

protocol lda {
    log_path = /home/vmail/dovecot-deliver.log
    auth_socket_path = /var/run/dovecot/auth-master
    postmaster_address = postmaster@example.com
    mail_plugins = sieve
    global_script_path = /home/vmail/globalsieverc
}


protocol pop3 {
    pop3_uidl_format = %08Xu%08Xv
}

protocol imap {
  mail_plugins = autocreate
}

plugin {
  autocreate = INBOX.Trash
  autocreate2 = INBOX.Spam
  autocreate3 = INBOX.Drafts
  autocreate4 = INBOX.Sent
  autosubscribe = INBOX.Trash
  autosubscribe2 = INBOX.Spam
  autosubscribe3 = INBOX.Drafts
  autosubscribe4 = INBOX.Sent

}

auth default {
    user = root

    passdb sql {
        args = /etc/dovecot/dovecot-sql.conf
    }

    userdb static {
        args = uid=5000 gid=5000 home=/home/vmail/%d/%n allow_all_users=yes
    }

    socket listen {
        master {
            path = /var/run/dovecot/auth-master
            mode = 0600
            user = vmail
        }

        client {
            path = /var/spool/postfix/private/auth
            mode = 0660
            user = postfix
            group = postfix
        }
    }
}
 
Setup the dovecot mysql driver:
 
Backup original dovecot-sql.conf file:
 
cp -a /etc/dovecot/dovecot-sql.conf /etc/dovecot/dovecot-sql.conf.bak
 
Remove the contents of /etc/dovecot/dovecot-sql.conf and replace it with the following:
 
driver = mysql
connect = host=127.0.0.1 dbname=mail user=mailadmin password=lolpassword
default_pass_scheme = CRYPT
password_query = SELECT email as user, password FROM users WHERE email='%u';
 
Now you need to allow the vmail use read access to the dovecot.conf file:
 
chgrp vmail /etc/dovecot/dovecot.conf
chmod g+r /etc/dovecot/dovecot.conf
 
Create a file at /home/vmail/globalsieverc and add the following lines:
 

``` {style="font-size: 13px;"}

Move spam to spam folder

if header :contains "X-Spam-Flag" ["YES"] { fileinto "INBOX.Spam"; stop; } ```

Now restart the dovecot service:
 
/etc/init.d/dovecot restart
 
If everything is successful you should see the following line in your /var/log/mail.log file:
 
Dec  8 16:30:53 mail dovecot: Dovecot v1.2.15 starting up (core dumps disabled)
Dec  8 16:30:53 mail dovecot: auth-worker(default): mysql: Connected to 127.0.0.1 (mail)
 
Next you want to check on your aliases to make sure postmaster and root are setup properly:
 
In /etc/aliases:
 
postmaster: root
root: someone_who_will_read_this_mail@example.com
 
You may want to set aliases for abuse, info etc. 
 
This will move mail with a spam flag to the user\'s spam folder.
 
Update the aliases and restart postfix:
 
newaliases
/etc/init.d/postfix restart
 

Extras: Spam and Virus Checking

 
At this point you have a fully functioning mail server.  You can go on using this without any real issues.  However it has very little in the way of antivirus or antispam protection. First we need to install clamav and clamsmtp:
 
apt-get install amavisd-new spamassassin clamav clamav-daemon zoo unzip bzip2 unzoo libnet-ph-perl\ 
libnet-snpp-perl libnet-telnet-perl nomarch lzo
Edit /etc/amavis/conf.d/15-content\_filter\_mode and comment out the following lines:
 
@bypass_virus_checks_maps = (
   \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);


@bypass_spam_checks_maps = (
   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);
 
 
Add the clamav user to amavis group and restart the services:
 
adduser clamav amavis
adduser amavis clamav
/etc/init.d/amavis restart
/etc/init.d/clamav-daemon restart
 
Add the following lines to /etc/clamav/freshclam.conf:
 
NotifyClamd /etc/clamav/clamd.conf
Restart freshclam:
 
/etc/init.d/clamav-freshclam restart
 
Edit /etc/postifx/master.cf, add the following lines:
 
amavis unix     -       -       -       -       2       smtp
        -o smtp_data_done_timeout=1200
        -o smtp_send_xforward_command=yes


127.0.0.1:10025 inet    n       -       -       -       -       smtpd
        -o content_filter=
        -o local_recipient_maps=
        -o relay_recipient_maps=
        -o smtpd_restriction_classes=
        -o smtpd_client_restrictions=
        -o smtpd_helo_restrictions=
        -o smtpd_sender_restrictions=
        -o smtpd_recipient_restrictions=permit_mynetworks,reject
        -o mynetworks=127.0.0.0/8
        -o strict_rfc821_envelopes=yes
        -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
        -o smtpd_bind_address=127.0.0.1
 
Enable spamassassin, edit /etc/default/spamassassin:
 
ENABLED=1
CRON=1
 
Start the spamd service:
 
/etc/init.d/spamassassin start
 
Now we need to tweak some amavis settings to get X-Spam headers in our messages (handy for debugging):
 
Edit /etc/amavis/conf.d/20-debian\_defaults:
 
sa_spam_subject_tag = '***SPAM*** ';
$sa_tag_level_deflt  = -10.0;  # add spam info headers if at, or above that level
$sa_tag2_level_deflt = 6.31; # add 'spam detected' headers at that level
$sa_kill_level_deflt = 6.31; # triggers spam evasive actions
$sa_dsn_cutoff_level = 10;   # spam level beyond which a DSN is not sent
 
I change the \$sa\_tag\_level\_deflt  from 2.0 to -10 to get more information in the headers. You can change the other various SA cut off levels to whatever seems to kill the most spam for you.
 
Next edit the etc/amavis/conf.d/50-user file and add the following line:
 
@local_domains_acl = ( "example.com", "example.org" );
Add all of the domains that this machine will be handling mail for.
 
and restart amavis:
 
/etc/init.d/amavis restart
 
Now you have a fairly robust anti-spam and anti-virus email gateway.
 
Next we want to configure webmail with nginx and Roundcube mail.
 
If you want the newer nginx binaries add the repository information to /etc/apt/sources.lst:
 
deb http://nginx.org/packages/debian/ squeeze nginx
deb-src http://nginx.org/packages/debian/ squeeze nginx
 
apt-get update

apg-get install nginx php5-cgi php5-mysql php5-curl php5-gd php5-idn php-pear php5-imagick\ 
php5-imap php5-mcrypt php5-memcache php5-ming php5-pspell php5-recode php5-snmp php5-sqlite\ 
php5-tidy php5-xmlrpc php5-xsl php-apc spawn-fcgi
 
Tell php what timezone you\'re in:
 
cat /etc/timezone
 
Now edit /etc/php5/cli/php.ini and set date.timezone to the proper value.  You might want to adjust the upload\_max\_filesize and post\_max\_size to match your attachment size. 
 
Edit /etc/php5/conf.d/suhosin.ini, uncomment and change to off:
 
suhosin.session.encrypt = off
 
Create a file at /usr/bin/php-fastcgi:
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash

FASTCGI_USER=www-data
FASTCGI_GROUP=www-data
ADDRESS=127.0.0.1
PORT=9000
PIDFILE=/var/run/php-fastcgi/php-fastcgi.pid
CHILDREN=6
PHP5=/usr/bin/php5-cgi
/usr/bin/spawn-fcgi -a $ADDRESS -p $PORT -P $PIDFILE -C $CHILDREN -u $FASTCGI_USER -g $FASTCGI_GROUP -f $PHP5
 
Now make it executable:
 
chmod +x /usr/bin/php-fastcgi
 
Now create a file at /etc/init.d/php-fastcgi:
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/bin/bash

PHP_SCRIPT=/usr/bin/php-fastcgi
FASTCGI_USER=www-data
FASTCGI_GROUP=www-data
PID_DIR=/var/run/php-fastcgi
PID_FILE=/var/run/php-fastcgi/php-fastcgi.pid
RET_VAL=0

case "$1" in
    start)
      if [[ ! -d $PID_DIR ]]
      then
        mkdir $PID_DIR
        chown $FASTCGI_USER:$FASTCGI_GROUP $PID_DIR
        chmod 0770 $PID_DIR
      fi
      if [[ -r $PID_FILE ]]
      then
        echo "php-fastcgi already running with PID `cat $PID_FILE`"
        RET_VAL=1
      else
        $PHP_SCRIPT
        RET_VAL=$?
      fi
  ;;
    stop)
      if [[ -r $PID_FILE ]]
      then
        kill `cat $PID_FILE`
        rm $PID_FILE
        RET_VAL=$?
      else
        echo "Could not find PID file $PID_FILE"
        RET_VAL=1
      fi
  ;;
    restart)
      if [[ -r $PID_FILE ]]
      then
        kill `cat $PID_FILE`
        rm $PID_FILE
        RET_VAL=$?
      else
        echo "Could not find PID file $PID_FILE"
      fi
      $PHP_SCRIPT
      RET_VAL=$?
  ;;
    status)
      if [[ -r $PID_FILE ]]
      then
        echo "php-fastcgi running with PID `cat $PID_FILE`"
        RET_VAL=$?
      else
        echo "Could not find PID file $PID_FILE, php-fastcgi does not appear to be running"
      fi
  ;;
    *)
      echo "Usage: php-fastcgi {start|stop|restart|status}"
      RET_VAL=1
  ;;
esac
exit $RET_VAL
 
Now setup php-fastcgi to run at boot time:
 
chmod +x /etc/init.d/php-fastcgi
update-rc.d php-fastcgi defaults
 
Finally start the service:
 
/etc/init.d/php-fastcgi start
 
To install Roundcube Mail:
 
cd /tmp
wget http://downloads.sourceforge.net/project/roundcubemail/roundcubemail/0.8.4/roundcubemail-0.8.4.tar.gz
tar xf roundcubemail-0.8.4.tar.gz
mkdir -p /var/www/mail.example.com/
cd roundcubemail-0.8.4
mv * /var/www/mail.example.com/
chown -R www-data:www-data /var/www/www.example.com/web
 
Now we need to setup the nginx vhost.  Edit /etc/nginx/nginx.conf and add this line in the http stanza:
 
include /etc/nginx/vhost.d/*.conf;
 
I also like to uncomment the gzip on line.
 
Now to create the vhost setup:
 
mkdir /etc/nginx/vhost.d
 
Create the a file /etc/nginx/vhost.d/mail.example.com.conf and add the following lines:
 
 
server {
    listen       443;
    ssl on;
    server_name  mail.example.com www.mail.example.com;
    ssl_certificate /etc/certs/mail.cert; 
    ssl_certificate_key /etc/certs/mail.key;

    #charset koi8-r;
    access_log  /var/log/nginx/mail.example.com.access.log;
    error_log /var/log/nginx/mail.example.com.error.log;

    location / {
        root   /var/www/mail.example.com/;
        index  index.html index.htm index.php;
    }

   # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
   #
    location ~ \.php$ {
        root           /var/www/mail.example.com;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /var/www/mail.example.com/$fastcgi_script_name;
        include        fastcgi_params;
    }

}

server {
    listen      80;
    server_name mail.example.com www.mail.example.com;
    rewrite     ^   https://$server_name$request_uri? permanent;

}
 
Restart nginx:
 
/etc/init.d/nginx restart
Now create a database for RoundCube Mail:
 
mysql -u root -p
create database roundcube;
grant all privileges on roundcube.* to 'roundcubeadmin'@localhost' identified by 'password';
grant all privileges on roundcube.* to 'roundcubeadmin'@localhost.localdomain' identified by 'password';
flush privileges;
 
Setup the database defaults:
 
cd /var/www/mail.example.com/SQL
mysql -u root -p roundcube < mysql.initial.sql
 
Now configure RoundCube Mail:
 
cd /var/www/wilson.buttonhost.net/config
cp db.inc.php.dist db.inc.php
cp main.inc.php.dist main.inc.php
 
Edit the db.inc.php file:
 
$rcmail_config['db_dsnw'] = 'mysql://roundcubeadmin:password@localhost/roundcube';
 
Edit the main.inc.php file:
 
$rcmail_config['default_host'] = 'localhost';
 
That\'s it.  You now have a mail server that will do a pretty solid job of spam and virus filtering.  If you\'re planning on using this in a high traffic situation you might need to purchase subscriptions to the various RBLs used by SpamAssassin or Postfix.