Motivation
Since the release of Microsoft Outlook 2016, it is possible to connect clients via the ActiveSync protocol, mostly known for its use on mobile devices to synchronize Calender, contacts and e-mail. So the complicated MAPI protocol (i.e. offered by OpenChange project) isn’t necessarily needed anymore.
So my goal was to set up a Linux server that offers ActiveSync protocol interfaces as well as the “classic” IMAP, Caldav and Carddav interfaces for integration with e-mail clients such as Thunderbird. For this SOGo seems to be a very good solution, because it offers you to use the standard Unix daemons in your desired configuration and is just a component that you can easily plug in to offer access to all components with above mentioned protocols which makes the server very easy to maintain without the need to use new, unfamiliar interfaces to manage it like partly with other groupware servers.
So I describe some simple setup for SOGo 2 (because I like its webinterface) on a Debian Jessie Server for handling mail on one domain in the combination Dovecot IMAP server and Postfix MTA. It is a mix of stuff taken from several tutorials available on the Internet.
Installation
1) Install SOGo 2
echo deb http://packages.inverse.ca/SOGo/nightly/2/debian/ jessie jessie >>/etc/apt/sources.list
apt-key adv --keyserver keys.gnupg.net --recv-key 0x810273C4
apt-get update
apt-get install sogo mysql-server sope4.9-gdl1-mysql memcached
2) Fix some packages
sed -i "s/SHOWWARNING=true/SWOWWARNING=false/" /etc/tmpreaper.conf # suppress tmpreaper warnings
sed -i "s/127.0.0.1/localhost/" /etc/memcached.conf # Fix IPv6 errors
/etc/init.d/mysql restart
/etc/init.d/memcached restart
3) Install MySQL and create user table
Unforutnately, SOGo doesn’t support PAM authentication for whatever reason. The most common solution in the tutorials is to use a LDAP server, which is of course also possible, but for me, it is harder to maintain due to my lack of LDAP-Skills. Therefore I decided to maintain a MySQL user database which will also be used by Dovecot for authentication and which I can add new shell users to with a simple shell script presented lateron. I prefer to have my mailbox users in /etc/passwd with a disabled login shell so that they automatically have a systemwide account, get their e-mails stored and delivered to their home-directories. That’s why I chose this method:
mysql -u root -p mysql
CREATE DATABASE `sogo` CHARACTER SET='utf8';
CREATE USER 'sogo'@'localhost' IDENTIFIED BY 'sogopasswd';
GRANT ALL PRIVILEGES ON `sogo`.* TO 'sogo'@'localhost' WITH GRANT OPTION;
USE sogo;
CREATE TABLE sogo_users (c_uid VARCHAR(60) PRIMARY KEY, c_name VARCHAR(60),
c_password VARCHAR(32), c_cn VARCHAR(128), mail VARCHAR(128),
home VARCHAR(255) NOT NULL, uid INTEGER NOT NULL, gid INTEGER NOT NULL);
FLUSH PRIVILEGES;
quit
4) Install and configure dovecot IMAP-Server
apt-get install dovecot dovecot-sieve dovecot-lmtpd dovecot-managesieved dovecot-sql dovecot-mysql
You can also install dovecot-pop3d if needed.
/etc/dovecot/conf.d/10-auth.conf |
#!include auth-system.conf.ext
!include auth-sql.conf.ext
|
/etc/dovecot/conf.d/10-mail.conf |
mail_location = maildir:~/Maildir
|
/etc/dovecot/conf.d/10-master.conf |
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
group = postfix
mode = 0600
user = postfix
}
}
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
}
|
/etc/dovecot/conf.d/15-lda.conf |
lda_mailbox_autocreate = yes
|
/etc/dovecot/conf.d/20-lmtp.conf |
protocol lmtp {
postmaster_address = postmaster@domain.com
mail_plugins = $mail_plugins sieve
}
|
/etc/dovecot/conf.d/20-managesieve.conf |
service managesieve-login {
inet_listener sieve {
port = 4190
address = 127.0.0.1
}
}
|
/etc/dovecot/conf.d/auth-sql.conf.ext |
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
driver = prefetch
}
userdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
|
/etc/dovecot/dovecot-sql.conf.ext |
driver = mysql
connect = host=localhost dbname=sogo user=sogo password=sogopasswd
default_pass_scheme = MD5
user_query = \
SELECT home, uid, gid \
FROM sogo_users WHERE c_uid = '%n'
password_query = \
SELECT c_uid AS user, c_password AS password, \
home AS userdb_home, uid AS userdb_uid, gid AS userdb_gid \
FROM sogo_users WHERE c_uid = '%u'
|
4) Install the Postfix MTA
I assume that you have 2 DNS set up pointing to your mailserver: mail.domain.com and imap.domain.com, this also facilitates automatic mail server detection in most Mail applications.
apt-get install postfix postfix-policyd-spf-python
/etc/postfix/main.cf |
myhostname = mail.domain.com
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
home_mailbox = Maildir/
mailbox_transport = lmtp:unix:private/dovecot-lmtp
# Restrictions
policy-spf_time_limit = 3600s
smtpd_helo_required = yes
smtpd_recipient_restrictions = permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
reject_unauth_pipelining,
reject_non_fqdn_recipient,
check_policy_service unix:private/policy-spf
smtpd_sender_restrictions = permit_mynetworks,
permit_sasl_authenticated,
reject_unknown_hostname,
reject_unknown_recipient_domain,
reject_unknown_sender_domain
smtpd_client_restrictions = permit_mynetworks,
permit_sasl_authenticated
|
/etc/postfix/master.cf |
# SPF
policy-spf unix - n n - - spawn
user=nobody argv=/usr/bin/policyd-spf
|
5) Install Apache 2 webserver
apt-get install apache2 sogo-activesync
a2enmod proxy
a2enmod proxy_http
a2enmod headers
a2enmod rewrite
a2enconf SOGo
6) configure Microsoft ActiveSync
Please read here carefully for related documentation.
apt-get install sogo-activesync
Uncomment and modify:
/etc/apache2/conf-available/SOGo.conf |
ProxyPass /Microsoft-Server-ActiveSync \
http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync \
retry=60 connectiontimeout=60 timeout=660
|
7) Install Let’s encrypt SSL-certificates for your site
As self-signed certificates are always needed to be added to a trust list on the client side which makes setup for the user harder and we now have the possibility to get free SSL-certificates by the Let’s encrypt project, it is a good idea to use them instead. The downside of this may be the expiration time (3 months), but as renewal process can be automated with a cron-job, it’s not such a big issue.
/etc/apache2/sites-available/000-default.conf |
ServerAlias mail.domain.com
ServerAlias imap.domain.com
|
echo "deb http://ftp.debian.org/debian jessie-backports main" >>/etc/apt/sources.list
apt-get update
apt-get install python-certbot-apache -t jessie-backports
letsencrypt --apache -d mail.domain.com -d imap.domain.com
Change TLS parameters in Postfix:
/etc/postfix/main.cf |
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.domain.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.domain.com/privkey.pem
|
/etc/dovecot/conf.d/10-ssl.conf |
ssl = yes
ssl_cert = </etc/letsencrypt/live/imap.domain.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/imap.domain.com/privkey.pem
|
Now we need to create a renewal-Cronjob for the requested certificates:
/etc/cron.weekly/letsencrypt |
#!/bin/sh
letsencrypt renew
result=$(find /etc/letsencrypt/live/ -type l -mtime -1 )
if [ -n "$result" ]; then
/etc/init.d/apache2 restart
/etc/init.d/postfix restart
/etc/init.d/dovecot restart
fi
|
chmod a+x /etc/cron.weekly/letsencrypt
8) Install DKIM
If you want to increase your e-mail reputation, it is a good idea to set up SPF and DKIM records. For DKIM, you can use opendkim daemon. This step is optional and requires full access to your DNS server.
This was shameslessly copied from here
apt-get install opendkim opendkim-tools
mkdir /etc/opendkim
mkdir /etc/opendkim/keys
mkdir /var/spool/postfix/var/run/opendkim
/etc/opendkim.conf |
# OpenDKIM agiert als Mail Filter (= Milter) in den
# Modi signer (s) und verifier (v) und verwendet eine
# Socket-Datei zur Kommunikation (alternativ: lokaler Port)
Mode sv
# Socket local:/var/run/opendkim/opendkim.sock
# Socket inet:12345@localhost
Socket local:/var/spool/postfix/var/run/opendkim/opendkim.sock
# OpenDKIM verwendet diesen Benutzer bzw.
# diese Gruppe
UserID postfix:postfix
UMask 002
PidFile /var/run/opendkim/opendkim.pid
# OpenDKIM bei Problemen neustarten,
# aber max. 10 mal pro Stunde
AutoRestart yes
AutoRestartRate 10/1h
# Logging (wenn alles funktioniert eventuell reduzieren)
Syslog yes
SyslogSuccess yes
LogWhy yes
# Verfahren, wie Header und Body durch
# OpenDKIM verarbeitet werden sollen.
Canonicalization relaxed/simple
# interne Mails nicht mit OpenDKIM verarbeiten
ExternalIgnoreList refile:/etc/opendkim/trusted
InternalHosts refile:/etc/opendkim/trusted
# welche Verschlüsselungs-Keys sollen für welche
# Domains verwendet werden
# (refile: für Dateien mit regulären Ausdrücke)
SigningTable refile:/etc/opendkim/signing.table
KeyTable /etc/opendkim/key.table
# diesen Signatur-Algorithmus verwenden
SignatureAlgorithm rsa-sha256
# Always oversign From (sign using actual From and a null From to prevent
# malicious signatures header fields (From and/or others) between the signer
# and the verifier. From is oversigned by default in the Debian pacakge
# because it is often the identity key used by reputation systems and thus
# somewhat security sensitive.
OversignHeaders From
|
/etc/opendkim/trusted |
127.0.0.1
::1
localhost
hostname
domain.com
|
/etc/opendkim/signing.table |
# for E-Mails from xxx@domain.com use the key 'domain' for signing
*@domain.com domain
|
/etc/opendkim/key.table |
# The key 'domain' is located in /etc/opendkim/keys/domain.private
domain domain.com:201611:/etc/opendkim/keys/domain.private
|
/etc/default/opendkim |
USER=postfix
GROUP=postfix
|
cd /etc/opendkim
opendkim-genkey -d domain.com -b 2048 -r -s 201611
mv 201611.private keys/domain.private
mv 201611.txt keys/domain.txt
chown -R postfix:postfix /etc/opendkim
chmod -R go-rwx /etc/opendkim/keys
/etc/postfix/main.cf |
milter_protocol = 6
milter_default_action = accept
smtpd_milters = unix:/var/run/opendkim/opendkim.sock
non_smtpd_milters = unix:/var/run/opendkim/opendkim.sock
|
Then add the record from /etc/opendkim/keys/domain.txt to your DNS server.
9) Deploy some antivirus and antispam scripts for the MTA
It is a good idea to have some virus filtering and antispam on a Mailserver obiously. Now there are a lot of filtering solutions out there which can accomplish this, but I prefer not to rely on another piece of big software, so I just use a simple shellscript to do some simple mail filtering according to my needs. I’m using Clamav as an antivirus-filter, spamassassin as a spam-filter and some custom .zip file parsing using munpack which certainly can be improved.
apt-get install clamdscan spamassassin clamav-daemon mpack zip
mkdir /var/spool/spam
chmod 777 /var/spool/spam
mkdir /var/spool/virus
chmod 777 /var/spool/virus
/etc/spamassassin/local.cf |
rewrite_header Subject *****SPAM*****
report_contact your_email@address.com
|
/etc/default/spamassassin |
ENABLED=1
|
/etc/init.d/spamassassin start
mkdir /var/lib/dovecot/sieve
chmod 777 /var/lib/dovecot/sieve/
Now we want to move spam into the Junk folder automatically on the server side:
/var/lib/dovecot/sieve/global.sieve |
require "fileinto";
if header :contains "X-Spam-Flag" "YES" {
fileinto "Junk";
}
|
/etc/dovecot/conf.d/90-sieve.conf |
plugin {
sieve_before=/var/lib/dovecot/sieve/global.sieve
}
|
Now create the mail-scanner script that can be modified according to your needs:
/etc/postfix/mail-scanner.sh |
#!/bin/sh
EX_OK=0
EX_BOUNCE=69
EX_DEFER=75
SENDMAIL="/usr/sbin/sendmail -G -i"
# prepare for scanning
INPUT=`mktemp /tmp/mail-scanner.XXXXXXXX`
OUTPUT=`mktemp /tmp/mail-scanner.XXXXXXXX`
if [ "$?" != 0 ]; then
logger -s -p mail.warning -t scanner "Unable to create temporary files, deferring"
exit $EX_DEFER
fi
trap "rm -f $INPUT $OUTPUT" EXIT TERM
cat >$INPUT
# check for viruses
/usr/bin/clamdscan --quiet - <$INPUT
return="$?"
if [ "$return" = 1 ]; then
TARGET=/var/spool/virus/`basename $INPUT`
logger -p mail.info "ClamAV found virus, quarantined as $TARGET"
cp $INPUT $TARGET || { echo Cannot copy possible-virus mail; exit $EX_DEFER; };
exit $EX_OK
elif [ "$return" != 0 ]; then
logger -s -p mail.warning -t scanner "Temporary ClamAV failure $return, deferring"
exit $EX_DEFER
fi
# check for undesired file extensions
MTMPDIR=`mktemp -d /tmp/mailattXXXXXXX`
BADEXT='[.](bat|cmd|com|cpl|exe|pif|msi|vb|vbs|js|jse|wsf)$'
munpack -C $MTMPDIR -q <$INPUT >/dev/null 2>&1
for i in $( ls $MTMPDIR | egrep -i '[.]zip' )
do
if [ $( unzip -l "${MTMPDIR}/${i}" | tail -n +4 |head -n -2 | egrep -i "${BADEXT}" | wc -l ) -gt 0 ]; then
HASBADEXT=1
break
fi
done
if [ $( ls $MTMPDIR | egrep -i "${BADEXT}" | wc -l ) -gt 0 ]; then
HASBADEXT=1
fi
rm -r $MTMPDIR
if [ "$HASBADEXT" = 1 ]; then
TARGET=/var/spool/virus/`basename $INPUT`
logger -p mail.info "Found potential virus with suspicious extension, quarantined as $TARGET"
cp $INPUT $TARGET || { echo Cannot copy possible-virus mail; exit $EX_DEFER; };
exit $EX_OK
fi
# check for spam
/usr/bin/spamc -E <$INPUT >$OUTPUT
return="$?"
if [ "$return" = 1 ]; then
# Activate this if you want to filter it out instead of just marking und filing into Junk
#TARGET=/var/spool/spam/`basename $INPUT`
logger -p mail.info "SpamAssassin found spam"
#cp $INPUT $TARGET || { echo Cannot copy possible-spam mail; exit $EX_DEFER; };
#exit $EX_OK
elif [ "$return" != 0 ]; then
logger -s -p mail.warning -t scanner "Temporary SpamAssassin failure $return, delivering"
# 1) deliver original mail
OUTPUT=$INPUT
# 2) or defer instead of delivering:
# exit $EX_DEFER
fi
# deliver
$SENDMAIL "$@" <$OUTPUT
exit $?
|
chmod 755 /etc/postfix/mail-scanner.sh
Now register mail-scanner with postfix by appending content_filter option to smtpd line and adding the filter definition:
/etc/postfix/master.cf |
smtp inet n - n - - smtpd
-o content_filter=scanner:dummy
scanner unix - n n - 4 pipe
flags=Rq user=nobody null_sender=
argv=/etc/postfix/mail-scanner.sh -f ${sender} -- ${recipient}
|
10) Configure SOGo
/etc/sogo/sogo.conf |
/* Database configuration (mysql:// or postgresql://) */
SOGoProfileURL = "mysql://sogo:sogopasswd@localhost:3306/sogo/sogo_user_profile";
OCSFolderInfoURL = "mysql://sogo:sogopasswd@localhost:3306/sogo/sogo_folder_info";
OCSSessionsFolderURL = "mysql://sogo:sogopasswd@localhost:3306/sogo/sogo_sessions_folder";
/* Mail */
SOGoIMAPServer = localhost;
SOGoSieveServer = sieve://127.0.0.1:4190;
SOGoSMTPServer = 127.0.0.1;
SOGoMailDomain = domain.com;
SOGoMailingMechanism = smtp;
/* Notifications */
SOGoAppointmentSendEMailNotifications = YES;
SOGoACLsSendEMailNotifications = NO;
SOGoFoldersSendEMailNotifications = NO;
/* Authentication */
SOGoPasswordChangeEnabled = YES;
/* SQL authentication example */
/* These database columns MUST be present in the view/table:
* c_uid - will be used for authentication - it's the username or username@domain.tld)
* c_name - which can be identical to c_uid - will be used to uniquely identify entries
* c_password - password of the user, plain-text, md5 or sha encoded for now
* c_cn - the user's common name - such as "John Doe"
* mail - the user's mail address
* See the installation guide for more details
*/
SOGoUserSources = (
{
type = sql;
id = users;
viewURL = "mysql://sogo:sogopasswd@127.0.0.1:3306/sogo/sogo_users";
canAuthenticate = YES;
isAddressBook = YES;
displayName = "Benutzer";
userPasswordAlgorithm = md5;
}
);
/* Web Interface */
SOGoVacationEnabled = YES;
SOGoSieveScriptsEnabled = YES;
SOGoMailAuxiliaryUserAccountsEnabled = YES;
/* General */
SOGoLanguage = German;
SOGoTimeZone = Europe/Vienna;
SOGoSuperUsernames = (youradminacct);
/* Activesync */
SOGoMaximumPingInterval = 300;
SOGoMaximumSyncWindowSize = 100;
SOGoMaximumSyncResponseSize = 5172;
|
If you read the ACtiveSync tuning link, you know that you need to maybe increase the number of active instances for handling requests according to the number of your users by setting PREFORK= value in /etc/default/sogo
Now finally you need to add your admin user you also specified above in SOGoSuperUsernames with SOGo. For every new user, you can add the user like a normal shell user with
adduser [username]
and maybe disable login shell in /etc/passwd. Then use the following script to register your new user with the MySQL DB (reenter user’s password when prompted):
cr_user.sh |
#!/bin/bash
if [ -z $1 ]; then
echo $0 \[Username\]
exit
fi
ID=$1
C_UID=`id -u $ID`
if [ $? -ne 0 ]; then
echo User $ID does not exist
exit
fi
C_GID=`id -g $ID`
C_CN=`getent passwd $ID | cut -d ':' -f 5 | cut -d"," -f1`
C_MAIL=$ID@`cat /etc/mailname`
C_HOME=`eval echo ~$ID`
read -sp "Password: " C_PASSWORD
echo "INSERT INTO sogo_users(c_uid,c_name,c_cn,c_password,mail,home,uid,gid) VALUES
('$ID','$ID','$C_CN',MD5('$C_PASSWORD'),'$C_MAIL','$C_HOME',$C_UID,$C_GID)
ON DUPLICATE KEY UPDATE c_uid='$ID',c_name='$ID',c_cn='$C_CN',c_password=MD5('$C_PASSWORD'),
mail='$C_MAIL',home='$C_HOME',uid=$C_UID,gid=$C_GID;" | mysql -u sogo --password=sogopasswd sogo
|
Finally you can add SOGo backup script to your daily backups (you need to adjust the file):
cp /usr/share/doc/sogo/sogo-backup.sh /usr/sbin/sogo-backup
vi /usr/sbin/sogo-backup
Finally restart all the stuff
Comments
perfect tutorial!
thanks for your effort
nice tutorial – just have gone through all steps on a fresh jessie installation …
please here are some small fixes :
4)
apt-get install dovecot-core dovecot-pop3d dovecot-imapd dovecot-sieve dovecot-lmtpd dovecot-managesieved dovecot-mysql
6)
the modified file should be
/etc/sogo/sogo.conf
7)
letsencrypt gives unicodeerror … simple fix was to delete the non unicode char at offset 147 of /usr/lib/pymodules/python2.7/rpl-1.5.5.egg-info
thank you for the article…i have been searching for the same for quiet sometime..
I am stuck at the point of creating sogo users using the script.. when I ran the script in echos Username and exits
Hi – i’m getting this error
gpg: requesting key 810273C4 from hkp server keys.gnupg.net
gpgkeys: key 810273C4 can’t be retrieved
gpg: no valid OpenPGP data found.
gpg: Total number processed: 0
Nice guide . Want to implement following this guide but How the postfix will authenticate the users as there is no database for virtual mailbox table mapping /virtual domains mapping in main.cf .
Спасибо за информацию!!!!!
Trackbacks