MailScanner
-------
---
Email Server With Postfix Dovecot and MailScanner (Part 1 - LEMP)
Posted on 2016-04-20 | In Email Server , LEMP | 2 Comments
Email server is quite complicate. It is not only just for sending and receiving emails, but also need lots features and protections. Recently I built such an email server for my company. The whole process is worth to document.
I know there are some solutions exist for easy and quick setup a mail server, such as iRedMail. But I prefer to build the server step by step from scratch. This way I can understand how these all different components put together and how they work with each other. It’s kind of like driving an automobile, knowing a little bit better how the engine and transmission works will help me when there is a problem or need improvement down the road.
Features and Components
I begin with a list of some important features I needed for the mail system:
support virtual domain and mailboxes
support SMTP submission with STARTTLS
support IMAP/POP3 with SSL/TLS
have a secured web mail
have a management web interface for user accounts
have a management web interface for MailScanner
Here I list the major components I will build on the new email server:
LEMP server (CentOS 7 + Nginx + MariaDB + PHP)
Postfix
Dovecot (with Sieve filter)
MailScanner (which using ClamAV and Spamassassin)
MailWatch (Web UI for MailScanner)
RoundCube webmail
Postfix Admin (a web based interface used to manage mailboxes, virtual domains and aliases.)
Fail2ban and iptables (Firewall)
OpenSSL and Let’s Encripts SSL certificate
OpenDKIM and SPF
Domain name and DNS
Before I start to build the email server, I checked that I have these network related stuff ready:
Domain name: mydomain.com. I’ll use subdomain smtp.mydomain.com as the host name of the mail server.
A static IP from my ISP: 11.22.33.44
DNS records:
mydomain.com. 600 IN A 11.22.33.44
smtp.mydomain.com. 3600 IN A 11.22.33.44
mydomain.com. 3599 IN MX 10 smtp.mydomain.com.
postfixadmin.mydomain.com. 1697 IN CNAME smtp.mydomain.com.
mailwatch.mydomain.com. 1697 IN CNAME smtp.mydomain.com.
roundcube.mydomain.com. 1697 IN CNAME smtp.mydomain.com.
Reverse DNS PTR record: (Need ask my ISP to set this reverse DNS up for me)
$ dig -x 11.22.33.44 +short
smtp.mydomain.com.
CentOS installation
I installed CentOS 7.2 64bit which is my faverate OS for server platform. During the installation, I setup the static IP, time zone, and hard drive partitions.
I’ll save all the emails in /home/vmail later on, so make sure it has enough space for email storage.
Once I finished installation and reboot the server, I login in as root and start configration.
Disable SELinux
Install some packages
Firewall
Centos 7 come with Firewalld as the firewall but I like to use iptables for firewall, so let’s disable the default installed firewalld.
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
yum -y install net-tools nano wget man bind-utils git mailx telnet
systemctl stop firewalld
systemctl mask firewalld
systemctl disable firewalld
Install iptables:
yum -y install iptables-services
systemctl enable iptables
systemctl start iptables
Now install fail2ban:
yum install -y epel-release
yum install -y fail2ban jwhois
Create fail2ban local configration file:
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Edit this file to enable sshd jail. Set:
[sshd]
enabled = true
...
Now enable and start the fail2ban service:
systemctl start fail2ban.service
systemctl enable fail2ban.service
Now the ssh port 22 is protected by Fail2ban against brutal-force attack. In the future, anytime I need open up a new port for a service in iptables, I’ll also need to configure the corresponding fail2ban jail to have it protected.
There are lots scan activities on the well-known ssh port 22. So I changed the sshd to listen on a different port. Also configured iptables and fail2ban accordingly.
NTP
CentOS 7 use chronyd to keep the clock synchronized.
If timezone is not set, then:
timedatectl set-timezone America/Vancouver
Now install Chrony:
yum install -y chrony
systemctl enable chronyd
systemctl start chronyd
Use the following commands to check the status:
timedatectl
chronyc tracking
chronyc sources
chronyc sourcestats
Update system then reboot
Bring the system up to date:
yum -y update && reboot
After reboot, log in and check:
# sestatus
SELinux status: disabled
LEMP
MariaDB
Install MariaDB server:
yum install -y mariadb-server
systemctl enable mariadb.service
systemctl start mariadb.service
Secure MariaDB. Run this command, set the root password, and answer Y to all other questions:
mysql_secure_installation
Install Nginx
Add Nginx Repo by create a configration file /etc/yum.repos.d/nginx.repo with the following content:
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
Install Nginx:
yum install nginx
Edit /etc/nginx/nginx.conf:
worker_processes 4;
...
gzip on;
server_tokens off;
...
Set worker_processes to the CPU core number.
Start nginx:
systemctl enable nginx.service
systemctl start nginx.service
Check to see Nginx is running on port 80:
# netstat -ntlp | grep :80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 9901/nginx: master
Now open up port 80 and 443 on iptables. I can access http://smtp.mydomain.com for the nginx’s default page.
Install PHP5
PHP5 works in nginx through PHP-FPM. So install some php packages:
yum install php-fpm php-cli php-mysql php-gd php-mcrypt php-intl php-ldap php-odbc php-pdo php-pecl-memcache php-pear php-mbstring php-xml php-xmlrpc php-mbstring php-snmp php-soap php-imap
Edit /etc/php.ini , set
date.timezone = America/Vancouver
cgi.fix_pathinfo = 0
Edit /etc/php-fpm.d/www.conf, use socket instead of TCP port for better performance:
;listen = 127.0.0.1:9000
listen = /var/run/php-fpm/php-fpm.sock
user = nginx
group = nginx
Next enable and start php-fpm:
systemctl enable php-fpm.service
systemctl start php-fpm.service
Let’s Encrypt SSL Certificate
I use the free LE SSL Cert for all the virtual hosts and SMTP/IMAP/POP3
First make sure all DNS record are pointed to the correct IP. This includes all A records for @, www, and smtp.
yum install git bc
git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
Also make sure port 443 is open on iptables.
Obtain a certicate:
systemctl stop nginx
cd /opt/letsencrypt
./letsencrypt-auto certonly --standalone
Fill in my email address, then agree the agreement, then fill in all the domain names:
mydomain.com, www.mydomain.com,smtp.mydomain.com, mailwatch.mydomain.com, postfixadmin.mydomain.com roundcube.mydomain.com
output:
IMPORTANT NOTES:
Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/mydomain.com/fullchain.pem. Your cert will
expire on 2016-05-29. To obtain a new version of the certificate in
the future, simply run Let’s Encrypt again.
Let’s Encript SSL Cert is only valid for 90 days. To renew it, set a cron job (or wrote a script). The command to renew is:
/root/.local/share/letsencrypt/bin/letsencrypt renew --agree-tos
To test this command, add --dry-run flag at the end.
Here is my simple bash script le_renew.sh:
#!/bin/bash
systemctl stop nginx
/root/.local/share/letsencrypt/bin/letsencrypt renew --agree-tos
systemctl start nginx
Tip:
To obtain LE SSL certificates in one liner command:
/opt/letsencrypt/letsencrypt-auto certonly --standalone --agree-tos --email myemail@domain.tld -d mydomain.com -d www.mydomain.com -d smtp.mydomain.com -d mailwatch.mydomain.com -d postfixadmin.mydomain.com -d smtp.mydomain.com -d roundcube.mydomain.com
Configure Virtual Host
I will have few web sites running on this server using named based virtual host. They are RoundCube webmail, Postfix Admin and MailWatch.
I need to create a 2048 bit DH params file(default is 1024 bit):
openssl dhparam -out /etc/nginx/dhparams.pem 2048
Now let’s configure the first virtual host postfixadmin.mydomain.com by create a new configration file /etc/nginx/conf.d/postfixadmin.conf with content:
server {
listen 80;
server_name postfixadmin.mydomain.com;
return 301 https://$server_name$request_uri; # enforce https
}
server {
listen 443 ssl;
server_name postfixadmin.mydomain.com;
root /var/www/html/postfixadmin;
index index.php;
charset utf-8;
access_log /var/log/nginx/pa-access.log;
error_log /var/log/nginx/pa-error.log;
## SSL settings
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";
ssl_dhparam /etc/nginx/dhparams.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_ecdh_curve secp521r1;
add_header Strict-Transport-Security max-age=31536000;
location / {
try_files $uri $uri/ index.php;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
}
}
Let’s make a test page:
mkdir /var/www/html/postfixadmin
echo "<?php phpinfo(); ?>" > /var/www/html/postfixadmin/info.php
Restart Nginx and test by go to http://postfixadmin.mydomain.com/info.php, it should jump to https:// automatcally and show the PHP info page.
A good test for SSL can be done at SSL LABS. I got the highest score “A+“!
Repeat the above steps to create other virtual host sites(mailwatch, roundcube). Later we will build these sites in their doc root directory.
Now I have a basic LEMP server with SSL and firewall protections. I’m now ready to build the mail server on this system.
Quick links:
Part 1: LEMP
Part 2: Postfix and Dovecot
Part 3: MailScanner and MailWatch
Part 4: SPF, DKIM and DMARC
Part 5: Roundcube Webmail
Part 6: Afterthoughts
Email Server With Postfix Dovecot and MailScanner (Part 2 - Postfix and Dovecot)
Posted on 2016-04-20 | In Email Server | 13 Comments
Postfix is the mail transfer agent (MTA) that routes and delivers email. Dovecot is the IMAP and POP3 server. The two works together make a perfect email server.
Postfix
Postfix is installed and running after default CentOS 7 installation. It is just a basic SMTP server lintening on local interface (127.0.0.1) and serve for existing local user only.
Database for virtual domain and user
We will install PostfixAdmin which use MaridDB as back-end to handle virtual domain and user accounts. When Postfix and Dovecot want authenticate users they will query the MariaDB database.
Login MariaDB as root and create a database postfix. Add user postfix and grant accesses to it.
mysql -uroot -p
Create a database
CREATE DATABASE postfix;
CREATE USER 'postfix'@'localhost' IDENTIFIED BY 'PApassword';
GRANT ALL PRIVILEGES ON postfix.* TO 'postfix'@'localhost';
FLUSH PRIVILEGES;
QUIT;
Postfix Admin
Postfix Admin is a web based interface used to manage mailboxes, virtual domains and aliases
Get the Postfix Admin site ready:
cd /usr/local/src
wget http://downloads.sourceforge.net/project/postfixadmin/postfixadmin/postfixadmin-2.93/postfixadmin-2.93.tar.gz
tar zvxf postfixadmin-2.93.tar.gz
rm -rf /var/www/html/postfixadmin
mv postfixadmin-2.93 /var/www/html/postfixadmin
chown -R nginx:nginx /var/www/html/postfixadmin
Edit /var/www/html/postfixadmin/config.inc.php
With:
<?php
$CONF['configured'] = true;
$CONF['database_type'] = 'mysqli';
$CONF['database_user'] = 'postfix';
$CONF['database_password'] = 'PApassword';
$CONF['database_name'] = 'postfix';
?>
I also need to manual create a session dir:
mkdir /var/lib/php/session/
chown -R nginx:nginx /var/lib/php/session/
Postfix Admin web setup
Now go to https://postfixadmin.mydomain.com/setup.php to continue the setup in the web interface.
Type in “Setup Password” and generate password hash.
Copy this line back to /var/www/html/postfixadmin/config.inc.php, at line 30:
$CONF['setup_password'] = '82020bc067e2a6deaa3fba3632529114:0834f649bf09ee930910ab1b353e3f0722b77ee8';
Then create the superadmin account.
Now use the superadmin account to login at https://postfixadmin.mydomain.com/login.php. This is the admin login.
Once we create user email account, the user may login to manage their own account at https://postfixadmin.mydomain.com/users/login.php. Note the different address.
Bug Fix:
After login, click on “Fetch email” I got error “Invalid query: FUNCTION postfix.FROM_BASE64 does not exist”
To fix it, edit /var/www/html/postfixadmin/model/PFAHandler.php at line 572:
$base64_decode = "###KEY###";
Link Postfix to MariaDB
Create 5 database query configration files:
/etc/postfix/mysql-virtual_domains_maps.cf
hosts = localhost
user = postfix
password = PApassword
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'
/etc/postfix/mysql-relay_domains_maps.cf
hosts = localhost
user = postfix
password = PApassword
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '1'
/etc/postfix/mysql-virtual_mailbox_maps.cf
hosts = localhost
user = postfix
password = PApassword
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
/etc/postfix/mysql-virtual_mailbox_limit_maps.cf
hosts = localhost
user = postfix
password = PApassword
dbname = postfix
query = SELECT quota FROM mailbox WHERE username='%s' and active = '1'
/etc/postfix/mysql-virtual_alias_maps.cf
hosts = localhost
user = postfix
password = PApassword
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
Change permission to protect this files:
chgrp postfix mysql-*.cf
chmod 640 /etc/postfix/mysql-*.cf
Make Postfix use these 5 files to qurey database, add the following lines to /etc/postfix/main.cf
relay_domains = proxy:mysql:/etc/postfix/mysql-relay_domains_maps.cf
virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual_alias_maps.cf,regexp:/etc/postfix/virtual_regexp
virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual_domains_maps.cf
virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailbox_maps.cf
virtual_mailbox_limit_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailbox_limit_maps.cf
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 $smtpd_sender_login_maps $sender_bcc_maps $recipient_bcc_maps $smtp_generic_maps $lmtp_generic_maps $alias_maps $virtual_mailbox_limit_maps
Create virtual_regexp file
touch /etc/postfix/virtual_regexp
To enable postfix listen on all interface, edit /etc/postfix/main.cf line 113,116:
inet_interfaces = all
#inet_interfaces = localhost
vmail user
Create a local user vmail and set its home dir as maildir:
groupadd -g 5000 vmail
mkdir /home/vmail
chmod 770 /home/vmail/
useradd -r -u 5000 -g vmail -d /home/vmail/ -s /sbin/nologin -c "Virtual Mailbox" vmail
chown vmail:vmail /home/vmail/
Make postfix to use this vmail account, add to /etc/postfix/main.cf
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_mailbox_base = /home/vmail
Restart postfix:
systemctl restart postfix
Also open TCP port 25 in iptables.
Now the Postfix SMTP is running. I can test it from another computer:
$ telnet smtp.mydomain.com 25
Trying 11.22.33.44...
Connected to smtp.mydomain.com.
Escape character is '^]'.
220 smtp.mydomain.com ESMTP Postfix
Test virtual domain/mailbox
Setup test email account
Go to Postfix Admin site [https://postfixadmin.mydomain.com], log in as admin user, then create a virtual domain. In my case, I go to “Domain List” –> “New Domain”, add “mydomain.com”.
Next go to “Virtual List”, then “Add Mailbox”, add a newmail box(Username: “gao”). Make sure “Active” and “Send Welcome mail” are checked. Then click on “Add Mailbox”.
Test receiving email
If everything is ok, you should see an email has been sent to gao@mydomain.com in the /var/log/maillog log file:
Apr 20 15:47:13 smtp postfix/smtpd[27293]: connect from localhost[::1]
Apr 20 15:47:14 smtp postfix/smtpd[27293]: 5CC0199812: client=localhost[::1]
Apr 20 15:47:14 smtp postfix/cleanup[27300]: 5CC0199812: message-id=<20160420224714.5CC0199812@smtp.mydomain.com>
Apr 20 15:47:14 smtp postfix/smtpd[27293]: disconnect from localhost[::1]
Apr 20 15:47:14 smtp postfix/qmgr[27051]: 5CC0199812: from=<gao@mydomain.com>, size=485, nrcpt=1 (queue active)
Apr 20 15:47:14 smtp postfix/virtual[27309]: 5CC0199812: to=<gao@mydomain.com>, relay=virtual, delay=0.34, delays=0.11/0.07/0/0.17, dsn=2.0.0, status=sent (delivered to maildir)
Apr 20 15:47:14 smtp postfix/qmgr[27051]: 5CC0199812: removed
Check the maildir I saw the email has been put in the maildir:
# ls -l /home/vmail/mydomain.com/gao/new/
total 4
-rw------- 1 vmail vmail 568 Apr 20 15:47 1461192434.Vfd02I30000081M492053.smtp.mydomain.com
I also tested it by sending an email from my Gmail account and watch the maillog to see the mail arrived.
Test send email out
I still use telnet command from a remote PC to send a test email out:
$ telnet smtp.mydomain.com 25
Trying 11.22.33.44...
Connected to smtp.mydomain.com.
Escape character is '^]'.
220 smtp.mydomain.com ESMTP Postfix
EHLO jade
250-smtp.mydomain.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
MAIL FROM: gao@mydomain.com
250 2.1.0 Ok
RCPT TO: mytestmail@gmail.com
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: this is a telnet test
Hi,this is just a quick test form telnet.
.
250 2.0.0 Ok: queued as 2528F1A4E3
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
Check the maillog to make sure the mail is send out.
At this stage, sending email to Gmail may fail. This will be fixed later by setup proper SPF and DKIM record in our DNS settings. If you have to test with Gmail then you may add mydomain.com as truseted domain at [https://postmaster.google.com]
SMTP Submission
I will enable SMTP submission on port 587, and use dovecot embebed SASL authentication to verify user identity.
Edit /etc/postfix/master.cf, remove comments in these lines:
submission inet n - n - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_reject_unlisted_recipient=no
-o smtpd_client_restrictions=$mua_client_restrictions
-o smtpd_helo_restrictions=$mua_helo_restrictions
-o smtpd_sender_restrictions=$mua_sender_restrictions
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
Edit /etc/postfix/main.cf, add lines:
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_tls_cert_file = /etc/letsencrypt/live/mydomain.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mydomain.com/privkey.pem
smtpd_tls_security_level = may
#Disable sslv2 ad SSLv3
smtpd_tls_protocols= !SSLv2, !SSLv3
smtpd_tls_mandatory_protocols= !SSLv2, !SSLv3
#set minimum TLS ciphers grade for tls
smtpd_tls_mandatory_ciphers = high
#use server ciphers instead client preference
tls_preempt_cipherlist = yes
#ciphers to exclude
smtpd_tls_mandatory_exclude_ciphers = aNULL, MD5 , DES, ADH, RC4, PSD, SRP, 3DES, eNULL
#disallow plain login
smtpd_tls_auth_only = yes
mua_client_restrictions = permit_sasl_authenticated,reject
mua_helo_restrictions = permit_sasl_authenticated,reject
mua_sender_restrictions = permit_sasl_authenticated,reject
Restart postfix
systemctl restart postfix
Dovecot
I use Dovecot to provide POP amd IMAP services so the user can use an email client(Thunderbird, Outlook.,etc) to retrive emails.
Install dovecot
dovecot main config file
Edit dovecot main config file /etc/dovecot/dovecot.conf
yum install dovecot dovecot-mysql dovecot-pigeonhole
protocols = imap pop3
listen = *
shutdown_clients = yes
Enable and start dovecot:
systemctl enable dovecot
systemctl start dovecot
Check use netstat to see dovecot is listening on port 110,143,993,995
# netstat -ntlp | grep dovecot
tcp 0 0 0.0.0.0:110 0.0.0.0:* LISTEN 7564/dovecot
tcp 0 0 0.0.0.0:143 0.0.0.0:* LISTEN 7564/dovecot
tcp 0 0 0.0.0.0:993 0.0.0.0:* LISTEN 7564/dovecot
tcp 0 0 0.0.0.0:995 0.0.0.0:* LISTEN 7564/dovecot
Dovecot authentication
I configured Dovecot to use database created by PostfixAdmin for user authentication with Let’s Encript’s SSL certificate:
database query configration
Create a file /etc/dovecot/conf.d/dovecot-mysql.conf.ext
driver = mysql
connect = host=localhost dbname=postfix user=postfix password=PApassword
password_query = SELECT username as user, password, concat('/home/vmail/', maildir) as userdb_home, concat('maildir:/home/vmail/', maildir) as userdb_mail, 5000 as userdb_uid, 5000 as userdb_gid FROM mailbox WHERE username = '%u' AND active = '1'
user_query = SELECT concat('/home/vmail/', maildir) as home, concat('maildir:/home/vmail/', maildir) as mail, 5000 AS uid, 5000 AS gid, CONCAT('*:bytes=', quota) as quota_rule FROM mailbox WHERE username = '%u' AND active = '1'
Also we need a file to provide information about accounts quota. Edit /etc/dovecot/conf.d/dovecot-mysql-quota.conf.ext
connect = host=localhost dbname=postfix user=postfix password=PApassword
map {
pattern = priv/quota/storage
table = quota2
username_field = username
value_field = bytes
}
map {
pattern = priv/quota/messages
table = quota2
username_field = username
value_field = messages
}
Set file permission
chmod 640 /etc/dovecot/conf.d/dovecot-mysql*
With above files dovecot will query mariadb info about users idendity and mailbox quotas.
Make dovecot use MariaDB for authentication
Edit /etc/dovecot/conf.d/auth-sql.conf.ext
passdb {
driver = sql
args = /etc/dovecot/conf.d/dovecot-mysql.conf.ext
}
userdb {
driver = sql
args = /etc/dovecot/conf.d/dovecot-mysql.conf.ext
}
Enable dovecot to use sql_auth, edit /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes
auth_mechanisms = plain login cram-md5
#!include auth-system.conf.ext
!include auth-sql.conf.ext
Enable SSL/TLS support
Edit /etc/dovecot/conf.d/10-ssl.conf
ssl_cert = </etc/letsencrypt/live/mydomain.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mydomain.com/privkey.pem
# SSL protocols to use
ssl_protocols = !SSLv2 !SSLv3
# SSL ciphers to use
ssl_cipher_list = EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4
# Prefer the server's order of ciphers over client's.
ssl_prefer_server_ciphers = yes
Edit /etc/dovecot/conf.d/10-master.conf
service imap-login {
inet_listener imap {
port = 143
}
inet_listener imaps {
port = 993
ssl = yes
}
service pop3-login {
inet_listener pop3 {
port = 110
}
inet_listener pop3s {
port = 995
ssl = yes
}
}
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = vmail
group = vmail
}
Maildir and mail user
Edit /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/home/vmail/%d/%n/:INDEX=/home/vmail/%d/%n/indexes
mail_uid =5000
mail_gid =5000
first_valid_uid = 5000
last_valid_uid = 5000
first_valid_gid = 5000
last_valid_gid = 5000
Test dovecot
Open TCP port 993,995 and 587 on iptables. (I force all clients to use SSL/TLS so I keep port 110 and 143 closed.)
Restart dovecot
systemctl restart dovecot
Test SSL login to IMAPS on port 993 from a remote PC:
#openssl s_client -connect smtp.mydomain.com:993 -quiet
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X1
verify error:num=20:unable to get local issuer certificate
verify return:0
* OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN AUTH=LOGIN AUTH=CRAM-MD5] Dovecot ready.
a1 LOGIN gao@mydomain.com my_password
a1 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS SPECIAL-USE BINARY MOVE] Logged in
a2 LIST "" "*"
* LIST (\HasNoChildren) "." INBOX
a2 OK List completed.
a3 EXAMINE INBOX
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
* OK [PERMANENTFLAGS ()] Read-only mailbox.
* 4 EXISTS
* 4 RECENT
* OK [UNSEEN 1] First unseen.
* OK [UIDVALIDITY 1457462303] UIDs valid
* OK [UIDNEXT 5] Predicted next UID
a3 OK [READ-ONLY] Examine completed (2.716 secs).
a4 LOGOUT
* BYE Logging out
a4 OK Logout completed.
Mailbox quota
I enable imap_quota plugin:
Edit /etc/dovecot/conf.d/10-mail.conf, line 215 should be
mail_plugins = $mail_plugins quota
Edit /etc/dovecot/conf.d/20-imap.conf, line 56 should be
mail_plugins = $mail_plugins imap_quota
Edit /etc/dovecot/conf.d/90-quota.conf, line 68 should look like these
quota = maildir:User quota
Now restart dovecot service
Edit mailbox quota in PostfixAdmin, set to non-zero, then I can see the quota of INBOX.
Test the email server
Now I can create an new email account in Thunderbird to test.
Always use full email address as login name. Here is the setup with IMAP on port 993:
Now I can send out and receive email so the basic mail server is working.
Email Server With Postfix Dovecot and MailScanner (Part 3 - MailScanner and MailWatch)
http://blog.pztop.com/2016/04/21/Email-Server-With-Postfix-Dovecot-MailScanner-3/
I use MailScanner to scan emails for viruses, spam, phishing, malware, and other attacks against security vulnerabilities. Under the hood, MailScanner uses ClamAV(clamd) for virus scan, and uses Spamassassin to scan for spams.
MailWatch is the web UI frontend to manage MailScanner. I can manage qurantine and generate reports easily right in the web browser.
MailScanner come with a installation script you may use it for easy setup. It will install all compoenets once you made your selection.
ClamAV
Clam AV can be load in 3 different mode. Here is the explaination:
clamscan: most expensive CPU-wise, but involves no extra setup. This just executes the clamscan command-line tool. This causes the signature database to be re-read for each object scanned and can be pretty CPU intensive compared to the others.
clamav module: less expensive than clamscan CPU-wise, but needs the Mail::ClamAV perl module. This method loads a copy of the libclamav scanner library into MailScanner and keeps it resident, using it to perform scans without needing to re-read the signature libraries, etc. It can be somewhat touchy about what versions of Mail::ClamAV work with various versions of clamav.
clamd: less expensive than clamscan CPU-wise, but needs clamd running and is relatively new code. This causes MailScanner to connect to clamd’s socket and use that for scanning. Since clamd is already resident, there’s no need to re-read signatures. Since it’s using clamd, which comes with clamav, there’s no real version-compatibility problems like with the module, at least in theory
So I decide to run ClamAV as a daemon (clamd) for better performance.
ClamAVInstallation
Install ClamAV:
yum install clamav-server clamav-data clamav-update clamav-filesystem clamav clamav-scanner-systemd clamav-devel clamav-lib clamav-server-systemd
ClamAV will need unrar, it can be installed from rpmforge repository, so:
cd /usr/local/src/
wget http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el7.rf.x86_64.rpm
rpm -ivh rpmforge-release-0.5.3-1.el7.rf.x86_64.rpm
yum install unrar
After install unrar, I disabled rpmforge repo:
sed -i 's/enabled = 1/enabled = 0/g' /etc/yum.repos.d/rpmforge.repo
freshclam
freshclam will update the virus signature database. To enable it and update:
sed -i -e 's/^Example/#Example/' /etc/freshclam.conf
freshclam -v
Also edit /etc/sysconfig/freshclam, comment out this line as:
#FRESHCLAM_DELAY=disabled-warn # REMOVE ME
The MailScanner will call /usr/local/bin/freshclam to update the database, so make the proper link:
ln -s /usr/bin/freshclam /usr/local/bin/freshclam
clamd daemon
Enable clamd by editing /etc/clamd.d/scan.conf like this:
# Example
LogFile /var/log/clamd.scan
LogTime yes
LogSyslog yes
LogFacility LOG_MAIL
PidFile /var/run/clamd.scan/clamd.pid
LocalSocket /var/run/clamd.scan/clamd.sock
Create the log file:
touch /var/log/clamd.scan
chown :clamscan $_
chmod 0660 $_
Now enable and start the service:
systemctl enable clamd@scan
systemctl start clamd@scan
systemctl status clamd@scan
Test clamd service
I download a virus file (Eicar Test) and send to ClamAV
# cd /tmp
# wget http://www.eicar.org/download/eicar.com
# clamscan --infected --remove eicar.com
eicar.com: Eicar-Test-Signature FOUND
eicar.com: Removed.
----------- SCAN SUMMARY -----------
Known viruses: 4283601
Engine version: 0.98.7
Scanned directories: 0
Scanned files: 1
Infected files: 1
Data scanned: 0.00 MB
Data read: 0.00 MB (ratio 0.00:1)
Time: 21.513 sec (0 m 21 s)
Spamassassin
Install Spamassassin”
yum install spamassassin
Update database:
sa-update
Enable snd start Spamassassin:
systemctl enable spamassassin
systemctl start spamassassin
systemctl status spamassassin
MailScanner
MailScanner work like this:
As instructed, Postfix holds the mail upon receipt.
MailScanner swoops in and scans the email in queue.
MailScanner re queues the email and hands it over back to Postfix.
Postfix processes the email as necessary and delivers the mail to recipient.
Install MailScanner
First stop and disable postfix. We will use MailScanner in the future.
systemctl stop postfix
systemctl disable postfix
Download MailScanner and install:
cd /usr/local/src/
wget https://s3.amazonaws.com/mailscanner/release/v4/rpm/MailScanner-4.85.2-3.rpm.tar.gz
tar zvxf MailScanner-4.85.2-3.rpm.tar.gz
cd MailScanner-4.85.2-3
./install.sh
Start the installation. Answer Y to all questions except these three(they have been took care in the previous steps):
Do you want to install a Mail Transfer Agent (MTA)?
I can install an MTA via the Yum package manager to save you the trouble of having to do
this later. If you plan on using an MTA that is not listed below, you will have install
it manually yourself if you have not already done so.
1 - sendmail
2 - postfix
3 - exim
N - Do not install
Recommended: 1 (sendmail)
Install an MTA? [1] : N
Do you want to install or update Spamassassin?
This package is recommended unless you have your own spam detection solution.
Recommended: Y (yes)
Install or update Spamassassin? [n/Y] : N
Do you want to install or update Clam AV during this installation process?
This package is recommended unless you plan on using a different virus scanner.
Note that you may use more than one virus scanner at once with MailScanner.
Even if you already have Clam AV installed you should select this option so I
will know to check the clamav-wrapper and make corrections if required.
Recommended: Y (yes)
Install or update Clam AV? [n/Y] : N
MailScanner Configuration
Edit /etc/MailScanner/MailScanner.conf
%org-name% = mydomain
%org-long-name% = mydomain Ltd.
%web-site% = www.mydomain.com
Incoming Work Group = clamscan
Incoming Work Permissions = 0640
Virus Scanners = clamd
Clamd Socket = /var/run/clamd.scan/clamd.sock
Clamd Use Threads = yes
MTA = postfix
Run As User = postfix
Run As Group = postfix
Incoming Queue Dir = /var/spool/postfix/hold
Outgoing Queue Dir = /var/spool/postfix/incoming
Use SpamAssassin = yes
SpamAssassin User State Dir = /var/spool/MailScanner/spamassassin
SpamScore Number Instead Of Stars = yes
Always Include SpamAssassin Report = yes
Log Spam = yes
Correct a permission to allow write for group clamscan:
chmod -R 770 /var/spool/MailScanner/incoming/
Edit /etc/MailScanner/spam.assassin.prefs.conf
envelope_sender_header X-mydomain-MailScanner-From
Edit /etc/MailScanner/virus.scanners.conf
clamd /bin/false /usr
clamd permission
When clamd scan emails, I want pass --fdpass to it, so it won’t have permssion issue:
mv /usr/bin/clamdscan /usr/bin/clamdscan-cmd
Now create a new file /usr/bin/clamdscan
#!/bin/bash
/usr/bin/clamdscan-cmd --fdpass $@
Make it executable:
chmod +x /usr/bin/clamdscan
Postfix hold queue
Let postfix hold all mails for scan, add line at bottom of /etc/postfix/header_checks
/^Received:/ HOLD
Enable header check in Postfix, edit /etc/postfix/main.cf, uncomment this line 548:
header_checks = regexp:/etc/postfix/header_checks
Check MailScanner configration to see if there is any error:
MailScanner --lint
Spamassassin Plugins
With plugins, Spamassassin can detect spam and bulk email better with online resources.
First, I need open some ports on iptables needed by DCC, pyzor and razor. Add these rules to /etc/sysconfig/iptables in the INPUT chain and reload iptables:
### razor DCC pyzor ###
-A INPUT -p tcp --dport 2703 -j ACCEPT
-A INPUT -p udp --dport 24441 -j ACCEPT
-A INPUT -p udp -m udp --dport 1024:65535 --sport 6277 -j ACCEPT
###End of razor DCC pyzor ###
Edit /etc/mail/spamassassin/mailscanner.cf
# paths to utilities
ifplugin Mail::SpamAssassin::Plugin::Pyzor
pyzor_path /usr/bin/pyzor
endif
ifplugin Mail::SpamAssassin::Plugin::DCC
dcc_path /usr/bin/dccproc
dcc_home /etc/dcc
endif
ifplugin Mail::SpamAssassin::Plugin::Razor2
razor_config /etc/mail/spamassassin/razor/razor-agent.conf
endif
Enable these in spamassassin. Edit /etc/mail/spamassassin/v310.pre
loadplugin Mail::SpamAssassin::Plugin::DCC
loadplugin Mail::SpamAssassin::Plugin::Pyzor
loadplugin Mail::SpamAssassin::Plugin::Razor2
DCC
Install DCC
yum install sendmail-milter
rpm -Uvh https://www.mirrorservice.org/sites/dl.atrpms.net/el7-x86_64/atrpms/stable/DCC-1.3.145-25.el7.x86_64.rpm
Test
cdcc info
Pyzor
Add a line in /etc/mail/spamassassin/local.cf
pyzor_options --homedir /etc/mail/spamassassin/.pyzor
Install Pyzor:
rpm -Uvh ftp://mirror.switch.ch/pool/4/mirror/fedora/linux/releases/22/Everything/x86_64/os/Packages/p/pyzor-0.5.0-10.fc21.noarch.rpm
pyzor --homedir /etc/mail/spamassassin discover
Test
spamassassin -t -D pyzor < /usr/share/doc/spamassassin-3.4.0/sample-spam.txt
Razor
mkdir /etc/mail/spamassassin/razor
razor-admin -create -home=/etc/mail/spamassassin/razor
razor-admin -register
Edit /etc/mail/spamassassin/razor/razor-agent.conf
razorhome = /etc/mail/spamassassin/razor
Test Razor2
spamassassin -t -D razor2 < /usr/share/doc/spamassassin-3.4.0/sample-spam.txt
Test
Check MailScanner configration again:
MailScanner --lint
Also check for SpamAssassin:
spamassassin -D --lint
Now restart services and check maillog to see if any error
systemctl restart clamd@scan
systemctl restart spamassassin
systemctl restart MailScanner
Now I can send some spam test email then check the maillog to see if it has need catched. Here are some test site:
[http://www.emailsecuritycheck.net/]
[https://www.mail-tester.com/]
MailWatch
Download code
cd /usr/local/src
git clone https://github.com/mailwatch/1.2.0.git
MariaDB database
Create a database with downloaded sql file:
cd /usr/local/src/1.2.0
mysql -uroot -p < create.sql
Create a DB user:
# mysql -uroot -p
Enter password:
MariaDB [(none)]> GRANT ALL ON mailscanner.* TO mailwatch@localhost IDENTIFIED BY 'MWpassword';
Query OK, 0 rows affected (1.27 sec)
MariaDB [(none)]> GRANT FILE ON *.* TO mailwatch@localhost IDENTIFIED BY 'MWpassword';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.05 sec)
Admin user
Create an Admin user gao:
# mysql mailscanner -umailwatch -pMWpassword
MariaDB [mailscanner]> INSERT INTO users SET username = 'gao', password = md5('mwpassword'), fullname = 'Gao', type = 'A';
Configure MailWatch
Move the mailscanner directory to the web server’s root
cp -r /usr/local/src/1.2.0/mailscanner /var/www/html/.
chown -R nginx:nginx /var/www/html/mailscanner/
Copy /var/www/html/mailscanner/conf.php.example to conf.php then edit the database setting:
define('DB_TYPE', 'mysql');
define('DB_USER', 'mailwatch');
define('DB_PASS', 'MWpassword');
define('DB_HOST', 'localhost');
define('DB_NAME', 'mailscanner');
define('DB_DSN', DB_TYPE.'://'.DB_USER.":".DB_PASS."@".DB_HOST."/".DB_NAME);
define('TIME_ZONE', 'America/Vancouver');
// Log file location
define('MS_LOG', '/var/log/maillog');
define('MAIL_LOG', '/var/log/maillog');
// Date/Time settings
define('DATE_FORMAT', '%y-%m-%d');
define('TIME_FORMAT', '%H:%i:%s');
Now stop MailScanner
systemctl stop MailScanner
Edit /etc/MailScanner/MailScanner.conf
Always Looked Up Last = &MailWatchLogging
Detailed Spam Report = yes
Quarantine Whole Message = yes
Quarantine Whole Messages As Queue Files = no
Include Scores In SpamAssassin Report = yes
Quarantine User = root
Quarantine Group = nginx
Quarantine Permissions = 0660
Is Definitely Not Spam = &SQLWhitelist
Is Definitely Spam = &SQLBlacklist
Copy Perl module to CustomFunctions
cp /usr/local/src/1.2.0/MailScanner_perl_scripts/SQLBlackWhiteList.pm /usr/share/MailScanner/MailScanner/CustomFunctions/
cp /usr/local/src/1.2.0/MailScanner_perl_scripts/MailWatch.pm /usr/share/MailScanner/MailScanner/CustomFunctions/.
Edit /usr/share/MailScanner/MailScanner/CustomFunctions/SQLBlackWhiteList.pm
sub CreateList {
my($type, $BlackWhite) = @_;
my($dbh, $sth, $sql, $to_address, $from_address, $count, $filter);
my($db_name) = 'mailscanner';
my($db_host) = 'localhost';
my($db_user) = 'mailwatch';
my($db_pass) = 'MWpassword';
...
Edit /usr/share/MailScanner/MailScanner/CustomFunctions/MailWatch.pm
# Modify this as necessary for your configuration
my($db_name) = 'mailscanner';
my($db_host) = 'localhost';
my($db_user) = 'mailwatch';
my($db_pass) = 'MWpassword';
...
I also installed a perl module Encoding::FixLatin in CPAN:
# cpan
cpan[1]> install Encoding::FixLatin
...
Start MailScanner again, check /var/log/maillog for any error.
Nginx configuration
Create a new nginx virtual host configration file /etc/nginx/conf.d/mailwatch.conf
server {
listen 80;
server_name mailwatch.mydomain.com;
return 301 https://$server_name$request_uri; # enforce https
}
server {
listen 443 ssl;
server_name mailwatch.mydomain.com;
root /var/www/html/mailscanner;
index index.php;
charset utf-8;
## SSL settings
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";
ssl_dhparam /etc/nginx/dhparams.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_ecdh_curve secp521r1;
add_header Strict-Transport-Security max-age=31536000;
# add_header X-Frame-Options DENY;
# auth_basic "Restricted area";
# auth_basic_user_file /etc/nginx/passwd;
location / {
try_files $uri $uri/ index.php;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
}
}
Mail queue
Configure mail queue directory:
chown -R postfix:nginx /var/spool/postfix/hold
chown -R postfix:nginx /var/spool/postfix/incoming
chmod -R 770 /var/spool/postfix/hold
chmod -R 770 /var/spool/postfix/incoming/
Test
Restart Nginx:
systemctl restart nginx
Now it’s time to go to https://mailwatch.mydomain.com/
Login as admin user “gao” with password “mwpassword”
Go to http://www.emailsecuritycheck.net/ and send myself some spam and virus, check MailWatch to see the result.
There are few tools came with MailWatch souce code in the "tools" directory. You may need to setup them following the instruction.
SpamAssassin Bayes
SpamAssassin Bayes can try to identify spam (or ham) by learning tokens. Here I configrue it with MailWatch installed.
Edit /etc/MailScanner/spam.assassin.prefs.conf
bayes_path /etc/MailScanner/bayes/bayes
bayes_file_mode 0660
bayes_ignore_header X-mydomain-COM-MailScanner
bayes_ignore_header X-mydomain-COM-MailScanner-SpamCheck
bayes_ignore_header X-mydomain-COM-MailScanner-SpamScore
bayes_ignore_header X-mydomain-COM-MailScanner-Information
Create the ‘new’ bayes directory, make the directory owned by the same group as the web server user and make the directory setgid:
mkdir /etc/MailScanner/bayes
chown root:nginx /etc/MailScanner/bayes
chmod g+rws /etc/MailScanner/bayes
Since I already some spam mails in quarantine, so I force a sa-learn
sa-learn --spam /var/spool/MailScanner/quarantine/20160420
After this I see few files have been generated in bayes home directory:
# ll /etc/MailScanner/bayes/
total 28
-rw-rw---- 1 root nginx 50 Mar 11 21:18 bayes.mutex
-rw-rw---- 1 root nginx 12288 Mar 11 21:18 bayes_seen
-rw-rw---- 1 root nginx 12288 Mar 11 21:18 bayes_toks
Test to see bayes work
spamassassin -D -p /etc/MailScanner/spam.assassin.prefs.conf --lint
shoud see these lines:
Mar 11 21:20:27.020 [6494] dbg: bayes: tie-ing to DB file R/O /etc/MailScanner/bayes/bayes_toks
Mar 11 21:20:27.022 [6494] dbg: bayes: tie-ing to DB file R/O /etc/MailScanner/bayes/bayes_seen
Mar 11 21:20:27.024 [6494] dbg: bayes: found bayes db version 3
Mar 11 21:20:27.025 [6494] dbg: bayes: DB journal sync: last sync: 0
Mar 11 21:20:27.026 [6494] dbg: bayes: not available for scanning, only 2 spam(s) in bayes DB < 200
Mar 11 21:20:27.026 [6494] dbg: bayes: untie-ing
It can also be verified in MailWatch in “Tools/Link” –> “Spamassassin Bayes Database Info”
Now restart Spamassassin and MailScanner and check maillog.
Now I have an email server with protections. Unforturnatly this is just a start. There are so many things need further configuration to improve the security of the mail system.
Quick links:
Part 1: LEMP
Part 2: Postfix and Dovecot
Part 3: MailScanner and MailWatch
Part 4: SPF, DKIM and DMARC
Part 5: Roundcube Webmail
Part 6: Afterthoughts
#MariaDB #Postfix #Dovecot #MailScanner
Email Server With Postfix Dovecot and MailScanner (Part 2 - Postfix and Dovecot) Email Server With Postfix Dovecot and MailScanner (Part 4 - SPF DKIM and DMARC)
Email Server With Postfix Dovecot and MailScanner (Part 4 - SPF DKIM and DMARC)
Posted on 2016-04-21 | In Email Server | 6 Comments
Both SPF and DKIM has two parts: One is the DNS records for SPF/DKIM serve the purpose of setting your own policy for others to check. The other is to check if the incoming mail message is in accordance with the SPF/DKIM that is set by the admins of the domain from which the message was sent.
SPF
DNS txt record
Add a txt record to DNS server:
@ TXT 300 v=spf1 a ip4:11.22.33.44/32 include:mydomain.com ~all
Test it by sending an email to check-auth@verifier.port25.com and will get a report back.
SPF on Postfix
To prevent sender address forgery, we setup The Sender Policy Framework (SPF) on the postfix. When there is an incoming email, postfix will check the SPF record.
yum install perl-Mail-SPF perl-Sys-Hostname-Long
cd /usr/local/src
wget https://launchpad.net/postfix-policyd-spf-perl/trunk/release2.010/+download/postfix-policyd-spf-perl-2.010.tar.gz
tar zvxf postfix-policyd-spf-perl-2.010.tar.gz
cd postfix-policyd-spf-perl-2.010
cp postfix-policyd-spf-perl /usr/local/sbin/.
Then edit /etc/postfix/master.cf and add the following stanza at the end:
[...]
policy unix - n n - - spawn
user=nobody argv=/usr/bin/perl /usr/local/sbin/postfix-policyd-spf-perl
(The leading spaces before user=nobody ... are important so that Postfix knows that this line belongs to the previous one!)
Then open /etc/postfix/main.cf and search for the smtpd_recipient_restrictions directive. You should have reject_unauth_destination in that directive, and right after reject_unauth_destination you add check_policy_service unix:private/policy like this:
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, check_policy_service unix:private/policy
policy_time_limit = 3600
Restart MailScanner, send an email from gmail to gao@mydomain.com, in header:
Received-SPF: pass (gmail.com ... _spf.google.com: Sender is authorized to use 'gao@gmail.com' in 'mfrom' identity (mechanism 'include:_netblocks.google.com' matched)) receiver=szeta; identity=mailfrom; envelope-from="gao@gmail.com"; helo=mail-pa0-f48.google.com; client-ip=209.85.220.48
DKIM
OpenDKIM
Install OpenDKIM
yum install opendkim
Generate keys for signing
You need to generate a private and a public key for each of the domains for which you wish to sign mail. The private key is stored away on your server, while the public key gets published in your domain’s DNS records so that receiving mail servers can verify your DKIM-signed mail.
You need decide now what the name of your selector is going to be. A selector is a unique keyword that is associated with both keys (public and private), included in all the signatures, and published in your DNS records. For simplicity, I use the word szeta as my default selector.
mkdir -p /etc/opendkim/keys/mydomain.com
/usr/sbin/opendkim-genkey -D /etc/opendkim/keys/mydomain.com/ -d mydomain.com -s szeta
Now we have two files for each domain(the text file is the public key).
chown -R opendkim:opendkim /etc/opendkim/keys/*
Edit four configuration files:
/etc/opendkim.conf (I created a new file)
##
## opendkim.conf -- configuration file for OpenDKIM filter
##
AutoRestart Yes
AutoRestartRate 10/1h
Canonicalization relaxed/simple
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
KeyTable refile:/etc/opendkim/KeyTable
LogWhy Yes
Mode sv
PidFile /var/run/opendkim/opendkim.pid
SignatureAlgorithm rsa-sha256
SigningTable refile:/etc/opendkim/SigningTable
Socket inet:8891@localhost
Syslog Yes
SyslogSuccess Yes
TemporaryDirectory /var/tmp
UMask 022
UserID opendkim:opendkim
/etc/opendkim/KeyTable
/etc/opendkim/SigningTable
/etc/opendkim/TrustedHosts
szeta._domainkey.mydomain.com mydomain.com:szeta:/etc/opendkim/keys/mydomain.com/szeta
*@mydomain.com szeta._domainkey.mydomain.com
127.0.0.1
::1
localhost
Now enable OpenDKIM in Postfix, edit /etc/postfix/main.cf, add
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept
Now start services
systemctl enable opendkim
systemctl start opendkim
systemctl restart MailScanner
DNS txt record
Now that the mail server is signing outgoing mail and verifying incoming mail, you’ll need to put some information in your DNS records to tell other mail servers how your keys are set up, and provide the public key for them to check that your mail is properly signed.
Use the public key created above to add a DNS TEXT record to mydomain.com.
Check:
$ dig szeta._domainkey.mydomain.com TXT +noall +answer
szeta._domainkey.mydomain.com. 3599 IN TXT "v=DKIM1\; k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGYaonAHWmVitTa9p4QRmtjobBRyWflXwCa3akQ87aJ2iT8bg/25/t7dwzOq4nRS9CoW6vu9gVPBS6hWIumRoWFwYfwgUXGWCxMQLr6Nc7wuKnqPOoA6/JTa0s1o0QWiY18k1Rsh8p4/oRQilCEVjvdezRxsIigIEGUlEn9a+xqwIDAQAB"
Test
Restart MailScanner then send email to check-auth@verifier.port25.com then read the report, also analyse header as well.
DMARC
A DMARC policy allows a sender to indicate that their emails are protected by SPF and/or DKIM, and give instruction if neither of those authentication methods passes. Please be sure you have a DKIM and SPF set before using DMARC.
To enable DMARC, just add a TXT DNS record. Host name is _dmarc and text value is v=DMARC1; p=none ;rua=mailto:postmaster@mydomain.com
To check:
# dig _dmarc.mydomain.com TXT +noall +answer
_dmarc.mydomain.com. 7207 IN TXT "v=DMARC1\;p=none\;rua=mailto:postmaster@mydomain.com"
Email Server With Postfix Dovecot and MailScanner (Part 5 - Roundcube webmail)
Posted on 2016-04-25 | In Email Server | 0 Comments
Roundcube is a free opensource web-based IMAP email client. It provides full functionality you expect from an email client, including MIME support, address book, folder manipulation, message searching and spell checking. At the time of this writing, Roundcube just released v1.1.5.
Download souce code
cd /usr/local/src/
wget https://github.com/roundcube/roundcubemail/releases/download/1.1.5/roundcubemail-1.1.5-complete.tar.gz
tar zvxf roundcubemail-1.1.5-complete.tar.gz
Now copy the source code to web root:
cp -r /usr/local/src/roundcubemail-1.1.5 /var/www/html/roundcubemail
chown -R nginx:nginx /var/www/html/roundcubemail
Database
Roundcube uses MariaDB as the backend database. So create a database and add a database user:
#mysql -uroot -p
CREATE DATABASE roundcubemail;
GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost IDENTIFIED BY 'RCpassword';
FLUSH PRIVILEGES;
quit
Nginx Configuration
Create a new Nginx site configrration file /etc/nginx/conf.d/roundcube.conf
server {
listen 80;
server_name roundcube.mydomain.com;
return 301 https://$server_name$request_uri; # enforce https
}
server {
listen 443 ssl;
server_name roundcube.mydomain.com;
root /var/www/html/roundcubemail;
index index.php;
charset utf-8;
## SSL settings
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";
ssl_dhparam /etc/nginx/dhparams.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_ecdh_curve secp521r1;
add_header Strict-Transport-Security max-age=31536000;
# add_header X-Frame-Options DENY;
# auth_basic "Restricted area";
# auth_basic_user_file /etc/nginx/passwd;
location / {
try_files $uri $uri/ index.php;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
}
}
Reload Nginx
systemctl reload nginx
Web installation
Now I can start installation by go to https://roundcube.mydomain.com/installer/
Check environment
First the RouncCube installer will check the environment. There may be some items show as “NOT AVAILABLE”, for these items I only need make sure what I needed is “OK”
I found that it complain that “Mcrypt” and “Intl” PHP modules shows as “NOT AVALIABLE”, so let’s intall them and restart PHP-FPM”
yum -y install php-mcrypt php-intl
systemctl restart php-fpm
Then refreash the web page and now the environment is ready. Click “NEXT” button to go on.
Create config
Fill the “Database password”. Also fill in SMTP and IMAP configration. Create the config file
Don't warray to much about put in wrong configration inforamtion on the IMAP and SMTP sections. I will fix them later by manually editing the configration file later.
Test config
Go ahead to inatialize database.
When test SMTP and IMAP there are errors. I manually edited the configured file config/config.inc.php
// ----------------------------------
// SQL DATABASE
// ----------------------------------
$config['db_dsnw'] = 'mysql://roundcube:RCpassword@localhost/roundcubemail';
// ----------------------------------
// IMAP
// ----------------------------------
$config['default_host'] = 'ssl://smtp.mydomain.com';
$config['default_port'] = 993;
$config['imap_auth_type'] = 'PLAIN';
// ----------------------------------
// SMTP
// ----------------------------------
$config['smtp_server'] = 'tls://smtp.mydomain.com';
$config['smtp_port'] = 587;
$config['smtp_auth_type'] = 'PLAIN';
$config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p';
Save the configration file. To test again, go back to
https://roundcube.mydomain.com/installer/index.php?_step=1
All tests passed. Last remove the installer folder.
rm -rf /var/www/html/roundcubemail/installer
Now Roundcube wabmail is working. I can use it at https://roundcube.mydomain.com/
Sieve filter
One of the reason I use Dovecot is that I need to use Sieve filter in RoundCube Mail, so user can setup their own filter such as Vacation Autoresponse.
LMTP
Till now my mail server use Postfix as the LDA(Local Delivery Agent) to diliver mails to users maildir. For sieve to work we need to use dovecot as a LDA. This means that dovecot has to write the email to the email folder of the user for the final delivery.
We will configure dovecot acting as local delivery using LMTP. (The other option is using LDA, which works like a binary command, each time that postfix sends a email lda deliver is called.)
Configure LMTP by editing /etc/dovecot/conf.d/10-master.conf
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
group = postfix
mode = 0600
user = postfix
}
unix_listener lmtp {
#mode = 0666
}
# Create inet listener only if you can't use the above UNIX socket
#inet_listener lmtp {
# Avoid making LMTP visible for the entire internet
#address =
#port =
#}
}
Also set up a postmaster addr at /etc/dovecot/conf.d/20-lmtp.conf
protocol lmtp {
postmaster_address = postmaster@yourdomain.com
}
Then we will enable lmtp protocol in /etc/dovecot/dovecot.conf
protocols = imap pop3 lmtp
Now I need tell Postfix to use Dovecot LDA, edit /etc/postfix/main.cf add lines:
#use dovecot lmtp as virtual transport
virtual_transport = lmtp:unix:private/dovecot-lmtp
Restart Dovecot and MailScanner, send a test email then check maillog to see LMTP in action for local delivery:
Apr 24 13:29:32 smtp dovecot: master: Dovecot v2.2.10 starting up for imap, pop3, lmtp (core dumps disabled)
...
Apr 24 13:32:34 smtp dovecot: lmtp(3544): Connect from local
Apr 24 13:32:35 smtp dovecot: lmtp(3544, gao@mydomain.com): ZIvkJGJx6FbYDQAA1qURPQ: msgid=<56E8714F.4060405@gmail.com>: saved mail to INBOX
Apr 24 13:32:35 smtp postfix/lmtp[3543]: D23571331C6: to=<gao@mydomain.com>, relay=smtp.mydomain.com[private/dovecot-lmtp], delay=12, delays=11/0.31/0.24/0.81, dsn=2.0.0, status=sent (250 2.0.0 <gao@mydomain.com> ZIvkJGJx6FbYDQAA1qURPQ Saved)
Apr 24 13:32:35 smtp dovecot: lmtp(3544): Disconnect from local: Successful quit
Apr 24 13:32:35 smtp postfix/qmgr[3461]: D23571331C6: removed
Managesieve
I use dovecot-pigeonhole and it’s been installed already.
Enable sieve filter, edit /etc/dovecot/conf.d/20-lmtp.conf
protocol lmtp {
# Space separated list of plugins to load (default is global mail_plugins).
mail_plugins = $mail_plugins sieve
postmaster_address = postmaster@mydomain.com
}
Configure sieve, edit /etc/dovecot/conf.d/90-sieve.conf
plugin {
# The path to the user's main active script. If ManageSieve is used, this the
# location of the symbolic link controlled by ManageSieve.
sieve = ~/sieve/.dovecot.sieve
sieve_dir = ~/sieve
...
}
Configure managesieve, edit /etc/dovecot/conf.d/20-managesieve.conf
protocols = $protocols sieve
service managesieve-login {
inet_listener sieve {
port = 4190
}
...
}
(Note, make sure all brackets are closed properly.)
Now restart Dovecot then test to see if managesieve works:
# telnet localhost 4190
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
"IMPLEMENTATION" "Dovecot Pigeonhole"
"SIEVE" "fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date ihave"
"NOTIFY" "mailto"
"SASL" "PLAIN LOGIN CRAM-MD5"
"STARTTLS"
"VERSION" "1.0"
OK "Dovecot ready."
^]
telnet> quit
Connection closed.
Roundcube Plugin SieveRules
I will install the SieveRules plugin created by JohnDoh at Github:
https://github.com/JohnDoh/Roundcube-Plugin-SieveRules-Managesieve
Save to roundcube plugins folder as /var/www/html/roundcube/plugins/sieverules
Then make a config.inc.php from config.inc.php.dist
cd /usr/local/src/
git clone https://github.com/JohnDoh/Roundcube-Plugin-SieveRules-Managesieve
cp -r Roundcube-Plugin-SieveRules-Managesieve /var/www/html/roundcubemail/plugins/sieverules
cd /var/www/html/roundcubemail/plugins/sieverules
cp config.inc.php.dist config.inc.php
chown -R nginx:nginx /var/www/html/roundcubemail/plugins/sieverules
Edit /var/www/html/roundcubemail/plugins/sieverules/config.inc.php, set
$config['sieverules_auth_type'] = 'PLAIN';
Last add the plugin to /var/www/html/roundcube/config/config.inc.php:
// List of active plugins (in plugins/ directory)
$config['plugins'] = array(
'archive',
'zipdownload',
'fail2ban',
'password',
'jqueryui',
'sieverules',
);
(Note: jqueryui is needed for this plugin to work.)
Now login to Roundcube webmail to create a filter and test it.
---
--------