This is step by step guide for Centos 7. Server1 will be the Active node and Server2 will be the failover node. After failover when Server 1 comes back online all service will be restored to Server1.
A floating IP 10.21.202.110 will be used for the cluster config
To start with disable Firewall and Selinux on both servers and install prerequisites
#yum install vim wget bzip2 telnet pcs pacemaker corosync cman wget -y
Server 1
10.21.202.108
hostname: mail.example.com
Server 2
10.21.202.109
hostname: mail.example.com
Step 1: Make host file entries
Server1
$vim /etc/hosts
10.21.202.108 master1.example.com master1
10.21.202.109 master2.example.com master2
10.21.202.108 mail.example.com
Server2
$vim /etc/hosts
10.21.202.108 master1.example.com master1
10.21.202.109 master2.example.com master2
10.21.202.109 mail.example.com
Step 2: Install Mariadb On Both Servers.
The mysql root password and other user password should be the same on both servers in order for HA to work with iRedMail/Roundcube.
#yum install mariadb-server -y
Step 3: Start Mariadb Multi-Master Replication Between The Two Servers
Insert the following configuration for replication. Create the file and paste the below
Server1:
#vim /etc/my.cnf.d/repl.cnf
[mysqld]
server-id = 108
report_host = master1
log_bin = /var/log/mariadb/mariadb-bin
log_bin_index = /var/log/mariadb/mariadb-bin.index
relay_log = /var/log/mariadb/relay-bin
relay_log_index = /var/log/mariadb/relay-bin.index
Server2:
#vim /etc/my.cnf.d/repl.cnf
[mysqld]
server-id = 102
report_host = master2
log_bin = /var/log/mariadb/mariadb-bin
log_bin_index = /var/log/mariadb/mariadb-bin.index
relay_log = /var/log/mariadb/relay-bin
relay_log_index = /var/log/mariadb/relay-bin.index
Restart Mariadb on both servers and run the following commands to initialize Mariadb
#systemctl restart mariadb.service
#systemctl enable mariadb.service
# mysql_secure_installation
Set the same root password on both servers. Now login to mysql and create the replication user.
Server1:
#mysql -u root -p<pass>
> create user 'replusr'@'%' identified by '<password>';
> grant replication slave on *.* to 'replusr';
To check Master status
>show master status;
Make a note of bin file name and position
Server2:
#mysql -u root -p<pass>
> create user 'replusr'@'%' identified by '<password>';
> grant replication slave on *.* to 'replusr';
To start replication on Server 2
>stop slave;
>change master to master_host='master1', master_user='replusr', master_password='<pass>’,
master_log_file='<bin file name>', master_log_pos=<pos>;
>start slave;
To check status use the following command
>show slave status;
Now check master status in Server2 and get bin file name and position
>show master status;
Server1
>stop slave;
>change master to master_host='master2', master_user='replusr', master_password='<pass>',
master_log_file='<bin file name>', master_log_pos=<pos>;
>start slave;
>show slave status;
Now both servers have Mariadb installed and multi-master replication is enabled.
Step 4: Install Remi And EPEL Repo On Both Servers
#yum install epel-release -y
#rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
Now enable remi repo for php5.5 on both servers
#vim /etc/yum.repos.d/remi.repo
-----------------------------------------------------------
[remi-php55]
name=Remi's PHP 5.5 RPM repository for Enterprise Linux 7 - $basearch
#baseurl=http://rpms.remirepo.net/enterprise/7/php55/$basearch/
#mirrorlist=https://rpms.remirepo.net/enterprise/7/php55/httpsmirror
mirrorlist=http://rpms.remirepo.net/enterprise/7/php55/mirror
# NOTICE: common dependencies are in "remi-safe"
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi
--------------------------------------------------------------
Step 5: Install iRedMail With Openladap Backend On Server 1
Server 1:
#wget https://bitbucket.org/zhb/iredmail/downloads/iRedMail-0.9.6.tar.bz2
#tar xjvf iRedMail-0.9.6.tar.bz2
#cd iRedMail-0.9.6 && chmod +x iRedMail.sh
Note: Do not apply iRedMail's mysql settings
Step 6: Installing Calendar Plugin For RoundCube
#yum install composer -y
Comment this line in php.ini
#vim /etc/php.ini
;disable_functions=(.....)
#cd /tmp
#git clone https://git.kolab.org/diffusion/RPK/roundcubemail-plugins-kolab.git
#cd /tmp/roundcubemail-plugins-kolab/plugins
#mv calendar/ libcalendaring/ /var/www/roundcubemail/plugins/
#cd /var/www/roundcubemail/
#mv composer.json-dist composer.json
Now install dependancy for calendar plugin
#composer require "sabre/vobject" "~3.3.3"
Initialize the calendar database tables
# mysql -uroot -p<pass> roundcubemail < /var/www/roundcubemail/plugins/calendar/drivers/database/SQL/mysql.initial.sql
Enable the calendar plugin
#vim /var/www/roundcubemail/config/config.inc.php
Add 'calendar' to the list of active plugins:
$config['plugins'] = array((...) 'calendar', );
Step 7: Installing Skins For Roundcube
Harry Skin
#mkdir /root/skins
#cd /root/skins
#git clone https://github.com/beliys/harry.git
#cd harry
#rm -rf .git
Barry Skin
#cd /root/skins
#wget http://indexnl.com/barry.zip
#unzip barry.zip
#mv harry barry /var/www/roundcubemail/skins/
Step 8: Restart And Enable All Services
systemctl enable amavisd.service
systemctl enable fail2ban.service
systemctl enable nginx.service
systemctl enable php-fpm.service
systemctl enable uwsgi.service
systemctl enable mariadb.service
systemctl restart amavisd.service
systemctl restart fail2ban.service
systemctl restart nginx.service
systemctl restart php-fpm.service
systemctl restart uwsgi.service
systemctl restart mariadb.service
systemctl restart iredapd
Step 9: Integrate iRedMail And Roundcube With Active Directory
Create an account "vmail" in AD with a strong password. Password should be set to never expire.
Disable unused iRedMail special settings:
postconf -e virtual_alias_maps=''
postconf -e sender_bcc_maps=''
postconf -e recipient_bcc_maps=''
postconf -e relay_domains=''
postconf -e relay_recipient_maps=''
postconf -e sender_dependent_relayhost_maps=''
Add your mail domain name in
smtpd_sasl_local_domain
and virtual_mailbox_domains
:postconf -e smtpd_sasl_local_domain='example.com'
postconf -e virtual_mailbox_domains='example.com'
Change transport maps setting:
postconf -e transport_maps='hash:/etc/postfix/transport'
Enable AD query. Note: We will create these 3 files later.
- Verify SMTP senders
postconf -e smtpd_sender_login_maps='proxy:ldap:/etc/postfix/ad_sender_login_maps.cf'
- Verify local mail users
postconf -e virtual_mailbox_maps='proxy:ldap:/etc/postfix/ad_virtual_mailbox_maps.cf'
- Verify local mail lists/groups.
postconf -e virtual_alias_maps='proxy:ldap:/etc/postfix/ad_virtual_group_maps.cf'
- Create/edit file:
/etc/postfix/transport
.
example.com dovecot
Note:
dovecot
used here is a Postfix transport defined in /etc/postfix/master.cf
, used to deliver received emails to local user mailboxes.
Run
postmap
so that postfix can read it:# postmap hash:/etc/postfix/transport
- Create file:
/etc/postfix/ad_sender_login_maps.cf
:
server_host = ad.example.com
server_port = 389
version = 3
bind = yes
start_tls = no
bind_dn = vmail
bind_pw = password_of_vmail
search_base = cn=users,dc=example,dc=com
scope = sub
query_filter = (&(userPrincipalName=%s)(objectClass=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))
result_attribute= userPrincipalName
debuglevel = 0
- Create file:
/etc/postfix/ad_virtual_mailbox_maps.cf
:
server_host = ad.example.com
server_port = 389
version = 3
bind = yes
start_tls = no
bind_dn = vmail
bind_pw = passwd_of_vmail
search_base = cn=users,dc=example,dc=com
scope = sub
query_filter = (&(objectclass=person)(userPrincipalName=%s))
result_attribute= userPrincipalName
result_format = %d/%u/Maildir/
debuglevel = 0
Note: Here, we hard-code user's mailbox path in
[domain]/[username]/Maildir/
format (result_format
parameter). for example:example.com/postmaster/Maildir/
.- Create file:
/etc/postfix/ad_virtual_group_maps.cf
:
server_host = ad.example.com
server_port = 389
version = 3
bind = yes
start_tls = no
bind_dn = vmail
bind_pw = password_of_vmail
search_base = cn=users,dc=example,dc=com
scope = sub
query_filter = (&(objectClass=group)(mail=%s))
special_result_attribute = member
leaf_result_attribute = mail
result_attribute= userPrincipalName
debuglevel = 0
Note:
- If your user have email address in both
mail
anduserPrincipalName
, you will get duplicate result. Comment outleaf_result_attribute
line will fix it. - If your mail group account doesn't contain attribute
mail
anduserPrincipalName
, please tryquery_filter = (&(objectClass=group)(sAMAccountName=%u))
instead.
Also, we need to remove iRedAPD related settings in Postfix:
- Open Postfix config file
/etc/postfix/main.cf
- Remove setting
check_policy_service inet:127.0.0.1:7777
.
Verify LDAP query with AD in Postfix
We can now use command line tool
postmap
to verify AD integration in postfix. Before testing, we have to create two testing mail accounts first:- Create a mail user in AD. e.g.
user@example.com
. - Create a mail group in AD. e.g.
testgroup@example.com
, then assign mail useruser@example.com
as group member. - Query mail user account with below command:
# postmap -q user@example.com ldap:/etc/postfix/ad_virtual_mailbox_maps.cf
example.com/user/Maildir/
If nothing returned by the command, it means LDAP query doesn't get expected result. Please set
debuglevel = 1
file /etc/postfix/ad_virtual_mailbox_maps.cf
, then query again, it now will print detailed debug message. If you're not familiar with LDAP related info, please post the debug message in our online support forum to get help.
Verify sender login check:
# postmap -q user@example.com ldap:/etc/postfix/ad_sender_login_maps.cf
user@example.com
Verify mail group
# postmap -q testgroup@example.com ldap:/etc/postfix/ad_virtual_group_maps.cf
user@example.com
NOTE:
postmap
return nothing if:- mail group doesn't exist
- mail group doesn't have any members
Remove iRedAPD integration in Postfix
iRedAPD relies on iRedMail LDAP scheme, so it's useless if you integrate iRedMail with Active Directory. We should remove the integration in Postfix to save some system resource.
To disable iRedAPD, please read tutorial: Manage iRedAPD.
Enable Active Directory integration in Dovecot
To query AD instead of local LDAP server, we have to modify Dovecot config file
/etc/dovecot/dovecot-ldap.conf
like below:hosts = ad.example.com:389
ldap_version = 3
auth_bind = yes
dn = vmail
dnpass = passwd_of_vmail
base = cn=users,dc=example,dc=com
scope = subtree
deref = never
user_filter = (&(userPrincipalName=%u)(objectClass=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))
pass_filter = (&(userPrincipalName=%u)(objectClass=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))
pass_attrs = userPassword=password
default_pass_scheme = CRYPT
user_attrs = =home=/var/vmail/vmail1/%Ld/%Ln/Maildir/,=mail=maildir:/var/vmail/vmail1/%Ld/%Ln/Maildir/
Restart dovecot service to make it work.
Note: we don't have per-user quota limit here, you can set a hard-coded quota for all users in
/etc/dovecot/dovecot.conf
. For example:plugin {
[... omit other settings here ...]
# Format: integer number + M/G/T (M -> MB, G -> GB, T -> TB).
quota_rule = *:storage=1G
}
Now use command
telnet
to verify AD query after restarted Dovecot service:# telnet localhost 143 # <- Type this
* OK [...] Dovecot ready.
. login user@example.com password_of_user # <- Type this. Do not miss the dot in the beginning
. OK [...] Logged in
^] # <- Quit telnet with "Ctrl+]", then type 'quit'.
Note: Do NOT miss the dot character before
login
command. if it returns Logged in
, then dovecot + AD works.Step 10: Integrate Roundcube with AD for address book lookup
# vim /var/www/roundcubemail/config/config.inc.php
Delete all lines after the plugin config line and insert the below.
Modify the connection and user details as per the requirement
-----------------------------------------------------------------------------
#
# "sql" is personal address book stored in roundcube database.
# "global_ldap_abook" is the new LDAP address book for AD, we will create it below.
#
$config['autocomplete_addressbooks'] = array("sql", "global_ldap_abook");
# Enable setting below if Roundcube returns 'user@127.0.0.1' as email address
#$config['mail_domain'] = '%d';
#
# Global LDAP Address Book with AD.
#
$config['ldap_public']["global_ldap_abook"] = array(
'name' => 'Global Address Book',
'hosts' => array("ad.example.com"), // <- Set AD hostname or IP address here.
'port' => 389,
'use_tls' => false, // <- Set to true if you want to use LDAP over TLS.
'ldap_version' => '3',
'network_timeout' => 10,
'user_specific' => false,
'base_dn' => "dc=example,dc=com", // <- Set base dn in AD
'bind_dn' => "vmail", // <- bind dn
'bind_pass' => "<pass>", // <- bind password
'writable' => false, // <- Do not allow mail user write data back to AD.
'search_fields' => array('mail', 'cn', 'sAMAccountName', 'displayname', 'sn',
givenName'),
// mapping of contact fields to directory attributes
'fieldmap' => array(
'name' => 'cn',
'surname' => 'sn',
'firstname' => 'givenName',
'title' => 'title',
'email' => 'mail:*',
'phone:work' => 'telephoneNumber',
'phone:mobile' => 'mobile',
'phone:workfax' => 'facsimileTelephoneNumber',
'street' => 'street',
'zipcode' => 'postalCode',
'locality' => 'l',
'department' => 'departmentNumber',
'notes' => 'description',
'photo' => 'jpegPhoto',
),
'sort' => 'cn',
'scope' => 'sub',
'filter' => "(|(&(objectclass=group)(!(groupType:1.2.840.113556.1.4.803:=2147483648)))(&(objectclass=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2))))",
'fuzzy_search' => true,
'vlv' => false, // Enable Virtual List View to more
// efficiently fetch paginated data
// (if server supports it)
'sizelimit' => '0', // Enables you to limit the count of
// entries fetched. Setting this to 0
// means no limit.
'timelimit' => '0', // Sets the number of seconds how long
// is spend on the search. Setting this
// to 0 means no limit.
'referrals' => false, // Sets the LDAP_OPT_REFERRALS option.
// Mostly used in multi-domain Active
// Directory setups
);
-------------------------------------------------------------------------------------
Save and close the file
Step 11: Now Drop all databases created mysq iRedmail in Server 1
Step 12: Install iRedmail in server 2 with openLDAP backend
Note: copy config file from server 1 to server 2 before starting the installation. The config file contains the random db user passwords created for installation. They should be the same on both servers.
#scp /root/iRedMail-0.9.6/config root@server2:/root/iRedMail-0.9.6/config
Install iredmail with openldap backend and install the calendar plugin just like how we did for server1. Install the skins as well
Step 13: Install unision on both server.
We will use unison to sync email, postfix and dovecot config files#yum install ocaml ocaml-camlp4-devel ctags ctags-etags -u
#cd ~
#wget http://www.seas.upenn.edu/~bcpierce/unison//download/releases/stable/unison-2.40.102.tar.gz
#tar xvfz unison-2.40.102.tar.gz
#cd unison-2.40.102
#make
#sudo cp -v unison /usr/local/sbin/
# sudo cp -v unison /bin/unison
Now enable shell access for vmail user and enable passwordless SSH for this user between the two servers. Emails are stored in /var/vmail/vmail1 directory and user "vmail" is the owner of the directory
On Server 1
Switch to user vmail and create the below crontab entry to sync mails across the two servers
#crontab -e
*/2 * * * * /bin/unison -batch /var/vmail/vmail1 ssh://master2//var/vmail/vmail1
Now as root user
#crontab -e
0 5 * * * /bin/unison -batch /etc/postfix ssh://master2//etc/postfix
0 6 * * * /bin/unison -batch /etc/dovecot ssh://master2//etc/dovecot
Step 14: Cluster configuration
On Server 1 and 2 set the same password for hacluster user
#passwd hacluster
Start PCSD service and enable it at startup
#systemctl start pcsd
#systemctl enable pcsd
#mkdir /etc/cluster
Server1
Now on server1 authorize the cluster nodes
#pcs cluster auth master1 master2
Now create the cluster and start the cluster
#pcs cluster setup --name MAILCLUSTER master1 master2
#pcs cluster start --all
Now disable STONITH and quorum as it is not required for a two node setup
#pcs property set stonith-enabled=false
#pcs property set no-quorum-policy=ignore
Now add the resources. We need a virtual IP
#pcs resource create VirtualIP ocf:heartbeat:IPaddr2 ip=x.x.x.x cidr_netmask=24 op monitor interval=30s
Now we need a mail alert when ever failover happens
Now we need a mail alert when ever failover happens
# pcs resource create MailTo ocf:heartbeat:MailTo email="admin@example.com" subject="MailServerFailOver" op monitor timeout="10" interval="10"
Now add postfix and dovecot as resources
# pcs resource create POSTFIX ocf:heartbeat:postfix op monitor interval=30s
# pcs resource create DOVECOT systemd:dovecot op monitor interval=30s
Now set a constraint so that they all run on the same server
# pcs constraint colocation set VirtualIP MailTo POSTFIX DOVECOT
Server1 is going to act as the active server and so we need to make sure that the services sticks to server1
# pcs constraint location VirtualIP prefers master1
# pcs constraint location MailTo prefers master1
# pcs constraint location DOVECOT prefers master1
# pcs constraint location POSTFIX prefers master1
Now stop and start the cluster
# pcs cluster stop --all
# pcs cluster start --all
Now we have iRedmail with High Availability