Difference between revisions of "Email server setup"

 
(17 intermediate revisions by the same user not shown)
Line 18: Line 18:
  
 
An "email server" is the sum of the following components:
 
An "email server" is the sum of the following components:
* SMTP server to
 
 
* Tools to check the email content against virus, spam
 
* Tools to check the email content against virus, spam
* Tools to encrypt the communication  
+
* SSL to encrypt the communication  
* Database to manage users and emails
+
* MySQL Database to manage users and emails
* (optional) WebMail such as Horde, RoundCube or SquirrelMail
+
* (optional) WebServer + WebMail such as Horde, RoundCube or SquirrelMail
  
  
Line 156: Line 155:
  
 
Create the following schema:
 
Create the following schema:
 +
 +
{| class="wikitable"
 +
!colspan="3"|domains
 +
|-
 +
|id
 +
|name
 +
|enabled
 +
|-
 +
|}
 +
 +
 +
{| class="wikitable"
 +
!colspan="6"|users
 +
|-
 +
|id
 +
|email
 +
|name
 +
|password
 +
|domain_id
 +
|enabled
 +
|-
 +
|}
 +
 +
 +
 +
{| class="wikitable"
 +
!colspan="5"|aliases
 +
|-
 +
|id
 +
|domain_id
 +
|source
 +
|destination
 +
|enabled
 +
|-
 +
|}
 +
  
 
<syntaxhighlight lang="sql">
 
<syntaxhighlight lang="sql">
Line 168: Line 203:
  
 
CREATE TABLE `users` (  
 
CREATE TABLE `users` (  
   `id` varchar(128) NOT NULL default '',  
+
   `id` int(11) NOT NULL auto_increment,  
 
   `email` varchar(120) NOT NULL,
 
   `email` varchar(120) NOT NULL,
 
   `name` varchar(120) NOT NULL default '',  
 
   `name` varchar(120) NOT NULL default '',  
Line 190: Line 225:
 
) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
 
) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
  
 +
</syntaxhighlight>
 +
 +
 +
 +
==Populate database==
 +
 +
Replace "daxiongmao.eu" by your own.
 +
 +
 +
'''Create domain(s)'''
 +
 +
{| class="wikitable"
 +
!colspan="3"|domains
 +
|-
 +
|id
 +
|name
 +
|enabled
 +
|-
 +
|1
 +
|daxiongmao.eu
 +
|1
 +
|-
 +
|}
 +
 +
<syntaxhighlight lang="sql">
 +
INSERT INTO `maildb`.`domains` (`name` ,`enabled`) VALUES ('daxiongmao.eu', '1');
 +
</syntaxhighlight>
 +
 +
 +
'''Create users'''
 +
 +
{| class="wikitable"
 +
!colspan="6"|users
 +
|-
 +
|id
 +
|email
 +
|name
 +
|password
 +
|domain_id
 +
|enabled
 +
|-
 +
|1
 +
|guillaume.diaz@daxiongmao.eu
 +
|Guillaume Diaz
 +
|myPassword
 +
|1
 +
|1
 +
|-
 +
|2
 +
|support@daxiongmao.eu
 +
|Support account
 +
|myPassword
 +
|1
 +
|1
 +
|-
 +
|3
 +
|noreply@daxiongmao.eu
 +
|NoReply account
 +
|myPassword
 +
|1
 +
|1
 +
|-
 +
|4
 +
|monitoring@daxiongmao.eu
 +
|Monitoring server
 +
|myPassword
 +
|1
 +
|1
 +
|-
 +
|5
 +
|mail@daxiongmao.eu
 +
|Email server
 +
|myPassword
 +
|1
 +
|1
 +
|-
 +
|}
 +
 +
You should create:
 +
* Yourself
 +
* A ''support'' user
 +
* A ''noReply'' account
 +
* 1 user per server (easy to manage)
 +
 +
Sometimes you might want a catch-all address (@daxiongmao.eu) = email account to will receive all the unknown or wrong address. That's risky since there are a LOT of spams bots and you might end up loading your server for nothing.
 +
 +
 +
<syntaxhighlight lang="sql">
 +
INSERT INTO `maildb`.`users` (`email` , `name` , `password` , `domain_id` , `enabled`)
 +
VALUES (
 +
'guillaume.diaz@daxiongmao.com', 'Guillaume Diaz', MD5( 'myPassword' ) , '1', '1'
 +
), (
 +
'support@daxiongmao.eu', 'Support account', MD5( 'myPassword' ) , '1', '1'
 +
), (
 +
'noreply@daxiongmao.eu', 'NoReply account', MD5( 'myPassword' ) , '1', '1'
 +
), (
 +
'monitoring@daxiongmao.eu', 'Monitoring server', MD5( 'myPassword' ) , '1', '1'
 +
), (
 +
'mail@daxiongmao.eu', 'Email server', MD5( 'myPassword' ) , '1', '1'
 +
);
 +
</syntaxhighlight>
 +
 +
 +
'''Create aliases'''
 +
 +
{| class="wikitable"
 +
!colspan="5"|aliases
 +
|-
 +
|id
 +
|domain_id
 +
|source
 +
|destination
 +
|enabled
 +
|-
 +
|1
 +
|1
 +
|guillaume.diaz@daxiongmao.eu
 +
|myAddress@gmail.com
 +
|1
 +
|-
 +
|1
 +
|1
 +
|support@daxiongmao.eu
 +
|guillaume.diaz@daxiongmao.eu
 +
|1
 +
|-
 +
|1
 +
|1
 +
|noreply@daxiongmao.eu
 +
|noreply@daxiongmao.eu
 +
|1
 +
|-
 +
|1
 +
|1
 +
|monitoring@daxiongmao.eu
 +
|monitoring@daxiongmao.eu
 +
|1
 +
|-
 +
|1
 +
|1
 +
|mail@daxiongmao.eu
 +
|mail@daxiongmao.eu
 +
|1
 +
|-
 +
|}
 +
 +
''Notes:''
 +
 +
* Support redirect to "guillaume"
 +
* Guillaume email actually redirect somewhere else in that example
 +
* Since 1 alias can redirect to many users (in case of vacations) you must provide the 1 to 1 association like "monitoring@daxiongmao.eu"
 +
 +
 +
<syntaxhighlight lang="sql">
 +
INSERT INTO `maildb`.`aliases` (`domain_id`, `source`, `destination`, `enabled`)
 +
VALUES (
 +
'1', 'guillaume.diaz@daxiongmao.eu', 'myAddress@gmail.com', '1'
 +
), (
 +
'1', 'support@daxiongmao.eu', 'guillaume.diaz@daxiongmao.eu', '1'
 +
), (
 +
'1', 'noreply@daxiongmao.eu', 'noreply@daxiongmao.eu', '1'
 +
), (
 +
'1', 'monitoring@daxiongmao.eu', 'monitoring@daxiongmao.eu', '1'
 +
), (
 +
'1', 'mail@daxiongmao.eu', 'mail@daxiongmao.eu', '1'
 +
);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 283: Line 484:
 
###########################
 
###########################
 
# how long to keep message on queue before return as failed
 
# how long to keep message on queue before return as failed
maximal_queue_lifetime = 1h
+
maximal_queue_lifetime = 1d
 
# max and min time in seconds between retries if connection failed
 
# max and min time in seconds between retries if connection failed
minimal_backoff_time = 5m
+
minimal_backoff_time = 10m
maximal_backoff_time = 10m
+
maximal_backoff_time = 50m
 
# how long to wait when servers connect before receiving rest of data
 
# how long to wait when servers connect before receiving rest of data
 
smtp_helo_timeout = 60s
 
smtp_helo_timeout = 60s
Line 349: Line 550:
 
virtual_uid_maps = static:5000
 
virtual_uid_maps = static:5000
 
virtual_gid_maps = static:5000
 
virtual_gid_maps = static:5000
 
## TLS parameters
 
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
 
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
 
smtpd_use_tls=yes
 
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
 
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
 
  
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 467: Line 661:
  
 
The "/var/log/mail.err" must be empty
 
The "/var/log/mail.err" must be empty
 +
 +
 +
>> If you have some error due to ''"Dovecot" service not found'' then you can comment these lines:
 +
# virtual_transport=dovecot
 +
# dovecot_destination_recipient_limit=1
 +
  
  
Line 622: Line 822:
 
     group = postfix
 
     group = postfix
 
}
 
}
 +
</syntaxhighlight>
 +
 +
 +
===Logging configuration===
 +
 +
<syntaxhighlight lang="bash">
 +
vim /etc/dovecot/conf.d/10-logging.conf
 +
</syntaxhighlight>
 +
 +
 +
set log_path:
 +
 +
<syntaxhighlight lang="bash">
 +
log_path = /var/log/mail.log
 +
</syntaxhighlight>
 +
 +
 +
Adjust file rights:
 +
 +
<syntaxhighlight lang="bash">
 +
chmod 777 /var/log/mail.log
 +
chmod 777 /var/log/mail.err
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 720: Line 942:
 
* TCP 995 = POP3s
 
* TCP 995 = POP3s
  
 +
+ TCP 4190 = SIEVE dynamic rules for email redirection and filtering
 +
 +
 +
=POSTFIX <> DOVECOT=
 +
 +
==Service binding==
 +
 +
<syntaxhighlight lang="bash">
 +
vim /etc/postfix/master.cf
 +
</syntaxhighlight>
  
  
 +
Adjust and add (~ in the middle of the file, line 80):
  
=RoundCube WebMail=
+
<syntaxhighlight lang="bash">
 +
# service type  private unpriv  chroot  wakeup  maxproc command + args
 +
#              (yes)  (yes)  (yes)  (never) (100)
 +
# ==========================================================================
 +
maildrop  unix  -      n      n      -      -      pipe
 +
  flags=DRhu user=virtualMail argv=/usr/bin/maildrop -d ${recipient}
 +
# DOVECOT integration
 +
dovecot  unix  -      n      n      -      -      pipe
 +
  flags=DRhu user=virtualMail:virtualMail argv=/usr/lib/dovecot/dovecot-lda -f ${sender} -d ${recipient}
 +
</syntaxhighlight>
 +
 
 +
* Adjust ''user''
 +
 
 +
 
 +
 
 +
==Postfix configuration==
 +
 
 +
You need to declare POSTFIX as Virtual transport + Security provider
 +
 
 +
<syntaxhighlight lang="bash">
 +
vim /etc/postfix/main.cf
 +
</syntaxhighlight>
 +
 
 +
Add the following lines:
 +
 
 +
<syntaxhighlight lang="bash">
 +
## Virtual transport
 +
virtual_transport=dovecot
 +
dovecot_destination_recipient_limit=1
 +
 
 +
###########################
 +
#  Security: Secure SMTP  #
 +
###########################
 +
## Security provider
 +
smtpd_sasl_type=dovecot
 +
smtpd_sasl_path=private/auth
 +
smtpd_sasl_auth_enable=yes
 +
## SSL settings
 +
smtpd_use_tls=yes
 +
smtpd_tls_cert_file=/etc/ssl/certs/mail.daxiongmao.eu.cert.pem
 +
smtpd_tls_key_file=/etc/ssl/private/mail.daxiongmao.eu.nopass.key
 +
 
 +
## "may" is required since some SMTP servers can ask for non-secure connection
 +
smtpd_tls_security_level=may
 +
## The current server will redirect all connection to TLS
 +
smtpd_tls_auth_only=yes
 +
 
 +
## TLS parameters
 +
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
 +
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
 +
 
 +
</syntaxhighlight>
 +
 
 +
 
 +
* Replace "mail.daxiongmao.eu" by your own {key, certificate}.
 +
* You should NOT use an encrypted private key here
 +
 
 +
 
 +
 
 +
 
 +
==Restart postfix==
 +
 
 +
<syntaxhighlight lang="bash">
 +
service postfix restart
 +
</syntaxhighlight>
  
There are many webmail clients available: horde, squirrelMail, roundCube, etc.
 
  
  
==Installation==
+
=Local test=
  
 +
Test to send yourself an email from the email server:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
apt-get install roundcube roundcube-plugins
+
echo "Test" | mail -s "guillaume.diaz@daxiongmao.eu"
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
Check the log: "/var/log/mail.log"
 +
 +
Check for file creation in: "/var/vmail"
  
Reply to the following questions:
 
* Use dbconfig-common? '''YES'''
 
* Database type? '''mysql'''
 
* Database's administrative user's password? '''root password'''
 
* Application's password? '''new password'''
 
  
  
  
==Security==
 
  
==Apache2 Virtual host==
+
=Apache2 Virtual host=
  
  
Line 761: Line 1,055:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
 +
<VirtualHost *:80>
 +
ServerName mail.daxiongmao.eu
 +
ServerAdmin guillaume.diaz@mail.daxiongmao.eu
 +
 +
# Logs settings
 +
LogLevel error
 +
ErrorLog ${APACHE_LOG_DIR}/error.log
 +
CustomLog ${APACHE_LOG_DIR}/access.log combined
 +
 +
## Redirect all traffic to HTTPS website
 +
        RewriteEngine On
 +
        RewriteCond %{HTTPS} off       
 +
        RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
 +
redirect permanent / https://mail.daxiongmao.eu/
 +
</VirtualHost>
 +
 +
<VirtualHost *:443>
 +
ServerName mail.daxiongmao.eu
 +
#ServerAlias mail.daxiongmao.eu
 +
ServerAdmin guillaume.diaz@mail.daxiongmao.eu
 +
 +
# Logs settings
 +
LogLevel error
 +
ErrorLog ${APACHE_LOG_DIR}/error.log
 +
CustomLog ${APACHE_LOG_DIR}/access.log combined
 +
 +
        # Enable SSL
 +
        SSLEngine              On
 +
        SSLCertificateFile      /etc/apache2/webServer.pem
 +
        SSLCertificateKeyFile  /etc/apache2/webServer.key
 +
 +
        # SECURITY: forbid access to .htaccess so no outsider can ever change it
 +
        <Files ~ "^\.ht">
 +
            Order allow,deny
 +
            Deny from all
 +
        </Files>
 +
 +
        # Restrict access to server root
 +
DocumentRoot /var/www/
 +
        <Directory />
 +
                Options FollowSymLinks
 +
                AllowOverride None
 +
require local
 +
        </Directory>
 +
 +
        # Virtual host root directory
 +
<Directory /var/www/>
 +
Options Indexes FollowSymLinks MultiViews
 +
AllowOverride None
 +
require local
 +
# LAN and VPN
 +
require ip 172.16.50
 +
require ip 172.16.60
 +
</Directory>
 +
</VirtualHost>
 +
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 782: Line 1,132:
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
 
a2enmod ssl rewrite
 
a2enmod ssl rewrite
 +
php5enmod mcrypt
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 795: Line 1,146:
  
  
 +
 +
 +
 +
=RoundCube WebMail=
 +
 +
There are many webmail clients available: horde, squirrelMail, roundCube, etc.
 +
 +
 +
==Requirements==
 +
 +
Roundcube need Apache2 mod_rewrite, mod_ssl + PHP5 mcrypt.
 +
 +
<syntaxhighlight lang="bash">
 +
a2enmod ssl rewrite
 +
php5enmod mcrypt
 +
</syntaxhighlight>
 +
 +
 +
 +
==Installation==
 +
 +
 +
<syntaxhighlight lang="bash">
 +
apt-get install roundcube roundcube-plugins
 +
</syntaxhighlight>
 +
 +
 +
Reply to the following questions:
 +
* Use dbconfig-common? '''YES'''
 +
* Database type? '''mysql'''
 +
* Database's administrative user's password? '''root password'''
 +
* Application's password? '''new password'''
 +
 +
 +
==VHost Configuration==
 +
 +
 +
<syntaxhighlight lang="bash">
 +
vim /etc/roundcube/apache.conf
 +
</syntaxhighlight>
 +
 +
 +
Enable both alias at the beginning. You can also add ''Satisfy any'' to ''Require all granted'':
 +
 +
<syntaxhighlight lang="bash">
 +
Alias /roundcube/program/js/tiny_mce/ /usr/share/tinymce/www/
 +
Alias /roundcube /var/lib/roundcube
 +
 +
[...]
 +
 +
<IfVersion >= 2.3>
 +
  Require all granted4190;
 +
  Satisfy any
 +
</IfVersion>
 +
<IfVersion < 2.3>
 +
    Order allow,deny
 +
    Allow from all
 +
</IfVersion>
 +
 +
[...]
 +
</syntaxhighlight>
 +
 +
 +
If you'd like you can also setup some r4190;estriction instead of ''Require all granted''.
 +
See [[Apache 2]].
 +
 +
 +
==Database configuration==
 +
 +
Check db configuration file:
 +
 +
<syntaxhighlight lang="bash">
 +
vim /etc/roundcube/debian-db.php
 +
</syntaxhighlight>
 +
 +
You should see:
 +
 +
<syntaxhighlight lang="php">
 +
$dbuser='roundcube';
 +
$dbpass='myPassword';
 +
$basepath='';
 +
$dbname='roundcube';
 +
$dbserver='localhost';
 +
$dbport='1433';
 +
$dbtype='mysql';
 +
</syntaxhighlight>
 +
                   
 +
 +
==Enable dynamic rules (SIEVE)==
 +
 +
Copy file
 +
 +
<syntaxhighlight lang="bash">
 +
cp /usr/share/roundcube/plugins/managesieve/config.inc.php.dist /etc/roundcube/plugins/managesieve/config.inc.php
 +
</syntaxhighlight>
 +
 +
 +
Edit file
 +
 +
<syntaxhighlight lang="bash">
 +
vim /etc/roundcube/plugins/managesieve/config.inc.php
 +
</syntaxhighlight>
 +
 +
 +
Set
 +
 +
<syntaxhighlight lang="bash">
 +
$rcmail_config['managesieve_port'] = 4190;
 +
</syntaxhighlight>
 +
 +
 +
 +
==Roundcube configuration==
 +
 +
Edit configuration file
 +
 +
<syntaxhighlight lang="bash">
 +
vim /etc/roundcube/main.inc.php
 +
</syntaxhighlight>
 +
 +
 +
<syntaxhighlight lang="php">
 +
// ~ Line 78
 +
$rcmail_config['default_host'] = 'localhost';
 +
 +
// ~ Line 220
 +
$rcmail_config['force_https'] = true;
 +
 +
 +
// ~ Line 414
 +
// List of active plugins (in plugins/ directory)
 +
$rcmail_config['plugins'] = array('managesieve');
 +
 +
</syntaxhighlight>
 +
 +
 +
 +
 +
==Take on changes and test==
 +
 +
<syntaxhighlight lang="bash">
 +
service apache2 restart
 +
</syntaxhighlight>
 +
 +
 +
Test your webmail: https://mail.daxiongmao.eu/roundcube
 +
 +
 +
 +
 +
=SPAM filter=
 +
 +
<syntaxhighlight lang="bash">
 +
## Anti-virus
 +
apt-get install clamav-base libclamav6 clamav-daemon clamav-freshclam
 +
 +
## SPAM killer
 +
apt-get install amavisd-new spamassassin spamc
 +
</syntaxhighlight>
 +
 +
 +
Then see https://workaround.org/ispmail/wheezy/malware-scanning-amavisd
  
  
Line 809: Line 1,322:
 
# Authentication using MySQL
 
# Authentication using MySQL
 
apt-get install libpam-mysql
 
apt-get install libpam-mysql
 
## Anti-virus
 
apt-get install clamav-base libclamav6 clamav-daemon clamav-freshclam
 
 
## SPAM killer
 
apt-get install  spamassassin spamc
 
  
 
## Interface to scan emails for virus & spam
 
## Interface to scan emails for virus & spam

Latest revision as of 16:21, 12 August 2014


Authors

All that follow is the sum of different how-to. I've based my research on Christoph Haas' how-to and FLURDY therefore a lot of commands are similar.


I'm not an expert of mail server, therefore most of the following content is not mine. I've just aggregate data to make it easier to work with. Please check out the #Sources if you want to know more.


This content is provided under the same license as my sources: GNU General Public License.



Requirements

An "email server" is the sum of the following components:

  • Tools to check the email content against virus, spam
  • SSL to encrypt the communication
  • MySQL Database to manage users and emails
  • (optional) WebServer + WebMail such as Horde, RoundCube or SquirrelMail


Server dependencies

Before starting you need to have:


Create Linux mail user

We need a dedicated to receive all emails and run an IMAP / POP3 server such as Devecot or Courier.

The delivery will be done by the IMAP / POP3 server using MySQL virtual domains & users.

# Server root folder, where all the mails will be stored
mkdir -p /var/spool/mail/virtualMail 

# New user
groupadd --system virtualMail -g 5000
useradd --system virtualMail -u 5000 -g 5000 -d /var/vmail -m
chown -R virtualMail:virtualMail /var/vmail
chmod u+w /var/vmail


  • It's a common good practice to create a dedicated user to send email. That's the user POSTFIX will use. As usual in Linux, that user should be UID > 1000 so it has more restrictions.
  • All the emails will be saved into "/var/vmail/"


Create mail server certificate

Since nothing is secure we'll use SSL to encrypt communications. Therefore, we need to create a server certificate.


!! Important !!

If your server is the same as your web-server then you've already created some certificates in the Apache2 section. So you don't need to create a new one.


2 options:

  1. Create a new server certificate using an external Authority of Certification (your own or a 3rd party)
  2. Create a self-signed certificate... Use that option only if there is no other choice...


Create server key and certificate request

Create the private key

cd /etc/ssl
# Encrypted private key
openssl genrsa -aes256 -out private/mail.daxiongmao.eu.key -rand ./ 4096
# Decipher it for Apache2 (will be used by the webmail)
openssl rsa -in private/mail.daxiongmao.eu.key -out private/mail.daxiongmao.eu.nopass.key


Generate server certificate's request

openssl req -config openssl.cnf -new -nodes -key private/mail.daxiongmao.eu.key -out certs/mail.daxiongmao.eu.req

!! Country, state and locality must match your AC !!

  • Country Name (2 letter code) [AU]: SE
  • State or Province Name (full name) [Some-State]:Vastra Goteland
  • Locality Name (eg, city) []:Goteborg
  • Organization Name (eg, company) [Internet Widgits Pty Ltd]:Daxiongmao.eu
  • Common Name (e.g. server FQDN or YOUR name) []:mail.daxiongmao.eu


Sign server certificate using your own AC

See SSL server#Server certificate for more details.


Send the .req file to the AC server, into /srv/ssl/certs/ then run:

cd /srv/ssl
openssl ca -config openssl.cnf \
-in certs/mail.daxiongmao.eu.req \
-out certs/mail.daxiongmao.eu.cert.pem \
-cert cacerts.pem \
-days 3600


Deploy server certificate

Copy the new certificate "mail.daxiongmao.cert.pem" to the mail server in "/etc/ssl/certs/"




MySQL database

Create and initialize a new database and user for email.


Create database

I assume that:

  • Database name: maildb
  • Db user: maildb


# log in as root 
mysql -u root -p 

# Create the mail database 
create database maildb; 

# Create a new user and grant rights upon mail database
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ON maildb.* TO 'maildb'@'localhost' IDENTIFIED by 'mailDbPASSWORD'; 
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ON maildb.* TO 'maildb'@'%' IDENTIFIED by 'mailDbPASSWORD'; 
exit;


Schema

Create the following schema:

domains
id name enabled


users
id email name password domain_id enabled


aliases
id domain_id source destination enabled


CREATE TABLE `domains` ( 
   `id` smallint(6) NOT NULL auto_increment, 
   `name` varchar(120) NOT NULL default '', 
   `enabled` tinyint(1) NOT NULL default '1', 
   PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `users` ( 
   `id` int(11) NOT NULL auto_increment, 
   `email` varchar(120) NOT NULL,
   `name` varchar(120) NOT NULL default '', 
   `password` varchar(32) NOT NULL,
   `domain_id`smallint(6) NOT NULL,
   `enabled` tinyint(3) unsigned NOT NULL default '1', 
   PRIMARY KEY (`id`),
   UNIQUE KEY `email` (`email`),
   FOREIGN KEY (domain_id) REFERENCES domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `aliases` ( 
    `id` smallint(3) NOT NULL auto_increment, 
    `domain_id` smallint(6) NOT NULL, 
    `source` varchar(120) NOT NULL default '', 
    `destination` varchar(100) NOT NULL,
    `enabled` tinyint(1) NOT NULL default '1', 
    PRIMARY KEY (`id`), 
    FOREIGN KEY (domain_id) REFERENCES domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


Populate database

Replace "daxiongmao.eu" by your own.


Create domain(s)

domains
id name enabled
1 daxiongmao.eu 1
INSERT INTO `maildb`.`domains` (`name` ,`enabled`) VALUES ('daxiongmao.eu', '1');


Create users

users
id email name password domain_id enabled
1 guillaume.diaz@daxiongmao.eu Guillaume Diaz myPassword 1 1
2 support@daxiongmao.eu Support account myPassword 1 1
3 noreply@daxiongmao.eu NoReply account myPassword 1 1
4 monitoring@daxiongmao.eu Monitoring server myPassword 1 1
5 mail@daxiongmao.eu Email server myPassword 1 1

You should create:

  • Yourself
  • A support user
  • A noReply account
  • 1 user per server (easy to manage)

Sometimes you might want a catch-all address (@daxiongmao.eu) = email account to will receive all the unknown or wrong address. That's risky since there are a LOT of spams bots and you might end up loading your server for nothing.


INSERT INTO `maildb`.`users` (`email` , `name` , `password` , `domain_id` , `enabled`)
VALUES (
'guillaume.diaz@daxiongmao.com', 'Guillaume Diaz', MD5( 'myPassword' ) , '1', '1'
), (
'support@daxiongmao.eu', 'Support account', MD5( 'myPassword' ) , '1', '1'
), (
'noreply@daxiongmao.eu', 'NoReply account', MD5( 'myPassword' ) , '1', '1'
), (
'monitoring@daxiongmao.eu', 'Monitoring server', MD5( 'myPassword' ) , '1', '1'
), (
'mail@daxiongmao.eu', 'Email server', MD5( 'myPassword' ) , '1', '1'
);


Create aliases

aliases
id domain_id source destination enabled
1 1 guillaume.diaz@daxiongmao.eu myAddress@gmail.com 1
1 1 support@daxiongmao.eu guillaume.diaz@daxiongmao.eu 1
1 1 noreply@daxiongmao.eu noreply@daxiongmao.eu 1
1 1 monitoring@daxiongmao.eu monitoring@daxiongmao.eu 1
1 1 mail@daxiongmao.eu mail@daxiongmao.eu 1

Notes:

  • Support redirect to "guillaume"
  • Guillaume email actually redirect somewhere else in that example
  • Since 1 alias can redirect to many users (in case of vacations) you must provide the 1 to 1 association like "monitoring@daxiongmao.eu"


INSERT INTO `maildb`.`aliases` (`domain_id`, `source`, `destination`, `enabled`) 
VALUES (
'1', 'guillaume.diaz@daxiongmao.eu', 'myAddress@gmail.com', '1'
), (
'1', 'support@daxiongmao.eu', 'guillaume.diaz@daxiongmao.eu', '1'
), (
'1', 'noreply@daxiongmao.eu', 'noreply@daxiongmao.eu', '1'
), (
'1', 'monitoring@daxiongmao.eu', 'monitoring@daxiongmao.eu', '1'
), (
'1', 'mail@daxiongmao.eu', 'mail@daxiongmao.eu', '1'
);



POSTFIX

POSTFIX is a SMTP server that is used to send/receive emails.


Installation

POSTFIX SMTP server:

apt-get install postfix postfix-mysql 

mkdir -p /var/spool/mail/virtual


Basic configuration

vim /etc/postfix/main.cf


Put the following configuration:


##########################
#      MISC settings     #
##########################
# Server name
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no
# appending .domain is the MUA's job.
append_dot_mydomain = no
# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# Use external SMTP relay?
relayhost = 
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination

# Bind interfaces
inet_interfaces = all
# Restrict to IPv4 (= avoid IPv6 errors and log spam)
inet_protocols=ipv4


###########################
#  Email global settings  #
###########################
# Email server name
myhostname = mail.daxiongmao.eu
# Domain name for emails originated from this server
#myorigin = /etc/mailname
myorigin = daxiongmao.eu
# Local destination (= email server local alias)
mydestination = mail.daxiongmao.eu, localhost.daxiongmao.eu, , localhost
# Trusted senders (localhost + LAN + VPN)
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 172.16.50.0/24 172.16.60.0/24


##############################
#          Commands          #
##############################
mailbox_command = procmail -a "$EXTENSION"


###################################
#  Email accounts / msg settings  #
###################################
# Max mailbox size
mailbox_size_limit = 0
# Max number of mailboxes 
virtual_mailbox_limit = 0
# Max message size
message_size_limit = 0
# Misc settings
recipient_delimiter = +


###########################
#   Connection settings   #
###########################
# how long to keep message on queue before return as failed
maximal_queue_lifetime = 1d
# max and min time in seconds between retries if connection failed
minimal_backoff_time = 10m
maximal_backoff_time = 50m
# how long to wait when servers connect before receiving rest of data
smtp_helo_timeout = 60s
# how many address can be used in one message.
# effective stopper to mass spammers, accidental copy in whole address list but may restrict intentional mail shots.
smtpd_recipient_limit = 16
# how many error before back off.
smtpd_soft_error_limit = 3
# how many max errors before blocking it.
smtpd_hard_error_limit = 12


####################################
#  Security: protocol enforcement  #
####################################
# Requirements for the HELO statement
smtpd_helo_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_hostname, reject_invalid_hostname, permit

# Requirements for the sender details
smtpd_sender_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unauth_pipelining, permit

# Requirements for the connecting server 
smtpd_client_restrictions = reject_rbl_client sbl.spamhaus.org, reject_rbl_client blackholes.easynet.nl

# Requirement for the recipient address
smtpd_recipient_restrictions = reject_unauth_pipelining, permit_mynetworks, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, permit
smtpd_data_restrictions = reject_unauth_pipelining


# require proper helo at connections 
smtpd_helo_required = yes

# waste spammers time before rejecting them
smtpd_delay_reject = yes
disable_vrfy_command = yes


############################
#      Email accounts      #
############################
# Alias definitions
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
# Location of the virtual mailbox folder (= Global server mailbox)
# ... This must match the folder you created in [[#Create Linux mail user]]
virtual_mailbox_base = /var/vmail

## MySQL settings
# Domain lookups
virtual_mailbox_domains = mysql:/etc/postfix/mysql_domains.cf
# List of available mailboxes
virtual_mailbox_maps = mysql:/etc/postfix/mysql_mailboxes.cf
# List of virtual mailboxes
virtual_alias_maps = mysql:/etc/postfix/mysql_aliases.cf,mysql:/etc/postfix/mysql_mailboxes.cf


############################
#         Security         #
############################
## Mail user / group
# Good practice: you should create a dedicated Linux user to send mails. That one is called "virtualMail"
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000

Don't forget to adjust:

  • Email global settings
    • myhostname
    • myorigin mailserver
    • mydestination
    • mynetworks


MySQL domain config

How to find the domains.

vim /etc/postfix/mysql_domains.cf


Put the following content, replace mailDbPASSWORD by your own database password:

user = maildb
password = mailPASSWORD 
hosts = 127.0.0.1
dbname = maildb 
query = SELECT name FROM domains WHERE name='%s' AND enabled = 1


Notes:

  • Do not use "localhost" instead of "127.0.0.1". Since Postfix and MySQL are chroot in different places Postfix must use network (127.0.0.1) communication instead of file (localhost).
  • The '%s' will be replace dynamically on runtime by the requested domain


MySQL mailbox config

How to select a mailbox from MySQL.

vim /etc/postfix/mysql_mailboxes.cf


Put the following content, replace mailDbPASSWORD by your own database password:

user = maildb
password = mailDbPASSWORD
dbname = maildb 
hosts = 127.0.0.1
query = SELECT email FROM users WHERE email = '%s' AND enabled = 1


MySQL alias config

How to find the email alias from MySQL

vim /etc/postfix/mysql_aliases.cf


Put the following content, replace mailDbPASSWORD by your own database password:

user = maildb 
password = mailDbPASSWORD
dbname = maildb 
hosts = 127.0.0.1
query = SELECT destination FROM aliases WHERE source='%s' AND enabled = 1




Trick:

In case of catch-all addresses such as @dev.daxiongmao.eu (to get everything) you need another file to allow (bob@dev.daxiongmao.eu).

In that case the Postfix "virtual_alias_map" will use 2 scripts.


Set rights

chgrp postfix /etc/postfix/mysql*.cf
​chmod u=rw,g=r,o= /etc/postfix/mysql*.cf


Basic test

echo "" > /var/log/mail.log
echo "" > /var/log/mail.err
service postfix restart
cat /var/log/mail.log


You should see something like in "/var/log/mail.log" : daemon started -- version 2.11.0, configuration /etc/postfix

The "/var/log/mail.err" must be empty


>> If you have some error due to "Dovecot" service not found then you can comment these lines:

  1. virtual_transport=dovecot
  2. dovecot_destination_recipient_limit=1


Check the process and network port

ps aux | grep postfix
netstat -pl | grep smtp
netstat -pl --numeric | grep 0.0.0.0:25
  • TCP 25 SMTP
  • TCP 465 SMTPs
  • TCP 587 SMTP



DOVECOT

Dovecot is an IMAP / POP3 server used to manage and deliver emails.


In our case:

  • All the emails files will be owned by the "local user" VirtualMail [= linux user]
  • Emails will be delivered to the "virtual domains & users" using MySQL database


Installation

apt-get install dovecot-mysql dovecot-pop3d dovecot-imapd dovecot-managesieved


Configuration

All the configuration is available in "/etc/dovecot/conf.d".


Authentication

Overall behavior

Enable MySQL + Microsoft Outlook support.

vim /etc/dovecot/conf.d/10-auth.conf


Edit the configuration:

  • Add "login" authentication mechanism to support MS Outlook
  • At the end of the file, comment "auth-system" in favor of "auth-sql"
auth_mechanisms = plain login

[...]

#!include auth-system.conf.ext
!include auth-sql.conf.ext


Configure email mailbox folder

vim /etc/dovecot/conf.d/auth-sql.conf.ext


Comment out all "userdb" section in favor of the following:

userdb {
  driver = static
  args = uid=virtualMail gid=virtualMail home=/var/vmail/%d/%n
}

!! Important, they can only be 1 "userdb" section


Configure DB access

Now you need to configure how Devecot will access the database:

vim /etc/dovecot/dovecot-sql.conf.ext

-- Actually this file should already exists, you just have to complete it!


Put the following (adjust to your own settings and replace MailDbPassword):

driver = mysql
connect = host=127.0.0.1 dbname=maildb user=maildb password=MailDbPassword
default_pass_scheme = PLAIN-MD5
password_query = SELECT email AS user, password FROM users WHERE email = '%u' AND enabled = 1;

Reminder:

  •  %u = entire user@domain
  •  %n = user part of user@domain
  •  %d = domain part of user@domain

In that case we're gonna use the complete email address as login.


Adjust rights

chown root:root /etc/dovecot/dovecot-sql.conf.ext
chmod go= /etc/dovecot/dovecot-sql.conf.ext


Mail location

vim /etc/dovecot/conf.d/10-mail


Adjust the mailbox_location:

mail_location = maildir:/var/vmail/%d/%n/Maildir


Network and service security (ports and rights)

vim /etc/dovecot/conf.d/10-master.conf

Check your configuration For Postfix to allow Dovecot as an authentication service you must uncomment and adjust:

# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
}


Logging configuration

vim /etc/dovecot/conf.d/10-logging.conf


set log_path:

log_path = /var/log/mail.log


Adjust file rights:

chmod 777 /var/log/mail.log
chmod 777 /var/log/mail.err


SSL configuration

vim /etc/dovecot/conf.d/10-ssl.conf


Earlier you created both a key and a certificate file to encrypt the communication. You need to use it:

ssl_cert = </etc/ssl/certs/mail.daxiongmao.eu.cert.pem
ssl_key = </etc/ssl/private/mail.daxiongmao.eu.key
ssl_key_password = </etc/dovecot/ssl_cert_pwd.cf


Create the password file (only root can access it, on service's startup):

touch /etc/dovecot/ssl_cert_pwd.cf
echo "myKeyPassword" > /etc/dovecot/ssl_cert_pwd.cf
chmod 0600 /etc/dovecot/ssl_cert_pwd.cf
chown root:root /etc/dovecot/ssl_cert_pwd.cf


Enable emails rules

To enable emails rules you need to use the "SIEVE" plugin.

vim /etc/dovecot/conf.d/15-lda.conf


protocol lda {
  # Space separated list of plugins to load (default is global mail_plugins).
  mail_plugins = $mail_pluginCheck your configurations sieve
}


Adjust Dovecot owner and rights

chgrp virtualMail /etc/dovecot/dovecot.conf
chmod g+r /etc/dovecot/dovecot.conf


Check your configuration

You can check your configuration by doing:

doveconf -n

If there is no typo error then the configuration should appear on your screen.


Test the server

Basic test

echo "" > /var/log/mail.log
echo "" > /var/log/mail.err
service dovecot restart
cat /var/log/mail.log


You should see something like in "/var/log/mail.log" : Info: Dovecot v2.2.9 starting up (core dumps disabled)

The "/var/log/mail.err" must be empty


Check the process and network port

ps aux | grep dovecot
netstat -pl | grep pop
netstat -pl | grep imap
netstat -pl --numeric | grep 0.0.0.0:110
  • TCP 110 = POP3
  • TCP 143 = IMAP
  • TCP 993 = IMAPs
  • TCP 995 = POP3s

+ TCP 4190 = SIEVE dynamic rules for email redirection and filtering


POSTFIX <> DOVECOT

Service binding

vim /etc/postfix/master.cf


Adjust and add (~ in the middle of the file, line 80):

# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
maildrop  unix  -       n       n       -       -       pipe
  flags=DRhu user=virtualMail argv=/usr/bin/maildrop -d ${recipient}
# DOVECOT integration
dovecot   unix  -       n       n       -       -       pipe
  flags=DRhu user=virtualMail:virtualMail argv=/usr/lib/dovecot/dovecot-lda -f ${sender} -d ${recipient}
  • Adjust user


Postfix configuration

You need to declare POSTFIX as Virtual transport + Security provider

vim /etc/postfix/main.cf

Add the following lines:

## Virtual transport
virtual_transport=dovecot
dovecot_destination_recipient_limit=1

###########################
#  Security: Secure SMTP  #
###########################
## Security provider
smtpd_sasl_type=dovecot
smtpd_sasl_path=private/auth
smtpd_sasl_auth_enable=yes
## SSL settings
smtpd_use_tls=yes
smtpd_tls_cert_file=/etc/ssl/certs/mail.daxiongmao.eu.cert.pem
smtpd_tls_key_file=/etc/ssl/private/mail.daxiongmao.eu.nopass.key

## "may" is required since some SMTP servers can ask for non-secure connection
smtpd_tls_security_level=may
## The current server will redirect all connection to TLS
smtpd_tls_auth_only=yes

## TLS parameters
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache


  • Replace "mail.daxiongmao.eu" by your own {key, certificate}.
  • You should NOT use an encrypted private key here



Restart postfix

service postfix restart


Local test

Test to send yourself an email from the email server:

echo "Test" | mail -s "guillaume.diaz@daxiongmao.eu"

Check the log: "/var/log/mail.log"

Check for file creation in: "/var/vmail"



Apache2 Virtual host

Create a new VHost

Create a new vHost:

vim /etc/apache2/sites-available/mail.daxiongmao.eu.conf


Put the following content:

<VirtualHost *:80>
	ServerName mail.daxiongmao.eu
	ServerAdmin guillaume.diaz@mail.daxiongmao.eu

	# Logs settings
	LogLevel error
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

	## Redirect all traffic to HTTPS website
        RewriteEngine On
        RewriteCond %{HTTPS} off        
        RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} 
	redirect permanent / https://mail.daxiongmao.eu/
</VirtualHost>

<VirtualHost *:443>
	ServerName mail.daxiongmao.eu
	#ServerAlias mail.daxiongmao.eu
	ServerAdmin guillaume.diaz@mail.daxiongmao.eu
	
	# Logs settings
	LogLevel error
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

        # Enable SSL
        SSLEngine               	On
        SSLCertificateFile      	/etc/apache2/webServer.pem
        SSLCertificateKeyFile   	/etc/apache2/webServer.key

        # SECURITY: forbid access to .htaccess so no outsider can ever change it
        <Files ~ "^\.ht">
            Order allow,deny
            Deny from all
        </Files>

        # Restrict access to server root
	DocumentRoot	/var/www/
        <Directory />
                Options FollowSymLinks
                AllowOverride None
		require local	
        </Directory>

        # Virtual host root directory
	<Directory /var/www/>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride None
		require local
		# LAN and VPN
		require ip 172.16.50
		require ip 172.16.60
	</Directory>
</VirtualHost>


Disable the default VHOST

a2dissite 000-default


Enable the new VHOST

a2ensite mail.daxiongmao.eu


Enable Apache2 modules

a2enmod ssl rewrite
php5enmod mcrypt


Restart and test

service apache2 restart


Go to: https://mail.daxiongmao.eu



RoundCube WebMail

There are many webmail clients available: horde, squirrelMail, roundCube, etc.


Requirements

Roundcube need Apache2 mod_rewrite, mod_ssl + PHP5 mcrypt.

a2enmod ssl rewrite
php5enmod mcrypt


Installation

apt-get install roundcube roundcube-plugins


Reply to the following questions:

  • Use dbconfig-common? YES
  • Database type? mysql
  • Database's administrative user's password? root password
  • Application's password? new password


VHost Configuration

vim /etc/roundcube/apache.conf


Enable both alias at the beginning. You can also add Satisfy any to Require all granted:

Alias /roundcube/program/js/tiny_mce/ /usr/share/tinymce/www/
Alias /roundcube /var/lib/roundcube

[...] 

<IfVersion >= 2.3>
   Require all granted4190;
   Satisfy any
</IfVersion>
<IfVersion < 2.3>
    Order allow,deny
    Allow from all
</IfVersion>

[...]


If you'd like you can also setup some r4190;estriction instead of Require all granted. See Apache 2.


Database configuration

Check db configuration file:

vim /etc/roundcube/debian-db.php

You should see:

$dbuser='roundcube';
$dbpass='myPassword';
$basepath='';
$dbname='roundcube';
$dbserver='localhost';
$dbport='1433';
$dbtype='mysql';


Enable dynamic rules (SIEVE)

Copy file

cp /usr/share/roundcube/plugins/managesieve/config.inc.php.dist /etc/roundcube/plugins/managesieve/config.inc.php


Edit file

vim /etc/roundcube/plugins/managesieve/config.inc.php


Set

$rcmail_config['managesieve_port'] = 4190;


Roundcube configuration

Edit configuration file

vim /etc/roundcube/main.inc.php


// ~ Line 78
$rcmail_config['default_host'] = 'localhost';

// ~ Line 220
$rcmail_config['force_https'] = true;


// ~ Line 414
// List of active plugins (in plugins/ directory)
$rcmail_config['plugins'] = array('managesieve');



Take on changes and test

service apache2 restart


Test your webmail: https://mail.daxiongmao.eu/roundcube



SPAM filter

## Anti-virus
apt-get install clamav-base libclamav6 clamav-daemon clamav-freshclam

## SPAM killer
apt-get install amavisd-new spamassassin spamc


Then see https://workaround.org/ispmail/wheezy/malware-scanning-amavisd


Other

## Security libraries
# SASL is the Simple Authentication and Security Layer, a method for adding authentication support to connection-based protocols.
apt-get install libsasl2-modules libsasl2-modules-sql libgsasl7 libauthen-sasl-cyrus-perl sasl2-bin

# Authentication using MySQL
apt-get install libpam-mysql

## Interface to scan emails for virus & spam
apt-get install amavisd-new

## Utility to SEND emails
apt-get install postfix postfix-mysql 

## Utility to RECEIVE emails
apt-get install courier-base courier-authdaemon courier-authlib-mysql courier-imap courier-imap-ssl courier-pop courier-pop-ssl courier-ssl



Sources

Fabulous guide from Christoph Haas: https://workaround.org/ispmail/wheezy .This also explain each step in detail: WHY and HOW do to it.