Difference between revisions of "OpenChange server"

From ArchWiki
Jump to: navigation, search
m (Prerequisites)
(Add all needed python bindings)
Line 17: Line 17:
 
Install all prerequisites:
 
Install all prerequisites:
  
  sudo pacman -S apache boost cyrus-sasl docbook-xml dovecot gcc-objc gnustep-base libical libmemcached memcached mod_wsgi pigeonhole postfix postgresql python2-{beaker,decorator,formencode,mako,nose,setuptools,simplejson,tempita} sqlite
+
  sudo pacman -S apache boost cyrus-sasl docbook-xml dovecot gcc-objc gnustep-base libical libmemcached memcached mod_wsgi pigeonhole postfix postgresql python2-{beaker,decorator,formencode,mako,nose,paste,pygments,setuptools,simplejson,tempita} sqlite
 +
 
 +
wget https://aur.archlinux.org/packages/py/python-webhelpers/python-webhelpers.tar.gz
 +
tar -xf python-webhelpers.tar.gz
 +
cd python-webhelpers
 +
makepkg
 +
sudo pacman -U --noconfirm python-webhelpers-*pkg.tar.*
 +
cd ..
 +
 +
for p2pkg in paste-{deploy,script} repoze-lru routes web{ob,error,test} pylons
 +
do
 +
    wget https://aur.archlinux.org/packages/py/python2-${p2pkg}/python2-${p2pkg}.tar.gz
 +
    tar -xf python2-${p2pkg}.tar.gz
 +
    cd python2-${p2pkg}
 +
    makepkg --asroot
 +
    pacman -U python2-${p2pkg}-*pkg.tar.*
 +
    cd ..
 +
done
  
 
==OpenChange Installation==
 
==OpenChange Installation==

Revision as of 07:00, 26 November 2013

Summary help replacing me
Installing and configuring OpenChange Server
Related
Samba 4 Active Directory Domain Controller
Active Directory Integration


Tango-document-new.pngThis article is a stub.Tango-document-new.png

Notes: This page is a work in progress, I wanted to get at least preliminary version here for now... (Discuss in Talk:OpenChange server#)


This article explains how to setup a mail server using OpenChange server following on from the Samba_4_Active_Directory_Domain_Controller article. It will use Postfix for the MTA, Dovecot for the IMAP/POP server, and SOGo for the backend. Below is preliminary text to get it started...

Installation

Prerequisites

Install all prerequisites:

sudo pacman -S apache boost cyrus-sasl docbook-xml dovecot gcc-objc gnustep-base libical libmemcached memcached mod_wsgi pigeonhole postfix postgresql python2-{beaker,decorator,formencode,mako,nose,paste,pygments,setuptools,simplejson,tempita} sqlite
wget https://aur.archlinux.org/packages/py/python-webhelpers/python-webhelpers.tar.gz
tar -xf python-webhelpers.tar.gz
cd python-webhelpers
makepkg
sudo pacman -U --noconfirm python-webhelpers-*pkg.tar.*
cd ..

for p2pkg in paste-{deploy,script} repoze-lru routes web{ob,error,test} pylons
do
   wget https://aur.archlinux.org/packages/py/python2-${p2pkg}/python2-${p2pkg}.tar.gz
   tar -xf python2-${p2pkg}.tar.gz
   cd python2-${p2pkg}
   makepkg --asroot
   pacman -U python2-${p2pkg}-*pkg.tar.*
   cd ..
done

OpenChange Installation

Build and install OpenChange Server from AUR. We'll need to modify the PKGBUILD file specifically for mapiproxy and oscmanager, I've alearted the maintainer, but this might be beyond the scope of the maintainer's intentions):

sudo pacman -S base-devel wget
wget https://aur.archlinux.org/packages/op/openchange/openchange.tar.gz
tar -xf openchange.tar.gz
cd openchange
rm PKGBUILD
cat > PKGBUILD << "EOF"
# Maintainer: Michael Hansen <zrax0111 gmail com>
# Contributor: DJ Lucas <dj@linuxfromscratch.org>
# Contributor: ngoonee <ngoonee.talk@gmail.com>
# Contributor: Adam Russell <adamlr6+arch@gmail.com>
##### THIS IS NOT QUITE READY YET #####
##### DO NOT USE #####
pkgname=openchange
_codename=QUADRANT
_dlid=220
pkgver=2.0
pkgrel=4
pkgdesc="A portable, open source implementation of Microsoft Exchange server \
and Exchange protocols.  This package was originally created to support \
evolution-mapi and may not work for any other purpose."
arch=('i686' 'x86_64')
url="http://www.openchange.org"
license=('GPL3')
depends=('samba>=4.0.2-1' 'libical' 'sqlite3' 'file' 'boost' 'python2')
makedepends=('ccache' 'python2' 'docbook-xsl' 'libxslt')
options=(!makeflags)
# Releases are mirrored at http://tracker.openchange.org/projects/openchange/files
source=("http://tracker.openchange.org/attachments/download/${_dlid}/${pkgname}-${pkgver}-${_codename}.tar.gz"
        "http://pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11-py2.7.egg")

sha256sums=('fa9032853104a72e939bf972ccc3805000c1c40957f2905222a7f2665f05acd7'
            '0d58908ff49d88391082f701c4baa43f1246abde920a5f91ce78edcc1aa67262')

build() {
    cd ${srcdir}/${pkgname}-${pkgver}-${_codename}

    PYTHON_CALLERS="$(find ${srcdir}/${pkgname}-${pkgver}-${_codename} -name '*.py')
                    $(find ${srcdir}/${pkgname}-${pkgver}-${_codename} -name 'configure.ac')
                    setup/openchange_newuser setup/openchange_provision
                    mapiproxy/services/web/rpcproxy/rpcproxy.wsgi"
    sed -i -e "s|/usr/bin/env python$|/usr/bin/env python2|" \
           -e "s|python-config|python2-config|" \
           -e "s|bin/python|bin/python2|" \
        ${PYTHON_CALLERS}

    # Fix linking of boost_thread in autoconf test
    sed -i -e "s|-lboost_thread\$BOOST_LIB_SUFFIX|-lboost_thread\$BOOST_LIB_SUFFIX -lboost_system\$BOOST_LIB_SUFFIX|" \
        configure.ac

    export PYTHON=/usr/bin/python2

    export PKG_CONFIG_PATH="/usr/samba/lib/pkgconfig:/usr/lib/pkgconfig"
    ./autogen.sh
    ./configure --prefix=/usr --sbindir=/usr/bin --enable-pymapi
    make FLEX=/usr/bin/flex BISON=/usr/bin/bison || return 1

    # Build rpcproxy
    cd mapiproxy/services/web/rpcproxy
    ./setup.py build
    cd ../../../../

    # Build ocsmanager
    cd mapiproxy/services/ocsmanager
    cp ${srcdir}/setuptools-0.6c11-py2.7.egg .
    sed 's@\"0.6c9@\"0.6c11@' -i ez_setup.py
    sed "s@^md5_data = {@md5_data = {\n    'setuptools-0.6c11-py2.7.egg': 'fe1f997bc722265116870bc7919059ea',@" -i ez_setup.py
    PYTHONPATH="${pkgdir}/usr/lib/python2.7/site-packages" \
        python2.7 setup.py build
}

package() {
    _pyver=`python2 -c 'import sys; print(sys.version[:3])'`

    cd ${srcdir}/${pkgname}-${pkgver}-${_codename}
    make DESTDIR="$pkgdir/" install

    # Install services
    cp -R mapiproxy/services ${pkgdir}/usr/lib/openchange

    # Install rpcproxy python scripts
    cd mapiproxy/services/web/rpcproxy
    ./setup.py install --prefix=${pkgdir}/usr
    install -vdm755 ${pkgdir}/etc/httpd/conf/extra
    install -vm644 rpcproxy.conf ${pkgdir}/etc/httpd/conf/extra/
    cd ../../../../

    # Install ocsmanager python scripts
    cd mapiproxy/services/ocsmanager
    PYTHONPATH="${pkgdir}/usr/lib/python2.7/site-packages" \
        python2.7 setup.py install --prefix=${pkgdir}/usr
    sed '/IfMod/s/\.c//' -i ocsmanager-apache.conf
    install -vm644 ocsmanager-apache.conf ${pkgdir}/etc/httpd/conf/extra/

    cd ${pkgdir}/usr/lib/
    ln -s libmapi.so libmapi.so.0
    ln -s libocpf.so libocpf.so.0

    find ${pkgdir}/usr/lib/python${_pyver}/site-packages/ -name '*.py' | \
         xargs sed -i "s|#!/usr/bin/env python$|#!/usr/bin/env python2|"
}
EOF
makepkg
sudo pacman -U openchange-2.0-4*.pkg.tar.gz

SOPE Installation

Build and install SOPE from AUR:

wget https://aur.archlinux.org/packages/so/sope/sope.tar.gz
tar -xf sope.tar.gz
cd sope
makepkg
sudo pacman -U sope-2.0.7-2*.pkg.tar.xz
cd ..

SOGo Installation

Build and install SOGo and SOGo-OpenChange from AUR (Please note that the maintainer of the SOGo package is aware of the changes needed for this to work and has expressed interest in making those changes, but I need to do additional testing first to make sure we can do this in a non-split package due to AUR restrictions. I am the hold-up on this, not the current maintainer):

wget https://aur.archlinux.org/packages/so/sogo/sogo.tar.gz
tar -xf sogo.tar.gz
cd sogo
rm -f PKGBUILD
cat > PKGBUILD << "EOF"
# Maintainer: Steven Hiscocks <steven [at] hiscocks [dot] me [dot] uk>
# Contributor:  Andre Wayand <aur-sogo [at] awayand [dot] sleepmail [dot] com>
# Contributor: DJ Lucas <dj [at] linuxfromscratch [dot] org>
pkgname=('sogo' 'sogo-openchange')
pkgver=2.0.7
pkgrel=3
pkgdesc="groupware server built around OpenGroupware.org (OGo) and the SOPE application server"
arch=('i686' 'x86_64')
url="http://www.sogo.nu/"
license=('GPL')
makedepends=('gcc-objc' 'sope=2.0.7' 'gnustep-base' 'libmemcached' 'memcached')
source=(
  http://www.sogo.nu/files/downloads/SOGo/Sources/SOGo-${pkgver}.tar.gz
  sogo_configure.patch
  sogo.logrotate.d
  sogo.service
  sogo.tmpfiles
)
md5sums=('c666706e006a1b4312789cddce5da2ee'
         '5fbd694ee94639697c5f635013d89327'
         '6e9809e4373a6cc674c286ba8d24571c'
         'c037d83ac8f7632a7de0d7e3ffb19bea'
         '04dc24e79e11b62933843cd1f9f60792')

prepare() {
  cd "$srcdir/SOGo-${pkgver}"
  patch configure ../sogo_configure.patch
}

build() {
  cd "$srcdir/SOGo-${pkgver}"
  #Fix MailViewer (not currently neeeded, but should be fixed upstream)
  sed 's@Mailer/SOGoMailBodyPart.h@SoObjects/Mailer/SOGoMailBodyPart.h@' \
      -i `grep -Rl "<Mailer/SOGoMailBodyPart.h>"`
  #Fix MailViewer (not currently neeeded, but should be fixed upstream)
  sed -e 's@<MailPartViewers@"../MailPartViewers@' \
      -e 's@Context.h>@Context.h"@' \
      -i UI/MailerUI/UIxMailView.m
  ./configure --prefix=$(gnustep-config --variable=GNUSTEP_SYSTEM_ROOT) --disable-debug
  make
  cd "${srcdir}/SOGo-${pkgver}/OpenChange"
  #Set python interpreter to python2
  sed 's@/usr/bin/python@/usr/bin/python2@' \
      -i `grep -R -e "/usr/bin/python" | \
          grep -v "/usr/bin/python2" | \
          cut -d ":" -f 1`
  sed 's@22\.6@2.7@' -i GNUmakefile
  #Remove -Werror
  sed 's@-Werror @@' -i GNUmakefile
  #Fix SoObjects include directory
  sed 's@-I../S@-I.. -I../S@' -i GNUmakefile
  make
}

package_sogo() {

  pkgdesc="groupware server built around OpenGroupware.org (OGo) and the SOPE application server"
  depends=('sope=2.0.7' 'gnustep-base' 'libmemcached' 'memcached')
  backup=(etc/logrotate.d/sogo etc/sogo/sogo.conf etc/httpd/conf/extra/SOGo.conf)
  install=sogo.install
  options=('!strip')
  optdepends=(
        'postgresql: run database server for sogo locally'
        'mariadb: run database server for sogo locally'
        'openldap: run directory server for sogo locally'
        'postfix: run smtp server for sogo locally'
        'dovecot: run imap server for sogo locally'
        'courier-imap: run imap server for sogo locally'
        'nginx: webserver to provide web interface locally'
        'apache: webserver to provide web interface locally'
        'lighttpd: webserver to provide web interface locally'
        'funambol: sync mobile devices with sogo contacts, events, tasks via SyncML')

  cd "${srcdir}/SOGo-${pkgver}"
  make install DESTDIR="${pkgdir}" GNUSTEP_SYSTEM_ADMIN_TOOLS="/usr/bin"
  install -D -m 0644 "${srcdir}/sogo.logrotate.d" "${pkgdir}/etc/logrotate.d/sogo"
  install -D -m 0644 "${srcdir}/sogo.service" "${pkgdir}/usr/lib/systemd/system/sogo.service"
  install -D -m 0644 "${srcdir}/sogo.tmpfiles" "${pkgdir}/usr/lib/tmpfiles.d/sogo.conf"
  install -D -m 0600 "${srcdir}/SOGo-${pkgver}/Scripts/sogo.conf" "${pkgdir}/etc/sogo/sogo.conf"
  install -d "${pkgdir}/var/log/sogo"
  install -d "${pkgdir}/etc/httpd/conf/extra"
  install -m644 "${srcdir}/SOGo-${pkgver}/Apache/SOGo.conf" "${pkgdir}/etc/httpd/conf/extra/SOGo.conf"
}

package_sogo-openchange() {

  pkgdesc="SOGo connector for OpenChange Server"
  depends=('sogo' 'openchange')
  options=('!strip')

  cd "${srcdir}/SOGo-${pkgver}/OpenChange"
  make install DESTDIR="${pkgdir}" GNUSTEP_SYSTEM_ADMIN_TOOLS="/usr/bin"
}
EOF
makepkg
sudo pacman -U sogo-2.0.7-3*.pkg.tar.xz
sudo pacman -U sogo-openchange-2.0.7-3*.pkg.tar.xz

Configuration

Initial OpenChange Configuration

Samba

Make a backup copy of your existing samba configuration

sudo cp /etc/samba/smb.conf{,.bak}

Append the following lines to [global] section of the /etc/samba/smb.conf file:

	# Begin OpenChange Server Configuration
	dcerpc endpoint servers = +epmapper, +mapiproxy, +dnsserver
	dcerpc_mapiproxy:server = true
	dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
	# End OpenChange Server configuration

OpenChange

Next, provision the database and create the openchange DB.

openchange_provision
openchange_provision --openchangedb

Enable mail for the first user (we'll use administrator):

openchange_newuser --create Administrator

Restart samba:

sudo systemctl restart samba

At this point, you should verify that all samba services are working as expected. Use the tests in the Samba 4 Active Directory Domain Controller guide in addition to testing RPC from a windows client (simply connect with RSAT tools or soemthing similar). If all is well, then continue. If not, restore the backup of the smb.conf until you can track down the problem.

Finally, verify that you can edit user properties. For this, we'll use ldbedit. Here you can directly modify user attributes. Relevant attributes are mail and proxyAddresses. The proxyAddress attributie labeled SMTP (as opposed to smtp) is the default mail address. If using internal and exteranal domains, you will need to set SMTP to external address as this will be the SMTP from address and envelope sender in outgoing messages. Replace vim in the following command with your preferred editor:

ldbedit -e vim -H /var/lib/samba/private/sam.ldb '(samaccountname=administrator)'

If you first followed the Samba 4 Active Directory Domain Controller article, you should see the following in the editor window (substituting internal.domain.tld with your domain's values):

...
mail: Administrator@internal.domain.tld
...
proxyAddresses: =EX:/o=First Organization/ou=First Administrative Group/cn=Recipients/cn=Administrator
proxyAddresses: smtp:postmaster@internal.domain.tld
proxyAddresses: X400:c=US;a= ;p=First Organizati;o=Exchange;s=Administrator
proxyAddresses: SMTP:Administrator@internal.domain.tld
...

It is important to change both the mail attribute (this is what we'll use for group expansion), and the primary SMTP address. Change it to the following (again, substitute appropriate values for internal.domain.tld):

...
mail: Administrator@domain.tld
...
proxyAddresses: =EX:/o=First Organization/ou=First Administrative Group/cn=Recipients/cn=Administrator
proxyAddresses: smtp:postmaster@internal.domain.tld
proxyAddresses: X400:c=US;a= ;p=First Organizati;o=Exchange;s=Administrator
proxyAddresses: smtp:Administrator@internal.domain.tld
proxyAddresses: SMTP:administrator@domain.tld
...

Initial SOGo Configuration

Apache httpd

Add SOGo to the Apache configuration:

su -
cat >> /etc/httpd/conf/httpd.conf << "EOF"
# Include SOGo configuration
include conf/extra/SOGo.conf
EOF
mkdir /var/run/sogo
chown sogo:sogo /var/run/sogo
systemctl enable sogo
systemctl start sogo
systemctl enable httpd
systemctl start httpd
exit

Open a browser and go to http://server.internal.domain.tld/SOGo/ but do not try to login just yet, just verify that you can connect and get the login screen.

PostGRE SQL

Initialize the default database and start postgresql (be sure to replace en_US.UTF-8 with the correct locale for your installation):

sudo mkdir -p /var/lib/postgres/data
sudo chown -R postgres:postgres /var/lib/postgres
su - postgres -c "initdb --locale en_US.UTF-8 -D '/var/lib/postgres/data'"
sudo systemctl enable postgresql
sudo systemctl start postgresql

Create the sogo user and the sogo DB for PostGRE (don't select a strong password for the sogo user, this is temporary and we'll change it later):

su - postgres
createuser --no-superuser --no-createdb --no-createrole --encrypted --pwprompt sogo
createdb -O sogo sogo
exit

Edit the access configuration for the openchange DB:

sudo cp /var/lib/postgres/data/pg_hba.conf{,.bak}
sudo sed \
    's/D$/D\n\n#Configuration for OpenChange/' \
    -i /var/lib/postgres/data/pg_hba.conf
sudo sed \
    's/ange$/ange\nhost\topenchange\topenchange\t127.0.0.1\/32\t\tmd5/' \
    -i /var/lib/postgres/data/pg_hba.conf
sudo chown postgres:postgres /var/lib/postgres/data/pg_hba.conf{,.bak}
sudo systemctl restart postgresql

SOGo

Configure SOGo defaults with the following commands (be certain to replace REGION/LOCALITY, SOGOPASSWORD, SAMBAADMINPASSWORD, and dc=internal,dc=domain,dc=tld with approproptiate values):

su - sogo -s /bin/bash
defaults write sogod SOGoTimeZone "REGION/LOCALITY"
defaults write sogod OCSFolderInfoURL "postgresql://sogo:SOGOPASSWORD@localhost:5432/sogo/sogo_folder_info"
defaults write sogod SOGoProfileURL "postgresql://sogo:SOGOPASSWORD@localhost:5432/sogo/sogo_user_profile"
defaults write sogod OCSSessionsFolderURL "postgresql://sogo:SOGOPASSWORD@localhost:5432/sogo/sogo_sessions_folder"
defaults write sogod OCSEMailAlarmsFolderURL "postgresql://sogo:SOGOPASSWORD@localhost:5432/sogo/sogo_alarm_folder"
defaults write sogod SOGoUserSources '({CNFieldName = displayName; IDFieldName = cn; UIDFieldName = sAMAccountName; IMAPHostFieldName =; baseDN = "cn=Users,dc=internal,dc=domain,dc=tld"; bindDN = "cn=Administrator,cn=Users,dc=internal,dc=domain,dc=tld"; bindPassword = "SAMBAADMINPASSWORD"; canAuthenticate = YES; displayName = "Shared Addresses"; hostname = "localhost"; id = public; isAddressBook = YES; port = 389;})'
defaults write sogod WONoDetach NO
defaults write sogod WOLogFile /var/log/sogo/sogo.log
defaults write sogod WOPidFile /var/run/sogo/sogo.pid
exit

Next, edit the sogo configuration file, /etc/httpd/conf/extra/SOGo.conf, and comment out the following lines for testing (until your SSL certs are in place and configuration is complete):

## adjust the following to your configuration
#  RequestHeader set "x-webobjects-server-port" "443"
#  RequestHeader set "x-webobjects-server-name" "yourhostname"
#  RequestHeader set "x-webobjects-server-url" "https://yourhostname"

Give the root user the GNUStep configuration for the sogo user:

sudo ln -s /etc/sogo/GNUStep /root/GNUStep

Initial Postfix Configuration

Basic Configuratoin

Create a minimal Postfix configuration. Replace server.internal.domain.tld with a valid internal FQDN):

sudo postconf -e myhostname=server.internal.domain.tld
sudo postconf -e mydestination=localhost

If this server will be accessible from the internet, set the HELO/EHLO values to match the FQDN as seen from the internet (repalce mail.domain.tld):

sudo postconf -e smtp_helo_name=mail.domain.tld
sudo postconf -e smtpd_banner='$smtp_helo_name ESMTP $mail_name'

Enable and start Postfix:

sudo systemctl enable postfix
sudo systemctl start postfix

Virtual User Configuration

Create a vmail user and set up Postfix to use it:

sudo groupadd -g 5000 vmail
sudo useradd -u 5000 -g vmail -s /sbin/nologin -d /home/vmail -m vmail
sudo chmod 750 /home/vmail
sudo postconf -e virtual_minimum_uid=5000
sudo postconf -e virtual_uid_maps=static:5000
sudo postconf -e virtual_gid_maps=static:5000
sudo postconf -e virtual_mailbox_base=/home/vmail
sudo postfix reload

LDAP Configuration

Next we need to tell Postfix how to lookup users. To do this, you will need to create an unprivileged user to use for LDAP lookups (select a suitably strong password, 63 alpha-numeric various case should be good):

sudo samba-tool user create ldap --description="Unprivileged user for LDAP lookups"

Now, create a LDAP alias and group maps for postfix (replace {,internal.}domain.tld and dc=internal, dc=domain, dc=tld with appropriate values):

cat > ldap-alias.cf << "EOF"
# Directory settings
server_host = 127.0.0.1
search_base = dc=internal,dc=domain,dc=tld
scope = sub
version = 3

# User Binding
bind = yes
bind_dn = cn=ldap,cn=users,dc=internal,dc=domain,dc=tld
bind_pw = axhnTc2LGdnUKQ80cWjWzZBR79SkgAQ1uLxv94M8EDosDoPBqD4bEEvJ1XvpwI7

# Filter
query_filter = (&(objectclass=person)(proxyAddresses=smtp:%s))
result_attribute = samaccountname
result_format = %s@internal.domain.tld
EOF

Create the group map:

sed -e '/^query/d' \
    -e '/^result/d' \
    -e '/format/d' \
    ldap-alias.cf > ldap-group.cf
echo "query_filter = (&(objectclass=group)(mail=%s))" >> ldap-group.cf
echo "special_result_attribute = member" >> ldap-group.cf
echo "leaf_result_attribute = mail" >> ldap-group.cf

Move them into place:

sudo mv ldap-{alias,group}.cf /etc/postfix
sudo chown root:root /etc/postfix/ldap-{alias,group}.cf
sudo chmod 0644 /etc/postfix/ldap-{alias,group}.cf

Next test our lookup maps for users (groups have not yet been created) (substitue {,internal.}domain.tld):

postmap -q administrator@domain.tld ldap:/etc/postfix/ldap-alias.cf
postmap -q administrator@internal.domain.tld ldap:/etc/postfix/ldap-alias.cf

You should receive the following output for both commands:

Administrator@internal.domain.tld

Append any other hosted domains to the first command below, add the maps, and then reload the Postfix configuration:

sudo postconf -e virtual_mailbox_domains="domain.tld, internal.domain.tld"
sudo postconf -e virtual_alias_maps="ldap:/etc/postfix/ldap-alias.cf, ldap:/etc/postfix/ldap-group.cf"
sudo postfix reload

At this point, Dovecot will need to be configured before completing the Postfix configuration as Dovecot SASL and LMTP will be used for athentication and delivery (respectively).

Dovecot Configuration

Basic Configuration

Create a very basic dovecot configuration:

sudo cp /etc/dovecot/dovecot.conf{.sample,}
sudo chmod 0644 /etc/dovecot/dovecot.conf
sudo chown root:root /etc/dovecot/dovecot.conf
cat > local.conf << "EOF"
auth_mechanisms = plain login
disable_plaintext_auth = no
ssl = no
auth_username_format = %n
mail_location = /home/vmail/%Lu/Maildir
EOF
sudo mv local.conf /etc/dovecot/conf.d
sudo chmod 0644 /etc/dovecot/conf.d/local.conf
sudo chown root:root /etc/dovecot/conf.d/local.conf

Enable and start Dovecot:

sudo systemctl enable dovecot
sudo systemctl start dovecot

LDAP Configuration

Add the LDAP lookup configuation:

cat > ldap.conf << "EOF"
passdb ldap {
    driver = ldap
    args = /etc/dovecot/dovecot-ldap-passdb.conf
}
userdb ldap {
    driver = ldap
    args = /etc/dovecot/dovecot-ldap-userdb.conf
}
EOF

sudo mv ldap.conf /etc/dovecot/conf.d
sudo chmod 0644 /etc/dovecot/conf.d/ldap.conf
sudo chown root:root /etc/dovecot/conf.d/ldap.conf

Add the LDAP user and password configurations (replace dc=internal,dc=domain,dc=tld and INTERNAL with appropropriate values):

cat > dovecot-ldap-passdb.conf << "EOF"
hosts = localhost
auth_bind = yes
auth_bind_userdn = INTERNAL\%u
ldap_version = 3
base = dc=internal,dc=domain,dc=tld
scope = subtree
deref = never
pass_filter = (&(objectClass=person)(sAMAccountName=%u)(mail=*))
EOF
cat > dovecot-ldap-userdb.conf << "EOF"
hosts = localhost
dn = cn=ldap,cn=Users,dc=internal,dc=domain,dc=tld
dnpass = axhnTc2LGdnUKQ80cWjWzZBR79SkgAQ1uLxv94M8EDosDoPBqD4bEEvJ1XvpwI7
ldap_version = 3
# The base must be cn=Users for OpenChange ATM...future
base = cn=Users,dc=internal,dc=domain,dc=tld
user_attrs = =uid=5000,=gid=5000,=home=/home/vmail/%Lu,=mail=maildir:/home/vmail/%Lu/Maildir/
user_filter = (&(objectClass=person)(sAMAccountName=%u)(mail=*))

# Attributes and filter to get a list of all users
iterate_attrs = sAMAccountName=user
iterate_filter = (objectClass=person)
EOF
sudo mv dovecot-ldap-{pass,user}db.conf /etc/dovecot
sudo chown root:root /etc/dovecot/dovecot-ldap{pass,user}db.conf
sudo chmod 0600 /etc/dovecot/dovecot-ldap-userdb.conf
sudo chmod 0644 /etc/dovecot/dovecot-ldap-passdb.conf

Create the SASL configuation:

cat > sasl.conf << "EOF"
service auth {
    unix_listener /var/spool/postfix/private/auth {
        mode = 0660
        user = postfix
        group = postfix
     }
}
EOF
sudo mv sasl.conf /etc/dovecot/conf.d
sudo chmod 0644 /etc/dovecot/conf.d/sasl.conf
sudo chown root:root /etc/dovecot/conf.d/sasl.conf

Reload Dovecot for the configuration to take effect:

sudo dovecot reload

Testing Dovecot Authentication

Open a telnet session and test (commands you enter are in bold, replace xxxxxxxx with your real password):

telnet localhost 143
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
* OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN AUTH=LOGIN] Dovecot ready.
. LOGIN Administrator xxxxxxxx
. 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
. LOGOUT
* BYE Logging out
. OK Logout completed.
Connection closed by foreign host.

If you've received anything other than OK, go back and double check your configuration before continuing.

LMTP Configuration

Create the LMTP configuration file:

cat > lmtp.conf << "EOF"
mail_location = /home/vmail/%Lu/Maildir
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
  user = vmail
}

protocol lmtp {
  postmaster_address = postmaster@domain.tld
}
sudo mv lmtp.conf /etc/dovecot/conf.d
sudo chown root:root /etc/dovecot/conf.d/lmtp.conf
sudo chmod 0644 /etc/dovecot/conf.d/lmtp.conf
sudo dovecot reload

TLS Configuration

Put your certificate files into place and create the TLS configuration file (adjust paths and names as necessary). The keyfile should be owned by root with 0400 permissions. Any intermediate certificates should be concatenated after the public cert.:

cat > tls.conf << "EOF"
ssl = yes
ssl_cert = </etc/dovecot/ssl/host.domain.tld.pem
ssl_key = </etc/dovecot/ssl/host.domain.tld.key
EOF
sudo mv tls.conf /etc/dovecot/conf.d/
sudo chown root:root /etc/dovecot/conf.d/tls.conf
sudo chmod 644 /etc/dovecot/conf.d/tls.conf

Remove the earlier explicitly defined values from local.conf and reload Dovecot:

sudo sed -e '/^ssl/d' -e '/disable_plaintext/s/no/yes/' \
     -i /etc/dovecot/conf.d/local.conf
sudo dovecot reload

Postfix Final configuration

SASL Configuration

Modify the default smtpd instance:

sudo postconf -e smtpd_sasl_type=dovecot
sudo postconf -e smtpd_sasl_path=private/auth
sudo postconf -e smtpd_sasl_auth_enable=yes
sudo postconf -e smtpd_relay_restrictions="permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination"

LMTP Configuration

Use dovecot LMTP for delivery:

postconf -e virtual_transport=lmtp:unix:private/dovecot-lmtp

TLS Configuration

If you intend to use STARTTLS (as you should), enable the mail submission port and restrict to authenticated clients. Edit the following lines in /etc/postfix/master.cf (replace internal.domain.tld):

submission inet n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
  -o smtpd_sasl_security_options=noanonymous
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o smtpd_sender_login_maps=ldap:/etc/postfix/ldap-sender.cf
  -o smtpd_sender_restrictions=reject_sender_login_mismatch
  -o smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject

Add your certificates. If you intend to chroot postfix (not discussed in this guide, see here), these need to be placed in the postfix configuration directory as opposed to the default /etc/ssl/private directory. Additionally, any intermediate certs should be concatenated with the public cert being first in the chain and the key file should be owned by root with 0400 permission mode:

sudo postconf -e smtpd_tls_key_file=/etc/postfix/ssl/mail.domain.tld.key
sudo postconf -e smtpd_tls_cert_file=/etc/postfix/ssl/mail.domain.tld.pem

Create a map to verify addresses to authenticated users:

cat > ldap-sender.cf << "EOF"
# Directory settings
server_host = localhost
search_base = dc=internal,dc=lucasit,dc=com
version = 3
scope = sub

# User Binding
bind = yes
bind_dn = cn=ldap,cn=Users,dc=internal,dc=lucasit,dc=com
bind_pw = axhnTc2LGdnUKQ80cWjWzZBR79SkgAQ1uLxv94M8EDosDoPBqD4bEEvJ1XvpwI7

# Filter
query_filter = (&(objectclass=person)(proxyAddresses=smtp:%s))
leaf_result_attribute = proxyAddresses
result_attribute = sAMAccountName
EOF
sudo mv ldap-sender.cf /etc/postfix
sudo chown root:root /etc/postfix/ldap-sender.cf
sudo chmod 0640 /etc/postfix/ldap-sender.cf

If you'd like to enable TLS on the default SMTP port, you should make it optional. If you make it required, you will not be able to receive mail from many hosts on the internet.

sudo postconf -e smtpd_tls_security_level=may

Reload postfix to apply the configuration changes:

sudo postfix reload

Testing the Postfix SASL Configuration

Begin by getting a base64 encoded version of you username and password (replace xxxxxxxx with your real password):

echo -ne '\000Administrator\000xxxxxxxx' | openssl base64

You should receive output similar to the following:

AEFkbWluaXN0cmF0b3IAeHh4eHh4eHg=

Now, open a telnet session and test (commands you enter are in bold, replace host.domain.tld with your real external FQDN and AEFkbWluaXN0cmF0b3IAeHh4eHh4eHg= with the result of the previous command):

telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 host.domain.tld ESMTP Postfix
ehlo host.domain.tld
250-mail.lucasit.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH PLAIN AEFkbWluaXN0cmF0b3IAeHh4eHh4eHg=
235 2.7.0 Authentication successful
quit
221 2.0.0 Bye
Connection closed by foreign host.

If you've gotten anything other than a 235 message, something is wrong and you should troubleshoot now rather than later.

At ths point, you have a fully functional mail server, though you'll probably want to lock it down a bit tighter (which isn't covered in this article). You could easily stop now and use any mail client you wish, howerver, you'd miss out on the fun of Outlook, RPC/HTTPS, calendar, the GAL, and contacts. This additional functionality is provided by SOGo and OpenChange...

SOGo Final configuration

PostgreSQL

Select a strong password (63 random alphanumeric characters is good) for the sogo user and change it now:

sudo su - postgres
psql
ALTER USER sogo WITH PASSWORD 'ZpRTOZuQiaKBma4YhvozRJwXCbLqhnRiurhvidB9A8vbjxEoNNjbAwHSbpBTobT';
\q
exit

SOGo

Create a suitable SOGo configuration file (replace items in bold with appropriate values):

cat > sogo.conf << "EOF"
{
    /* Database Configuration */
    SOGoProfileURL = "postgresql://sogo:ZpRTOZuQiaKBma4YhvozRJwXCbLqhnRiurhvidB9A8vbjxEoNNjbAwHSbpBTobT@localhost:5432/sogo/sogo_user_profile";
    OCSFolderInfoURL = "postgresql://sogo:ZpRTOZuQiaKBma4YhvozRJwXCbLqhnRiurhvidB9A8vbjxEoNNjbAwHSbpBTobT@localhost:5432/sogo/sogo_folder_info";
    OCSSessionsFolderURL = "postgresql://sogo:ZpRTOZuQiaKBma4YhvozRJwXCbLqhnRiurhvidB9A8vbjxEoNNjbAwHSbpBTobT@localhost:5432/sogo/sogo_sessions_folder";

    /* Mail */
    SOGoDraftsFolderName = Drafts;
    SOGoSentFolderName = Sent;
    SOGoTrashFolderName = Trash;
    SOGoIMAPServer = localhost;
    SOGoSieveServer = sieve://127.0.0.1:4190;
    SOGoSMTPServer = 127.0.0.1;
    SOGoMailDomain = internal.domain.tld;
    SOGoMailingMechanism = smtp;
    SOGoForceExternalLoginWithEmail = NO;
    SOGoMailSpoolPath = /var/spool/sogo;
    NGImap4ConnectionStringSeparator = "/";
    SOGoAppointmentSendEMailNotifications = NO;
    SOGoACLsSendEMailNotifications = NO;

   /* User Authentication */
    SOGoUserSources = (
        {
        type = ldap;
        CNFieldName = cn;
        IDFieldName = cn;
        UIDFieldName = sAMAccountName;
        baseDN = "dc=internal,dc=domain,dc=tld";
        bindDN = "cn=ldap,cn=Users,dc=internal,dc=domain,dc=tld";
        bindFields = (sAMAccountName);
        bindPassword = axhnTc2LGdnUKQ80cWjWzZBR79SkgAQ1uLxv94M8EDosDoPBqD4bEEvJ1XvpwI7;
        canAuthenticate = YES;
        displayName = "Active Directory";
        hostname = ldap://127.0.0.1:389;
        id = directory;
        isAddressBook = YES;
        }
    );

    /* Web Interface */
    SOGoPageTitle = SOGo;
    SOGoVacationEnabled = YES;
    SOGoForwardEnabled = YES;
    SOGoSieveScriptsEnabled = YES;

    /* General */
    SOGoLanguage = English;
    SOGoTimeZone = America/Chicago;
    SOGoCalendarDefaultRoles = (
        PublicDAndTViewer,
        ConfidentialDAndTViewer
    );
    SOGoSuperUsernames = (administrator);

    /* Debug */
    //SoDebugBaseURL = YES;
    //ImapDebugEnabled = YES;
    //LDAPDebugEnabled = YES;
    //SOGoDebugRequests = YES;
    //PGDebugEnabled = YES;
    //SOGoUIxDebugEnabled = YES;
    //WODontZipResponse = YES;

}
EOF
sudo mv sogo.conf /etc/sogo
sudo chown root:root /etc/sogo/sogo.conf
suod chmod 0600 /etc/sogo/sogo.conf
sudo rm /etc/sogo/GNUStep/Defaults/sogod.plist
sudo mkdir /var/spool/sogo
sudo chown sogo:sogo /var/spool/sogo
sudo chmod 700 /var/spool/sogo
sudo systemctl restart sogo

Now try and login to sogo by visiting http://server.internal.domain.tld/SOGo/ .

Apache

If all is well with SOGo without SSL, go ahead and enable SSL in httpd (modify paths and filenames as necessary):

sudo sed '/httpd-ssl.conf/s/#//' -i /etc/httpd/conf/httpd.conf
sudo sed -e '/^SSLCertificateFile/s@/etc/httpd/conf/server.crt@/etc/httpd/ssl/server.internal.domain.tld.pem@' \
         -e '/^SSLCertificateKeyFile/s@/etc/httpd/conf/server.key@/etc/httpd/ssl/server.internal.domain.tld.key@' \
         -i /etc/httpd/conf/extra/httpd-ssl.conf

Now go ahead and edit the /etc/httpd/conf/extra/SOGo.conf file and uncomment the following lines, edit to suit your site:

## adjust the following to your configuration
  RequestHeader set "x-webobjects-server-port" "443"
  RequestHeader set "x-webobjects-server-name" "server.internal.domain.tld"
  RequestHeader set "x-webobjects-server-url" "https://server.internal.domain.tld"

Restart apache for the changes to take effect

sudo systemctl restart httpd

Go ahead and go to the regular http page and it should redirect you to the https site.

OpenChange Additional Configuration

Testing OpenChange

If you'd like to test before adding the proxy, create a MAPI profile for testing (replace INTERNAL.DOMAIN.TLD and xxx.xxx.xxx.xxx with appropriate values):

mapiprofile --create -P testing -S -I xxx.xxx.xxx.xxx \
    --domain=INTERNAL --realm=INTERNAL.DOMAIN.TLD     \
    --username=Administrator --password='xxxxxxxx'

List the available profiles:

mapiprofile --list

Dump the test profile:

mapiprofile --dump -P testing

This profile can now be deleted, this was simply for testing purposes.

Adding OpenChange MAPIProxy and OCSManger to Apache

This is the part that glues it all together:

sudo echo "LoadModule wsgi_module modules/mod_wsgi.so" >> /etc/httpd/conf/httpd.conf 
sudo echo "include conf/extra/rpcproxy.conf" >> /etc/httpd/conf/httpd.conf
sudo echo "include conf/extra/ocsmanager-apache.conf" >> /etc/httpd/conf/httpd.conf
sudo systemctl restart httpd
sudo systemctl restart samba

What to do Next

...add entries here...