Dear visitor, in case we do not cover a topic you are looking for, then feel free to ask in our freshly created forum for IT-professionals for a solution. We hope our visitors can help you out with your questions. Have a good one. ~ Tom.

How to install|migrate sendmail / procmail / spamassassin / dovecot / opendkim / bind / apache / mariadb / egroupware / bind on|from CentOS7 to Rocky Linux 8

Rocky Linix 8.5 Mailserver

We where already prepared to switch our servers from CentOS 7 to 8 but our project stopped immediately after we heard about the abrupt end of CenOS – so we where looking around for new solutions. We evaluated Ubuntu, OpenMandriva, Slackware, FreeBSD and other Linux/Unix distros. Before we made a descision in which direction we move, we waited for the first release of Rocky Linux 8. Rocky Linux was announced as the official unofficial successor of CentOS, the project was created by the founder of CentOS. Some weeks ago the first stable version compatible to CentOS 8 / RHEL 8 was released and we started our migration project from scratch.

We use many applications on CentOS servers but the most imporant system is our e-mail/groupware server. In our mailserver we use following applications:

Sendmail (SMTP Server)
Procmail (Mail rules)
Spamassassin (Anti-Spam)
Dovecot (IMAP/POP3 Server)
OpenDKIM (DKIM signatures)
BIND (DNS Server)
Apache (http reverse proxy)
MariaDB (Database for eGroupware and other databases)
eGroupware (Groupware, CalDAV, CardDAV)
Docker (for eGroupware)

In the next chapters i document how we migrated our CentOS 7 installation to a fresh Rocky Linux 8 server.

Preparation

Download

Download Rocky Linux 8: https://rockylinux.org/de/download

Requirements

Virtual Server requirements for our environment:

– 4 vCPUs
– 12 GB RAM
– 1x 750 GB HDD
– 1x VMXNET3 Network Adapter

Disk Layout

Total Capacity: 750 GB

Mountpoint      Capacity Filesystem Device type
*************************************************************
/home           300 GB   xfs        LVM
/var/spool/mail 300 GB   xfs        LVM
/               130 GB   xfs        LVM
/boot           3.99 GB  xfs        Standard
SWAP            16 GB    swap       LVM

Software selection

[x] Server with GUI
    [x] Debugging Tools
    [x] Guest Agents
    [x] Performance Tools
    [x] Graphical Administation Tools
    [x] Security Tools
    [x] System Tools
[x] Workstation
    [x] Legacy UNIX Compatibility
[x] Custom Operating System
    [x] Development Tools

Hint: During the installation, create a local user called “administrator”.

Inital configuration

Disable SELinux

Disable SELinux and reboot your system afterwards. Hint: Make sure this configuration fits your security requirements.

[root@mail ~]# cat /etc/selinux/config

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of these three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted

[root@mail ~]# shutdown -r now

Enable Power Tools, install Delta RPMs and enable EPEL repo

[root@mail ~]# dnf config-manager --set-enabled powertools
[root@mail ~]# yum install epel-release [root@mail ~]# yum install drpm

Update your system

Make sure you have the lastet version installed and reboot your system afterwards.

[root@mail ~]# yum update
[root@mail ~]# shutdown -r now

Disable Firewall

We don’t want to enable the Linux firewall, so we disable the service.

[root@mail ~]# systemctl stop firewalld
[root@mail ~]# systemctl disable firewalld

Install Webmin and Usermin

Install Wemin and Usermin, start and enable services at boot.

[root@mail ~]# wget http://prdownloads.sourceforge.net/webadmin/webmin-1.979-1.noarch.rpm
[root@mail ~]# yum -y install perl perl-Net-SSLeay openssl perl-IO-Tty perl-Encode-Detect
[root@mail ~]# yum install webmin-1.979-1.noarch.rpm

[root@mail ~]# wget http://prdownloads.sourceforge.net/webadmin/usermin-1.823-1.noarch.rpm[root@mail ~]# yum install usermin-1.823-1.noarch.rpm

[root@mail ~]# systemctl start webmin
[root@mail ~]# systemctl enable webmin
[root@mail ~]# systemctl start usermin
[root@mail ~]# systemctl enable usermin

Install OpenSSL

Make sure all required openssl libraries are installed.

[root@mail ~]# yum install openssl openssl-devel

Uninstall postfix

We prefer to use the sendmail MTA, so we remove postfix.

[root@mail ~]# systemctl stop postfix
[root@mail ~]# yum remove postfix

Install sendmail

Install sendmail, start and enable services at boot.

[root@mail ~]# yum install sendmail sendmail-cf cyrus-sasl-plain
[root@mail ~]# systemctl enable sendmail
[root@mail ~]# systemctl start sendmail
[root@mail ~]# systemctl enable saslauthd
[root@mail ~]# systemctl start saslauthd

Install Spamassassin

Install spamassassin, start and enable services at boot.

[root@mail ~]# yum install spamassassin
[root@mail ~]# systemctl enable spamassassin
[root@mail ~]# systemctl start spamassassin

Install Dovecot

Install Dovecot, start and enable services at boot.

[root@mail ~]# yum install dovecot
[root@mail ~]# systemctl enable dovecot
[root@mail ~]# systemctl start dovecot

Install MariaDB

Install MariaDB, start and enable services at boot.

[root@mail ~]# yum install mariadb mariadb-server mariadb-backup boost-program-options
[root@mail ~]# systemctl enable mariadb
[root@mail ~]# systemctl start mariadb

Install Apache

Install Apache, start and enable services at boot.

[root@mail ~]# yum install httpd mod_ssl
[root@mail ~]# systemctl enable httpd
[root@mail ~]# systemctl start httpd

Install BIND

Install BIND, start and enable services at boot.

[root@mail ~]# yum install bind bind-utils
[root@mail ~]# systemctl enable named
[root@mail ~]# systemctl start named

Install Utilities

Install utilities i like to use.

[root@mail ~]# yum install mailx
[root@mail ~]# yum install dos2linux
[root@mail ~]# yum install fetchmail

SSL

Create required directories.

[root@mail ~]# mkdir /etc/pki/tls/certs/2021
[root@mail ~]# cd /etc/pki/tls/certs/2021
[root@mail ~]# mkdir cert; mkdir crl; mkdir inter; mkdir key

Transfer your certificate files to the previously created directories (you’ll notice that we have two files of the private key – one is for sendmail only because the sendmail-key requires a special mode).

[root@mail ~]# scp /etc/pki/tls/certs/2021/cert/netcult.ch.pem root@10.0.1.33:/etc/pki/tls/certs/2021/cert/
[root@mail ~]# scp /etc/pki/tls/certs/2021/cert/netcult.ch.sendmail.pem root@10.0.1.33:/etc/pki/tls/certs/2021/cert/
[root@mail ~]# scp /etc/pki/tls/certs/2021/crl/dvcasha2.crl root@10.0.1.33:/etc/pki/tls/certs/2021/crl/
[root@mail ~]# scp /etc/pki/tls/certs/2021/inter/inter.pem root@10.0.1.33:/etc/pki/tls/certs/2021/inter/
[root@mail ~]# scp /etc/pki/tls/certs/2021/key/netcult.ch.sendmail.key root@10.0.1.33:/etc/pki/tls/certs/2021/key/
[root@mail ~]# scp /etc/pki/tls/certs/2021/key/netcult.ch.key root@10.0.1.33:/etc/pki/tls/certs/2021/key/

Protect the private key of sendmail as sendmail checks the mode of the private key.

[root@mail ~]# chmod 600 /etc/pki/tls/certs/2021/key/netcult.ch.sendmail.key

Verify the contents and the permissions of the certifiacte files

[root@mail ~]# cd /etc/pki/tls/certs/2021/crl/
[root@mail ~]# ll
-rw-r--r-- 1 root root 174780 May 13 13:45 dvcasha2.crl

[root@mail ~]# cd /etc/pki/tls/certs/2021/inter/
[root@mail ~]# ll
-rw-r--r-- 1 root root 1754 May 26 14:30 inter.pem

[root@mail ~]# cd /etc/pki/tls/certs/2021/key/
[root@mail ~]# ll
-rw-r--r-- 1 root root 1704 May 27 15:21 netcult.ch.key
-rw------- 1 root mail 1704 May 27 15:21 netcult.ch.sendmail.key

Sendmail

Create sendmail configuration, only differences from the default configuration are documented.

[root@mail ~]# vi /etc/mail/sendmail.mc

dnl # default logging level is 9, you might want to set it higher to
dnl # debug the configuration.
dnl #
define(`confLOG_LEVEL', `14')dnl
(..)
define(`confAUTH_OPTIONS', `A')dnl
dnl #
dnl # The following allows relaying if the user authenticates, and disallows
dnl # plaintext authentication (PLAIN/LOGIN) on non-TLS links
dnl #
dnl define(`confAUTH_OPTIONS', `A p')dnl
dnl #
dnl # which realm to use in SASL database (sasldb2)
dnl #
define(`confAUTH_REALM', `mail')dnl
dnl #
dnl # PLAIN is the preferred plaintext authentication method and used by
dnl # Mozilla Mail and Evolution, though Outlook Express and other MUAs do
dnl # use LOGIN. Other mechanisms should be used if the connection is not
dnl # guaranteed secure.
dnl # Please remember that saslauthd needs to be running for AUTH.
dnl #
dnl TRUST_AUTH_MECH(`EXTERNAL DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
dnl define(`confAUTH_MECHANISMS', `EXTERNAL GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
define(`confAUTH_MECHANISMS',`LOGIN PLAIN DIGEST-MD5 CRAM-MD5')dnl
TRUST_AUTH_MECH(`LOGIN PLAIN DIGEST-MD5 CRAM-MD5')dnl
(..)
dnl #
dnl # Basic sendmail TLS configuration with self-signed certificate for
dnl # inbound SMTP (and also opportunistic TLS for outbound SMTP).
dnl #
define(`confCACERT_PATH',`/etc/pki/tls/certs')
define(`confCACERT',`/etc/pki/tls/certs/ca-bundle.trust.crt')
define(`confSERVER_CERT',`/etc/pki/tls/certs/2021/cert/netcult.ch.sendmail.pem')
define(`confSERVER_KEY',`/etc/pki/tls/certs/2021/key/netcult.ch.sendmail.key')
define(`confCRL',`/etc/pki/tls/certs/2021/crl/dvcasha2.crl')
define(`confTLS_SRV_OPTIONS', `V')dnl
LOCAL_CONFIG
dnl # Do not allow weak SSL/TLS protocols and cipher algorythms
O CipherList=HIGH:!ADH-DES-CBC3-SHA:!ADH-AES128-SHA:!ADH-AES256-SHA:!ADH-CAMELLIA128-SHA:!ADH-CAMELLIA256-SHA:!DH-AES128-SHA256:!DH-AES256-SHA256:!aNULL:!DES:!3DES:!MD5:!DES+MD5:!RC4
O ServerSSLOptions=+SSL_OP_NO_SSLv2 +SSL_OP_NO_SSLv3 +SSL_OP_CIPHER_SERVER_PREFERENCE
O ClientSSLOptions=+SSL_OP_NO_SSLv2 +SSL_OP_NO_SSLv3
(..)
dnl # For this to work your OpenSSL certificates must be configured.
dnl #
DAEMON_OPTIONS(`Port=smtps, Name=TLSMTA, M=s')dnl
(..)
dnl #
dnl # The following causes sendmail to only listen on the IPv4 loopback address
dnl # 127.0.0.1 and not on any other network devices. Remove the loopback
dnl # address restriction to accept email from the internet or intranet.
dnl #
DAEMON_OPTIONS(`Port=smtp,Addr=0.0.0.0, Name=MTA')dnl
dnl #
dnl # The following causes sendmail to additionally listen to port 587 for
dnl # mail from MUAs that authenticate. Roaming users who can't reach their
dnl # preferred sendmail daemon due to port 25 being blocked or redirected find
dnl # this useful.
dnl #
DAEMON_OPTIONS(`Port=submission, Name=MSA, M=Ea')dnl
dnl #
dnl # The following causes sendmail to additionally listen to port 465, but
dnl # starting immediately in TLS mode upon connecting. Port 25 or 587 followed
dnl # by STARTTLS is preferred, but roaming clients using Outlook Express can't
dnl # do STARTTLS on ports other than 25. Mozilla Mail can ONLY use STARTTLS
dnl # and doesn't support the deprecated smtps; Evolution <1.1.1 uses smtps
dnl # when SSL is enabled-- STARTTLS support is available in version 1.1.1.
dnl #
dnl # For this to work your OpenSSL certificates must be configured.
dnl #
DAEMON_OPTIONS(`Port=smtps, Name=TLSMTA, M=s')dnl
(..)
dnl # Add some dns blacklist checks
dnl #
dnl # Disabled blackist sites
dnl # FEATURE(`dnsbl',`sbl-xbl.spamhaus.org')dnl
dnl # FEATURE(`dnsbl',`bl.spamcop.net')dnl
dnl # FEATURE(`dnsbl',`cbl.abuseat.org')dnl
dnl # FEATURE(`dnsbl',`dnsbl.justspam.org')dnl
dnl # FEATURE(`dnsbl',`bl.0spam.org')dnl
dnl # FEATURE(`dnsbl',`url.0spam.org')dnl
dnl # FEATURE(`dnsbl',`ix.dnsbl.manitu.net')dnl
dnl # FEATURE(`dnsbl',`zen.spamhaus.org')dnl
dnl # FEATURE(`dnsbl',`dnsbl.sorbs.net')dnl
dnl # FEATURE(`dnsbl',`relays.ordb.org')dnl
(..)
MAILER(smtp)dnl
MAILER(procmail)dnl
dnl MAILER(cyrusv2)dnl
dnl #
dnl # Add OpenDKIM for Sendmail listening on TCP Port 8891 on localhost
dnl #
INPUT_MAIL_FILTER(`opendkim', `S=inet:8891@localhost')

Create sendmail configuration file and apply changes.

[root@mail ~]# /etc/mail/make
[root@mail ~]# systemctl restart sendmail

Procmail

Create procmail configuration. Find below our procmailrc configuration file. It will filter out all mails marked as spam by spamassassin and those marked mails will be moved to the users /Spam folder.

[root@mail ~]# vi /etc/procmailrc

# /etc/procmailrc
# Procmail configuration provided by thuinformatik GmbH

# Set variables
LOGFILE=/var/log/procmail.log
SPAMASSASSIN=/usr/bin/spamc
LOCKFILESPAMC=$HOME/.spamclock
LOCKFILEPROCM=$HOME/.proclock
DROPPRIVS=yes

# Pass emails through SpamAssassin and set X-Spam-Status flag by spamc
:0fw: $LOCKFILESPAMC
| $SPAMASSASSIN

# Pick emails with X-Spam-Status flag and move it over to users spamfolder
:0: $LOCKFILEPROCM
* ^X-Spam-Status: Yes
$HOME/mail/Spam

# Pick emails with X-Spam-Status flag and move it over to users spamfolder
:0: $LOCKFILEPROCM
* ^X-SPAM-LEVEL: Spam detection results
$HOME/mail/Spam

Hint: After the configuration of webmin/usermin, users can create their own rules via ~/.procmailrc.

Spamassassin

Create global Spamassassin configuration, only differences from the default configuration are documented.

[root@mail ~]# vi /etc/mail/spamassassin/local.cf

# These values can be overridden by editing ~/.spamassassin/user_prefs.cf
# (see spamassassin(1) for details)

# Custom rules
header CONTAINS_SUBJECT Subject =~/viagra, Cialix Pills, sex, xxx, penis, pussy, greekajob, greekajobs,
body CONTAINS_PEN/viagra, sex, xxx, penis, puss, greekajob, greekajobs, perazdera/

# How many hits before a message is considered spam (default: 3.5)
required_score 3.5

# Score definition
score URIBL_BLOCKED (0) (0) (0) (0)
score URIBL_BLACK (3) (3) (3) (3)
score URIBL_GREY (2) (2) (2) (2)
score URIBL_RED (1) (1) (1) (1)
score URIBL_ABUSE_SURBL (3) (3) (3) (3)
score URIBL_DBL_SPAM (5.5) (5.5) (5.5) (5.5)
score DKIM_VALID_AU (-2) (-2) (-2) (-2)
#score DKIM_SIGNED (-2) (-2) (-2) (-2)
score DKIM_VALID (-2.5) (-2.5) (-2.5) (-2.5)
score SPF_PASS (-2.5) (-2.5) (-2.5) (-2.5)
#score SPF_NONE (2) (2) (2) (2)
#score SPF_HELO_NONE (2) (2) (2) (2)
#score SPF_FAIL (2) (2) (2) (2)
score RCVD_IN_DNSWL_LOW (-0.1) (-0.1) (-0.1) (-0.1)
score RCVD_IN_DNSWL_MED (-0.7) (-0.7) (-0.7) (-0.7)
score RCVD_IN_DNSWL_HI (-1.3) (-1.3) (-1.3) (-1.3)
score T_KAM_HTML_FONT_INVALID (0.5) (0.5) (0.5) (0.5)
score LOTS_OF_MONEY (4) (4) (4) (4)
score ALL_TRUSTED (-6) (-6) (-6) (-6)
score MISSING_HEADERS (5) (5) (5) (5)
score SENDGRID_REDIR (1) (1) (1) (1)

# Scores for custom rules
score CONTAINS_SUBJECT (5) (5) (5) (5)
score CONTAINS_BODY (5) (5) (5) (5)
describe CONTAINS_SUBJECT Bad Word
describe CONTAINS_BODY Bad Word

# Change the subject of suspected spam
rewrite_header subject *SPAM* (Stage 2) -

# Encapsulate spam in an attachment (0=no, 1=yes, 2=safe)
report_safe 1

clear_report_template
report Potential Spam
report =======================================
report
report This incoming message was classified as potential spam.
report
report Please find the original message attached.
report
report In case this is false/positive, please read our technical information here:
report https://www.netcult.ch/techinfo.cfm
report
report Message preview
report =======================================
report
report _PREVIEW_
report
report Scores
report =======================================
report
report Date: _DATE_
report Hostname: _HOSTNAME_
report
report Is Spam: _YESNO_
report Stars: _STARS(*)_
report Bayes score: _BAYES_
report Total score: _SCORE(PAD)_
report Threshold: _REQD_
report
report Autolearn: _AUTOLEARN_
report Required by autolearn: _AUTOLEARNSCORE_
report
report Report
report =======================================
report
report Languages: _LANGUAGES_
report DCCR: _DCCR_
report PYZOR: _PYZOR_
report
report RBL
report =======================================
report
report _RBL_
report
report Summary
report =======================================
report
report _SUMMARY_
report
report =======================================

# Print or delete x-spam parts
# clear_headers

# Use terse version of the spam report
# use_terse_report 0

# Clear notification related to unsafe attachements
clear_unsafe_report_template

# Enable the Bayes system
use_bayes 1

# Enable Bayes auto-learning
bayes_auto_learn 1

# Enable or disable network checks
skip_rbl_checks 0
use_razor2 1

# DCC
loadplugin Mail::SpamAssassin::Plugin::DCC
use_dcc 1
dcc_path /usr/bin/dccproc
dcc_dccifd_path /usr/libexec/dcc/dccifd
full DCC_CHECK eval:check_dcc()
use_pyzor 1

# Mail using languages used in these country codes will not be marked
# as being possibly spam in a foreign language.
# - english german
# ok_languages en de

# Mail using locales used in these country codes will not be marked
# as being possibly spam in a foreign language.
# ok_locale en

# Show detailed phrase score
# detailed_phrase_score is from the old static phrase list code that dissapeared
# when bayes was added in spamassassin 2.50. (Bayes is a dynamic trainable version
# of this concept so anything from the old phrases code instantly obsolete)
# detailed_phrase_score 1

# Whitelist some safe senders
whitelist_from some@email.com
whitelist_from another@email.com

Hint: After the configuration of webmin/usermin, users can create their own rules via ~/.spamassassin/user_prefs.cf.

Activate older SpamAssassins plugins by removing the remarks (#) in the following files.

[root@mail ~]# vi /etc/mail/spamassassin/v310.pre
[root@mail ~]# vi /etc/mail/spamassassin/v320.pre
[root@mail ~]# vi /etc/mail/spamassassin/v312.pre
[root@mail ~]# vi /etc/mail/spamassassin/v330.pre
[root@mail ~]# vi /etc/mail/spamassassin/v340.pre
[root@mail ~]# vi /etc/mail/spamassassin/v341.pre
[root@mail ~]# vi /etc/mail/spamassassin/v342.pre
[root@mail ~]# vi /etc/mail/spamassassin/v343.pre

Following changes will be documented:

-------------------------------------------------------------------------
/etc/mail/spamassassin/v310.pre
-------------------------------------------------------------------------
# DCC - perform DCC message checks.
#
# DCC is disabled here because it is not open source. See the DCC
# license for more details.
#
loadplugin Mail::SpamAssassin::Plugin::DCC

# AWL - do auto-whitelist checks
#
loadplugin Mail::SpamAssassin::Plugin::AWL

# TextCat - language guesser
#
loadplugin Mail::SpamAssassin::Plugin::TextCat
-------------------------------------------------------------------------
/etc/mail/spamassassin/v312.pre
-------------------------------------------------------------------------
<no changes keeping the default>
-------------------------------------------------------------------------
/etc/mail/spamassassin/v320.pre
-------------------------------------------------------------------------
<no changes keeping the default>
-------------------------------------------------------------------------
/etc/mail/spamassassin/v330.pre
-------------------------------------------------------------------------
# PhishTag - allows sites to rewrite suspect phish-mail URLs
# (Note: this requires configuration, see http://umut.topkara.org/PhishTag)
#
loadplugin Mail::SpamAssassin::Plugin::PhishTag
-------------------------------------------------------------------------
/etc/mail/spamassassin/v340.pre
-------------------------------------------------------------------------
<no changes keeping the default>
-------------------------------------------------------------------------
/etc/mail/spamassassin/v341.pre
-------------------------------------------------------------------------
# TxRep - Reputation database that replaces AWL
loadplugin Mail::SpamAssassin::Plugin::TxRep

# PDFInfo - Use several methods to detect a PDF file's ham/spam traits
loadplugin Mail::SpamAssassin::Plugin::PDFInfo
-------------------------------------------------------------------------
/etc/mail/spamassassin/v342.pre
-------------------------------------------------------------------------
# HashBL - Query hashed/unhashed strings, emails, uris etc from DNS lists
loadplugin Mail::SpamAssassin::Plugin::HashBL

# FromNameSpoof - help stop spam that tries to spoof other domains using
# the from name
loadplugin Mail::SpamAssassin::Plugin::FromNameSpoof

# Phishing - finds uris used in phishing campaigns detected by
# OpenPhish or PhishTank feeds.
-------------------------------------------------------------------------
/etc/mail/spamassassin/v343.pre
-------------------------------------------------------------------------
# OLEVBMacro - Detects both OLE macros and VB code inside Office documents
#
# It tries to discern between safe and malicious code but due to the threat
# macros present to security, many places block these type of documents outright.
#
# For this plugin to work, Archive::Zip and IO::String modules are required.
loadplugin Mail::SpamAssassin::Plugin::OLEVBMacro

loadplugin Mail::SpamAssassin::Plugin::Phishing

Apply changes by restarting Spamassassin

[root@mail ~]# systemctl restart spamassassin

Configure crontab to keep Spamassassin up to date and learn from your users Spam folder within their mailbox

[root@mail ~]# crontab -e

# daily spam autolearn-on
30 * * * * sa-learn --spam --mbox /home/thomas/mail/Spam
30 * * * * sa-learn --spam --mbox /var/spool/mail/spam
30 7 * * * sa-learn --ham --mbox /var/spool/mail/thomas
30 * * * * sa-learn --spam --mbox /home/somedomain.ch/mail/Spam
30 7 * * * sa-learn --ham --mbox /var/spool/mail/somedomain.ch

# daily spamassassin update
30 7 * * * date >> /var/log/spamassassin_sa-update.log ; sa-update -v >> /var/log/spamassassin_sa-update.log ; /bin/systemctl restart spamassassin.service ; echo Spamassassin restarted >> /var/log/spamassassin_sa-update.log

Test the daily spamassassin update

[root@mail ~]# date >> /var/log/spamassassin_sa-update.log ; sa-update -v >> /var/log/spamassassin_sa-update.log ; /bin/systemctl restart spamassassin.service ; echo Spamassassin restarted >> /var/log/spamassassin_sa-update.log; cat /var/log/spamassassin_sa-update.log

Sat Jul 3 14:08:40 CEST 2021 Update available for channel updates.spamassassin.org: -1 -> 1891178 http: (curl) GET http://spamassassin.apache.org/updates/MIRRORED.BY, success http: (curl) GET http://sa-update.ena.com/1891178.tar.gz, success http: (curl) GET http://sa-update.ena.com/1891178.tar.gz.sha512, success http: (curl) GET http://sa-update.ena.com/1891178.tar.gz.asc, success Update was available, and was downloaded and installed successfully Spamassassin restarted

DCC

Install Distributed Checksum Clearinghouse (DCC) from the cheese-release repo.

http://www.nosuchhost.net/~cheese/fedora/packages/epel-8/x86_64/cheese-release.html

[root@mail ~]# wget http://www.nosuchhost.net/~cheese/fedora/packages/epel-8/x86_64/cheese-release-8-1.el8.noarch.rpm
[root@mail ~]# yum install cheese-release-8-1.el8.noarch.rpm
[root@mail ~]# yum install dcc

Dovecot

Create dovecot configuration, only differences from the default configuration are documented

-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/dovecot.conf
-------------------------------------------------------------------------
# Protocols we want to be serving.
# Default value: protocols = imap pop3 lmtp submission
protocols = imap pop3 lmtp

# Access for Dovecot process to home directories.
mail_privileged_group = mail
mail_access_groups = mail

# Greeting message for clients.
# Default value: login_greeting = Dovecot ready.
login_greeting = Dovecot at thuinformatik GmbH ready.
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/10-auth.conf
-------------------------------------------------------------------------
# Disable LOGIN command and all other plaintext authentications unless
# SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP
# matches the local IP (ie. you're connecting from the same computer), the
# connection is considered secure and plaintext authentication is allowed.
# See also ssl=required setting.
# Default value: disable_plaintext_auth = yes
disable_plaintext_auth = no

# Username character translations before it's looked up from databases. The
# value contains series of from -> to characters. For example "#@/@" means
# that '#' and '/' characters are translated to '@'.
auth_username_translation = @.

# Space separated list of wanted authentication mechanisms:
# plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp skey
# gss-spnego
# NOTE: See also disable_plaintext_auth setting.
# Default value: auth_mechanisms = plain
auth_mechanisms = plain login
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/10-director.conf
-------------------------------------------------------------------------
<no changes, keep the default>
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/10-logging.conf
-------------------------------------------------------------------------
# Log unsuccessful authentication attempts and the reasons why they failed.
# Default value: auth_verbose = no
auth_verbose = yes

Hint: Dovecot points the “mail_location” to the user home directory by default but sendmail stores the inbox files at /var/spool/mail/. To use the traditional sendmail structure, point the “mail_location” to the correct patch.

-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/10-mail.conf
-------------------------------------------------------------------------
# Location for users' mailboxes. The default is empty, which means that Dovecot
# tries to find the mailboxes automatically. This won't work if the user
# doesn't yet have any mail, so you should explicitly tell Dovecot the full
# location.
#
# If you're using mbox, giving a path to the INBOX file (eg. /var/mail/%u)
# isn't enough. You'll also need to tell Dovecot where the other mailboxes are
# kept. This is called the "root mail directory", and it must be the first
# path given in the mail_location setting.
#
# There are a few special variables you can use, eg.:
#
# %u - username
# %n - user part in user@domain, same as %u if there's no domain
# %d - domain part in user@domain, empty if there's no domain
# %h - home directory
#
# See doc/wiki/Variables.txt for full list. Some examples:
#
# mail_location = maildir:~/Maildir
# mail_location = mbox:~/mail:INBOX=/var/mail/%u
# mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n
#
# <doc/wiki/MailLocation.txt>
#
# Default value: mail_location =
mail_location = mbox:~/mail:INBOX=/var/mail/%u

# Valid UID range for users, defaults to 500 and above. This is mostly
# to make sure that users can't log in as daemons or other system users.
# Note that denying root logins is hardcoded to dovecot binary and can't
# be done even if first_valid_uid is set to 0.
first_valid_uid = 1000
#last_valid_uid = 0
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/10-master.conf
-------------------------------------------------------------------------
<no changes, keep the default>
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/10-ssl.conf
-------------------------------------------------------------------------
# SSL/TLS support: yes, no, required. <doc/wiki/SSL.txt>
# disable plain pop3 and imap, allowed are only pop3+TLS, pop3s, imap+TLS and imaps
# plain imap and pop3 are still allowed for local connections
# Default value: ssl = required
ssl = yes

# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
# dropping root privileges, so keep the key file unreadable by anyone but
# root. Included doc/mkcert.sh can be used to easily generate self-signed
# certificate, just make sure to update the domains in dovecot-openssl.cnf
# Default value: ssl_cert = </etc/pki/dovecot/certs/dovecot.pem
# Default value: ssl_key = </etc/pki/dovecot/private/dovecot.pem
ssl_cert = </etc/pki/tls/certs/2021/cert/netcult.ch.pem
ssl_key = </etc/pki/tls/certs/2021/key/netcult.ch.key

# PEM encoded trusted certificate authority. Set this only if you intend to use
# ssl_verify_client_cert=yes. The file should contain the CA certificate(s)
# followed by the matching CRL(s). (e.g. ssl_ca = </etc/pki/dovecot/certs/ca.pem)
# Default value: ssl_ca =
ssl_ca = </etc/pki/tls/certs/2021/inter/inter.pem

# SSL protocols to use
# Default vallue: ssl_protocols = !SSLv3
ssl_protocols = !SSLv2 !SSLv3

# SSL ciphers to use, the default is:
#ssl_cipher_list = ALL:!kRSA:!SRP:!kDHd:!DSS:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!RC4:!ADH:!LOW@STRENGTH
# To disable non-EC DH, use:
#ssl_cipher_list = ALL:!DH:!kRSA:!SRP:!kDHd:!DSS:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!RC4:!ADH:!LOW@STRENGTH
# Default value: ssl_cipher_list = PROFILE=SYSTEM
ssl_cipher_list=HIGH:!ADH-DES-CBC3-SHA:!ADH-AES128-SHA:!ADH-AES256-SHA:!ADH-CAMELLIA128-SHA:!ADH-CAMELLIA256-SHA:!DH-AES128-SHA256:!DH-AES256-SHA256:!aNULL:!DES:!3DES:!MD5:!DES+MD5:!RC4
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/15-lda.conf
-------------------------------------------------------------------------
<no changes, keep the default>
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/15-mailboxes.conf
-------------------------------------------------------------------------
<no changes, keep the default>
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/20-imap.conf
-------------------------------------------------------------------------
<no changes, keep the default>
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/20-lmtp.conf
-------------------------------------------------------------------------
<no changes, keep the default>
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/20-pop3.conf
-------------------------------------------------------------------------
<no changes, keep the default>
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/20-submission.conf
-------------------------------------------------------------------------
<no changes, keep the default>
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/90-acl.conf
-------------------------------------------------------------------------
<no changes, keep the default>
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/90-plugin.conf
-------------------------------------------------------------------------
<no changes, keep the default>
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/90-quota.conf
-------------------------------------------------------------------------
<no changes, keep the default>
-------------------------------------------------------------------------
[root@mail ~]# vi /etc/dovecot/conf.d/auth-checkpassword.conf.ext
[root@mail ~]# vi /etc/dovecot/conf.d/auth-deny.conf.ext
[root@mail ~]# vi /etc/dovecot/conf.d/auth-dict.conf.ext
[root@mail ~]# vi /etc/dovecot/conf.d/auth-ldap.conf.ext
[root@mail ~]# vi /etc/dovecot/conf.d/auth-master.conf.ext
[root@mail ~]# vi /etc/dovecot/conf.d/auth-passwdfile.conf.ext
[root@mail ~]# vi /etc/dovecot/conf.d/auth-sql.conf.ext
[root@mail ~]# vi /etc/dovecot/conf.d/auth-static.conf.ext
[root@mail ~]# vi /etc/dovecot/conf.d/auth-system.conf.ext
[root@mail ~]# vi /etc/dovecot/conf.d/auth-vpopmail.conf.ext
-------------------------------------------------------------------------
<no changes, keep the default>

Apply all changes by restarting dovecot

[root@mail ~]# systemctl restart dovecot

Administrator user configuration

Set the user group ID 100 for the user administrator.

[root@mail ~]# vi /etc/passwd
administrator:x:1000:100:Administrator:/home/administrator:/bin/bash

Make home directories accessible for the users group:

[root@mail ~]# chown -R :users /var/spool/mail/
[root@mail ~]# chown -R :users /home/

Just to be sure: apply changes by restarting dovecot and sasl

[root@mail ~]# systemctl restart dovecot
[root@mail ~]# systemctl restart saslauthd

Basic mailtests

Try to send an email with the administrator user created during the installation. Verify if the mailfow works as exptected.

[root@mail ~]# su administrator
[administrator@mail root]$ cat /etc/redhat-release | mail -s "Fedora Release" administrator@mail.yourhostname.ch

Verify the email has arrived

[administrator@mail root]$ cat /var/mail/administrator
From administrator@mail.netcult.ch Sat Jul 3 15:58:23 2021
Return-Path: <administrator@mail.yourhostname.ch>
X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on mail.yourhostname.ch
X-Spam-Level:
X-Spam-Status: No, score=-7.0 required=3.5 tests=ALL_TRUSTED autolearn=ham
autolearn_force=no version=3.4.4
Received: from mail.yourhostname.ch (localhost [127.0.0.1])
by mail.yourhostname.ch (8.15.2/8.15.2) with ESMTPS id 163DwNpD700072
(version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT)
for <administrator@mail.yourhostname.ch>; Sat, 3 Jul 2021 15:58:23 +0200
Received: (from administrator@localhost)
by mail.yourhostname.ch (8.15.2/8.15.2/Submit) id 163DwN0a700071
for administrator@mail.netcult.ch; Sat, 3 Jul 2021 15:58:23 +0200
From: General Administrator <administrator@mail.yourhostname.ch>
Message-Id: <202107031358.163DwN0a700071@mail.yourhostname.ch>
Date: Sat, 03 Jul 2021 15:58:23 +0200
To: administrator@mail.yourhostname.ch
Subject: Fedora Release
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Rocky Linux release 8.4 (Green Obsidian)

OpenDKIM

We have documented the installation of OpenDKIM in one of our previous blog posts.

Make sure the service will be started automatically after the host reboots.

[root@mail ~]# systemctl enable opendkim.service
[root@mail ~]# systemctl start opendkim.service

BIND configuration

We where not able to migrate the whole bind configuration from one host to the other. Instead of copying the running configuration we descided then to use a zone transfer to migrate our DNS zones from the old to the new server.

Apache

Configure apache http server, only differences from the default configuration are documented.

[root@mail ~]# vi /etc/httpd/conf.d/ssl.conf

# OCSP Stapling is a TLS extension that enables the web server
# to cache Certificate Revocation status information and not
# placing the onus on the web client to make the request directly
# with the Certificate Authority (CA).
SSLStaplingCache "shmcb:/var/log/stapling_cache(128000)"

# Pseudo Random Number Generator (PRNG):
# Configure one or more sources to seed the PRNG of the
# SSL library. The seed data should be of good random quality.
# WARNING! On some platforms /dev/random blocks if not enough entropy
# is available. This means you then cannot use the /dev/random device
# because it would lead to very long connection times (as long as
# it requires to make more entropy available). But usually those
# platforms additionally provide a /dev/urandom device which doesn't
# block. So, if available, use this one instead. Read the mod_ssl User
# Manual for more details.
SSLRandomSeed startup file:/dev/urandom 256
SSLRandomSeed connect builtin
#SSLRandomSeed startup file:/dev/random 512
#SSLRandomSeed connect file:/dev/random 512
#SSLRandomSeed connect file:/dev/urandom 512

# SSL Protocol support:
# List the enable protocol levels with which clients will be able to
# connect. Disable SSLv2 access by default:
# SSLProtocol all -SSLv2 -SSLv3
# SSLProtocol +TLSv1 +TLSv1.1 +TLSv1.2
SSLProtocol +TLSv1.2

# User agents such as web browsers are not configured for the user's
# own preference of either security or performance, therefore this
# must be the prerogative of the web server administrator who manages
# cpu load versus confidentiality, so enforce the server's cipher order.
SSLHonorCipherOrder on

# SSL Cipher Suite:
# List the ciphers that the client is permitted to negotiate.
# See the mod_ssl documentation for a complete list.
# The OpenSSL system profile is configured by default. See
# update-crypto-policies(8) for more details.
#SSLCipherSuite PROFILE=SYSTEM
#SSLProxyCipherSuite PROFILE=SYSTEM
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
SSLProxyCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA

# Point SSLCertificateFile at a PEM encoded certificate. If
# the certificate is encrypted, then you will be prompted for a
# pass phrase. Note that restarting httpd will prompt again. Keep
# in mind that if you have both an RSA and a DSA certificate you
# can configure both in parallel (to also allow the use of DSA
# ciphers, etc.)
# Some ECC cipher suites (http://www.ietf.org/rfc/rfc4492.txt)
# require an ECC certificate which can also be configured in
# parallel.
#SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateFile /etc/pki/tls/certs/2021/cert/netcult.ch.pem

# Server Private Key:
# If the key is not combined with the certificate, use this
# directive to point at the key file. Keep in mind that if
# you've both a RSA and a DSA private key you can configure
# both in parallel (to also allow the use of DSA ciphers, etc.)
# ECC keys, when in use, can also be configured in parallel
#SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
SSLCertificateKeyFile /etc/pki/tls/certs/2021/key/netcult.ch.key

# Server Certificate Chain:
# Point SSLCertificateChainFile at a file containing the
# concatenation of PEM encoded CA certificates which form the
# certificate chain for the server certificate. Alternatively
# the referenced file can be the same as SSLCertificateFile
# when the CA certificates are directly appended to the server
# certificate for convenience.
#SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt
SSLCertificateChainFile /etc/ssl/certs/2021/inter/inter.pem

# Certificate Authority (CA):
# Set the CA certificate verification path where to find CA
# certificates for client authentication or alternatively one
# huge file containing all of them (file must be PEM encoded)
#SSLCACertificateFile /etc/pki/tls/certs/ca-bundle.crt
SSLCACertificateFile /etc/pki/tls/certs/ca-bundle.crt

Apply all changes by restarting apache

[root@mail ~]# systemctl restart httpd

MariaDB

Configure mariadb server, only differences from the default configuration are documented.

[root@mail ~] vi /etc/my.cnf.d/mariadb-server.cnf

# this is only for the mysqld standalone daemon
# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mysqld/mariadb according to the
# instructions in http://fedoraproject.org/wiki/Systemd
[mysqld]
# Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 # default-time-zone=+02:00 # Settings user and group are ignored when systemd is used. # If you need to run mysqld under a different user or group, # customize your systemd unit file for mariadb according to the # instructions in http://fedoraproject.org/wiki/Systemd # InnoDB is the default engine of mariaDB and after setting # these parameters all the tables will have their own .idb file on server. # Now the question arises how will it make MariaDB more efficient? # As all the operations performed on this table will use the I/O of that single # .idb file and if you truncate that table you can reclaim that # space as the file against that table will be removed. innodb_file_per_table=1 # You can enable caching and indexing in MariaDB server by setting # the InnoDB buffer pool size parameter. The amount of memory you # want to dedicate solely depends upon the amount of RAM your server has. # If your server is dedicated for database then you can set the parameter # to 60 percent of your memory but if other services are running on #the same server then you should consider a different value. innodb_buffer_pool_size = 2G # Every time a connection is opened its IP is resolved by DNS lookup; # which consumes some amount of time. skip-name-resolve # Query cache size is also an important parameter as it caches # all the queries which keep on repeating with same data. # For small websites your value should not exceed 64MB. # Increasing this value to GB’s will decrease the performance instead of making it efficient. query_cache_size = 64M # These parameters are set to avoid disk writes on your servers. # For efficient performance, both of these values should be same. max_heap_table_size= 64M tmp_table_size= 64M # It is one of the best feature of MariaDB which allows the database developers # to improve the performance by checking the queries which are taking excessive time to execute. slow-query-log = 1 slow-query-log-file = /var/log/mariadb/mariadb-slow.log long_query_time = 1

Apply all changes by restarting mariadb

[root@mail ~]# systemctl restart mariadb

eGroupware

RHEL/CentOS 8/Rocky Linux 8 uses nftables instead of iptables, which does not work with current docker-ce. You need to configure firewalld to use iptables by editing /etc/firewalld/firewalld.conf.

[root@mail ~]# vi /etc/firewalld/firewalld.conf

#FirewallBackend=nftables
FirewallBackend=iptables

[root@mail ~]# systemctl restart firewalld

If installed, remove everything of podman and reboot your system afterwards

[root@mail ~]# yum remove podman runc pcp-pmda-podman
[root@mail ~]# yum remove @container-tools
[root@mail ~]# shutdown -r now

Install Docker for Rocky Linux 8

[root@mail ~]# curl https://download.docker.com/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker-ce.repo
[root@mail ~]# yum install --nobest docker-ce
[root@mail ~]# systemctl enable docker
[root@mail ~]# systemctl start docker
[root@mail ~]# usermod -aG docker $USER

Install eGroupware for Rocky Linux 8

[root@mail ~]# curl https://download.opensuse.org/repositories/server:/eGroupWare/CentOS_8/server:eGroupWare.repo -o /etc/yum.repos.d/server:eGroupWare.repo
[root@mail ~]# yum install egroupware-docker egroupware-collabora-key egroupware-rocketchat

Verify reverse proxy configuration in ssl.conf.

[root@mail ~]# cat /etc/httpd/conf.d/ssl.conf
(..)
# Collabora proxy needs to be included inside vhost
include /etc/egroupware-collabora-key/apache.conf
# EGroupware proxy needs to be included inside vhost
include /etc/egroupware-docker/apache.conf

To make sure Docker starts after the host has booted up, we use the tc.local.

[root@mail keys]# cat /etc/rc.local
#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.

touch /var/lock/subsys/local

# Start docker containers ...
cd /etc/egroupware-docker; docker-compose up -d

User and data migration

Configure passwordless ssh authentication

We have documented passwordless ssh authentication in one of our previous blog posts. Make sure you can access from the old to the new host and vice versa without needing the enter a password.

Create folders to store migration data

Create those folders on the old and the new host

[root@mail ~]# mkdir /root/migration
[root@mail ~]# mkdir /root/migration/userdata

Inital migration of mariadb

On the old host: Backup all mariadb databases.

[root@mail ~]# mysqldump --all-databases -u root -pYour_root_password > /root/migration/mariadb_full.sql

Transfer the backup to the new host.

[root@mail ~]# scp /root/migration/mariadb_full.sql root@10.0.1.33:/root/migration/

On the new host: Load mariadb database backup.

[root@mail ~]# mysql -u root -p < /root/migration/mariadb_full.sql
Enter password:

FLUSH PRIVILEGES (apply new user privileges)

[root@mail ~]# mysql -u root -p
Enter password:
MariaDB [(none)]> FLUSH PRIVILEGES; MariaDB [(none)]> exit;

Migrate eGroupware

Verify login with egroupware database user.

[root@mail ~]# mysql -u egroupware -p
Enter password:

Configure eGroupware to use the new hosts mariadb server.

[root@mail ~]# cd /etc/egroupware-docker/
[root@mail egroupware-docker]# vi docker-compose.override.yml

Uncomment all marked > lines (we would like to use the maridb server running on the host). Fee free to configure additional settings.

#########################################################################################
###
### docker-compose.override.yml file for egroupware-docker package
###
### Place all your modifications in this file, instead of /etc/egroupware-docker/docker-compose.yml.
###
### If you want to make some modification / uncomment eg. some enviroment variables, you also have to:
### - uncomment the service eg. "egroupware:", if not already uncommented like egroupware
### - uncomment the "environment:" section of the service
###
### services:
### egroupware:
### environment:
### - EGW_APC_SHM_SIZE=256M
###
### Please note: indention with space (NOT tabs!) matter in .yml files!
###
##########################################################################################
version: '3'

#volumes:
# EGroupware data stored in /var/lib/egroupware on the host
#data:
# driver_opts:
# type: none
# o: bind
# device: /var/lib/egroupware

services:
egroupware:
# egroupware images to use:
# - egroupware/egroupware: is the community edition of egroupware
# - download.egroupware.org/egroupware/epl: is the EPL / subscription version of EGroupware GmbH
# egroupware tags to use:
# - latest: recommended is to use tag latest for automatic updates incl. new stable major releases
# - 20.1: use a branch to keep on latest maintenance release for that branch, but not update automatic to next release
# - 20.1.20200613: use a maintenance release, to disable automatic updates via watchtower and run them manually
image: egroupware/egroupware:21.1

>volumes:
# if you want to use the host database:
# 1. follow instructions below to disable db service
# 2. set EGW_DB_HOST=localhost AND
# 3. uncomment the next line and modify the host path, it depends on your distro:
# - RHEL/CentOS /var/lib/mysql/mysql.sock:/var/run/mysqld/mysqld.sock
# - openSUSE/SLE /var/run/mysql/mysql.sock:/var/run/mysqld/mysqld.sock
# - Debian/Ubuntu /var/run/mysqld:/var/run/mysqld
#- /var/run/mysqld:/var/run/mysqld
> - /var/lib/mysql/mysql.sock:/var/run/mysqld/mysqld.sock
# private CA so egroupware can validate your certificate to talk to Collabora or Rocket.Chat
# multiple certificates (eg. a chain) have to be single files in a directory, with one named private-ca.crt!
#- /etc/egroupware-docker/private-ca.crt:/usr/local/share/ca-certificates/private-ca.crt:ro
> environment:
# setting a default language for a new installation
#- LANG=de
# MariaDB/MySQL host to use: for host database (socket bind-mounted into container) use "localhost"
> - EGW_DB_HOST=localhost
# for internal db service you should to specify a root password here AND in db service
# a database "egroupware" with a random password is created for you on installation (password is stored in header.inc.php in data directory)
#- EGW_DB_ROOT=root
#- EGW_DB_ROOT_PW=secret
# alternativly you can specify an already existing database with full right by the given user!
#- EGW_DB_NAME=egroupware
#- EGW_DB_USER=egroupware
> - EGW_DB_PASS=bn2H1R:SQ8d!cJSE
# other php.ini values to set in the container and their current defaults
#- EGW_SESSION_TIMEOUT=14000
#- EGW_APC_SHM_SIZE=128M
#- EGW_MEMORY_LIMIT=128M
#- EGW_MAX_EXECUTION_TIME=90
# set the ip-address of your docker host AND your official DNS name so EGroupware
# can access Rocket.Chat or Collabora without the need to go over your firewall
#extra_hosts:
#- "my.host.name:ip-address"

# to use the database on the host, uncomment all the following settings to disable the internal db service
> db:
> image: busybox
> entrypoint: /bin/true
> restart: "no"

# push server using phpswoole
#push:

# nginx server of egroupware using /etc/egroupware-docker/egroupware-nginx.conf
# You want to install your certificate on the webserver/Nginx running on the host proxying to this one
#nginx:

# automatic updates of all containers daily at 4am
# see https://containrrr.github.io/watchtower for more information
#watchtower:
#environment:
#- WATCHTOWER_CLEANUP=true # delete old image after update to not fill up the disk
# for email notifications add your email and mail-server here
#- WATCHTOWER_NOTIFICATIONS=email
#- WATCHTOWER_NOTIFICATIONS_LEVEL=info # possible values: panic, fatal, error, warn, info or debug
#- WATCHTOWER_NOTIFICATION_EMAIL_FROM=watchtower@my-domain.com
#- WATCHTOWER_NOTIFICATION_EMAIL_TO=me@my-domain.com
#- WATCHTOWER_NOTIFICATION_EMAIL_SERVER=mail.my-domain.com # if you give your MX here, you need no user/password
#- WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=25
#- WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER=watchtower@my-domain.com
#- WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=secret
#command: --schedule "0 0 4 * * *"

Stop all docker services.

[root@mail egroupware-docker]# docker-compose down

Start all docker services, remove orphaned db container and build images before starting containers.

[root@mail egroupware-docker]# docker-compose up -d --remove-orphans --build

Verify active containers only.

[root@mail egroupware-docker]# docker pslog
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d1420b4853f4 nginx:stable-alpine "/docker-entrypoint.…" 33 seconds ago Up 30 seconds 127.0.0.1:8080->80/tcp egroupware-nginx
d054757f012c phpswoole/swoole:4.6-php7.4-alpine "docker-php-entrypoi…" 34 seconds ago Up 32 seconds egroupware-push
71492d39293d egroupware/egroupware:21.1 "/entrypoint.sh php-…" 35 seconds ago Up 33 seconds 9000/tcp egroupware
df53e76a73aa containrrr/watchtower:latest "/watchtower --sched…" 37 seconds ago Up 34 seconds 8080/tcp egroupware-watchtower
44171a4b3c28 quay.io/egroupware/rocket.chat:stable "docker-entrypoint.s…" 33 hours ago Up 33 hours 127.0.0.1:3000->3000/tcp rocketchat
8852ee8cc9de mongo:4.0 "docker-entrypoint.s…" 33 hours ago Up 33 hours 27017/tcp rocketchat-mongo
a54c2878f835 quay.io/egroupware/collabora-key:stable "/bin/sh -c 'bash st…" 33 hours ago Up 33 hours 127.0.0.1:9980->9980/tcp collabora-key

Verify active and inactive containers.

[root@mail egroupware-docker]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d1420b4853f4 nginx:stable-alpine "/docker-entrypoint.…" 54 seconds ago Up 52 seconds 127.0.0.1:8080->80/tcp egroupware-nginx
d054757f012c phpswoole/swoole:4.6-php7.4-alpine "docker-php-entrypoi…" 55 seconds ago Up 53 seconds egroupware-push
71492d39293d egroupware/egroupware:21.1 "/entrypoint.sh php-…" 56 seconds ago Up 7 seconds 9000/tcp egroupware
1094d121a673 busybox "/bin/true" 58 seconds ago Exited (0) 55 seconds ago egroupware-db
df53e76a73aa containrrr/watchtower:latest "/watchtower --sched…" 58 seconds ago Up 55 seconds 8080/tcp egroupware-watchtower
44171a4b3c28 quay.io/egroupware/rocket.chat:stable "docker-entrypoint.s…" 33 hours ago Up 33 hours 127.0.0.1:3000->3000/tcp rocketchat
da02d5a1b1a2 mongo:4.0 "docker-entrypoint.s…" 33 hours ago Exited (0) 33 hours ago egroupware-rocketchat_mongo-init-replica_1
8852ee8cc9de mongo:4.0 "docker-entrypoint.s…" 33 hours ago Up 33 hours 27017/tcp rocketchat-mongo
a54c2878f835 quay.io/egroupware/collabora-key:stable "/bin/sh -c 'bash st…" 33 hours ago Up 33 hours 127.0.0.1:9980->9980/tcp collabora-key

We need/want to uninstall the rocketchat container as we do not want to use this feature.

[root@mail egroupware-docker]# yum remove egroupware-rocketchat

A useful command: Get realtime statistics of all docker containers

[root@mail egroupware-docker]# docker stats -a
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
a11320d40498 collabora-key 0.04% 464.4MiB / 11.52GiB 3.94% 9.89kB / 0B 1.37GB / 3.81MB 11
83e121e54c52 egroupware-nginx 0.00% 5.125MiB / 11.52GiB 0.04% 10.2kB / 0B 13.3MB / 0B 5
583282159d2f egroupware-push 0.00% 17.41MiB / 11.52GiB 0.15% 10.2kB / 0B 68.6MB / 0B 10
1417fc35a4f9 egroupware-watchtower 0.00% 15.06MiB / 11.52GiB 0.13% 10.2kB / 0B 30.2MB / 0B 10
9a5e0b97fd73 egroupware-db 0.00% 0B / 0B 0.00% 0B / 0B 0B / 0B 0

Remove rocketchat_mongo docker volume.

[root@mail egroupware-docker]# docker volume ls
DRIVER VOLUME NAME
local 0e1e0f7fd32f7d06c88621135a8331cb3d106e1edf3f905b2fc3bd2c8244776f
local 5950f665506af9b982646affd4b9305c1c1f1c636aa2c2777e9b116d84464a12
local e2be92753bc12b00d9fa5e4a9f7b14f4d9e321429e9ed9b462a99dd97bba00ee
local egroupware-docker_data
local egroupware-docker_db
local egroupware-docker_extra
local egroupware-docker_push-config
local egroupware-docker_sessions
local egroupware-docker_sources
local egroupware-docker_sources-push
local egroupware-docker_videos
local egroupware-rocketchat_mongo

[root@mail egroupware-docker]# docker volume rm egroupware-rocketchat_mongo
egroupware-rocketchat_mongo

Verify if eGroupware has a working database connection.

[root@mail egroupware-docker]# docker-compose logs -f

If you still get the error…

egroupware | Retrying EGroupware installation in 3 seconds ...
egroupware | /usr/bin/php7.4 -d memory_limit=-1 /usr/share/egroupware/setup/setup-cli.php --update 'all,admin,Qr[;pr-4nrRrND4B'
egroupware | EGroupware API version 21.1 found.
egroupware | EGroupware configuration file (header.inc.php) version 1.29 exists and is up to date
egroupware | Your database is not working! mysqli://egroupware:<somepassword)@db/egroupware:
egroupware |
egroupware | Installation failed --> exiting!

… then modify header.inc.php manually to point to the correct mariadb host.

[root@mail egroupware-docker]# vi /var/lib/docker/volumes/egroupware-docker_data/_data/header.inc.php

/* eGroupWare domain-specific db settings */
$GLOBALS['egw_domain']['default'] = array(
'db_host' => 'localhost',
'db_port' => '3306',
'db_name' => 'egroupware',
'db_user' => 'egroupware',
'db_pass' => '<somepassword>',
// Look at the README file
'db_type' => 'mysqli',
// This will limit who is allowed to make configuration modifications
'config_user' => 'admin',
'config_passwd' => '{crypt}$2a$12$84T8C2nSxJXHpA8I5krODeB7vBF5nylW/1iZNdtea6hEOc1ktzrK.'
);

Copy previously used custom logos and icons. Create required folder on new host.

[root@mail egroupware-docker]# cd ~
[root@mail ~]# mkdir /var/lib/docker/volumes/egroupware-docker_data/_data/default/files/anon-images

Copy over the content from the old host to the new host and set file permissions

[root@mail ~]# scp /var/lib/docker/volumes/egroupware-docker_data/_data/default/files/anon-images/* root@10.0.1.33://var/lib/docker/volumes/egroupware-docker_data/_data/default/files/anon-images/

Check current permissions and set it equal to the existing IDs

[root@mail ~]# ll /var/lib/docker/volumes/egroupware-docker_data/_data/default/files
total 0
drwx------ 2 33 tape 6 Jul 4 13:36 activesync
drwxr-xr-x 2 33 tape 47 Jul 5 22:48 anon-images
drwxr-xr-x 3 33 tape 19 Jul 4 13:36 smallpart
drwxr-xr-x 2 33 tape 6 Jul 4 13:36 sqlfs

[root@mail ~]# chown 33:tape /var/lib/docker/volumes/egroupware-docker_data/_data/default/files/anon-images

Find setup and administrator configuration credentials for http://yourhost/egroupware/setup.

[root@mail ~]# cat /var/lib/docker/volumes/egroupware-docker_data/_data/egroupware-docker-install.log |more


(...)
EGroupware successful installed
===============================

Please note the following user names and passwords:

Setup username: admin
password: <somepassword>

EGroupware username: sysop
password: <somepassword>
(...)

Change all required settings that need to point to the new host. Login to the setup-page (http://yourhost/egroupware/setup)

eGroupware Admin Login
Login to the Setup-/Configuration-page

Configuration
Open Step 2 – Configuration

Authentication Backend
Make sure your authentication backend is the IP address of your new host.

Compare all other settings and save all changes. Afterwards login at https://yourhost/egroupware and login as your administrative-user.

Administrator Login

Open Mailbox Settings
Right click the top level folder of the administrator-mailbox and select “Edit Account” from the context menu.

Mail Account Settings Mail Account Settings
Make sure the default Mail-Account is confiured for “All Users” to the new host.

As a final step, login to the egroupware solution and check if the authentication works and if you have access to your maildata.

Scripts to migrate data

Below some scripts we used to migrate user data from the old to the new host. All scripts will be executed on the old host. Store all scripts below in /root/migration.

Migration of users, groups and credentials
-----------------------------------------------------------------
[root@mail ~]# vi /root/migration/user.migration.sh
-----------------------------------------------------------------
#!/bin/bash

# Description:
# This script will be used to migrate users and credentials from a old to a new host.
#
# Version 1.0
# Date 06. July 2021

# Specify variables here
UGIDLIMIT=1000
TARGETHOST=10.0.1.33
BASEDIR=/root/migration/userdata

# Export users, groups and credentials
awk -v LIMIT=$UGIDLIMIT -F: '($3>=LIMIT) && ($3!=65534) && ($3!=1005) && ($3!=1009)' /etc/passwd > ${BASEDIR}/passwd.mig
awk -v LIMIT=$UGIDLIMIT -F: '($3>=LIMIT) && ($3!=65534) && ($3!=1001)' /etc/group > ${BASEDIR}/group.mig
awk -v LIMIT=$UGIDLIMIT -F: '($3>=LIMIT) && ($3!=65534) && ($3!=1005) && ($3!=1009) {print $1}' /etc/passwd | tee - | egrep -f - /etc/shadow > ${BASEDIR}/shadow.mig
cp /etc/gshadow ${BASEDIR}/gshadow.mig

# Copy configuration files of users, groups and credentials to a remote host
scp -r ${BASEDIR}/* root@${TARGETHOST}:${BASEDIR}/

# Import users, groups and credentials on a remote host
ssh root@${TARGETHOST} BASEDIR="/root/migration/userdata" /bin/bash<<"EOF"
  while IFS=":" read -r user x uid x; do [[ $uid -ge 1000 && $uid != 65534 ]] && userdel "$user"; done </etc/passwd
  while IFS=":" read -r user x uid x; do [[ $uid -ge 1000 && $uid != 65534 ]] && groupdel "$user"; done </etc/group
  cat ${BASEDIR}/passwd.mig >> /etc/passwd
  cat ${BASEDIR}/group.mig >> /etc/group
  cat ${BASEDIR}/shadow.mig >> /etc/shadow
  cp -nf ${BASEDIR}/gshadow.mig /etc/gshadow
EOF
Migration of opendkim keys
-----------------------------------------------------------------
[root@mail ~]# vi /root/migration/opendkim.migration.sh
-----------------------------------------------------------------
#!/bin/bash

# Description:
# This script will be used to copy opendkim related configuration files from an old to a new host.
#
# Version 1.0
# Date 06. July 2021

# Specify variables here
TARGETHOST=10.0.1.33

# Copy configuration files of opendkim to a remote host
scp /etc/opendkim.conf root@${TARGETHOST}:/etc/opendkim.conf
scp /etc/opendkim/TrustedHosts root@${TARGETHOST}:/etc/opendkim/TrustedHosts
scp /etc/opendkim/SigningTable root@${TARGETHOST}:/etc/opendkim/SigningTable
scp /etc/opendkim/KeyTable root@${TARGETHOST}:/etc/opendkim/KeyTable
rsync -avvzhe ssh --progress /etc/opendkim/keys root@10.0.1.32:/etc/opendkim
Migration of sendmail configuration
-----------------------------------------------------------------
[root@mail ~]# vi /root/migration/sendmail.migration.sh
-----------------------------------------------------------------
#!/bin/bash

# Description:
# This script will be used to copy sendmail related configuration files from an old to a new host.
#
# Version 1.0
# Date 06. July 2021

# Specify variables here
TARGETHOST=10.0.1.33

# Copy configuration files of sendmail to a remote host
scp /etc/aliases root@${TARGETHOST}:/etc/aliases
scp /etc/mail/access root@${TARGETHOST}:/etc/mail/access
scp /etc/mail/local-host-names root@${TARGETHOST}:/etc/mail/local-host-names
scp /etc/mail/domaintable root@${TARGETHOST}:/etc/mail/domaintable
scp /etc/mail/trusted-users root@${TARGETHOST}:/etc/mail/trusted-users
scp /etc/mail/virtusertable root@${TARGETHOST}:/etc/mail/virtusertable

# Restart sendmail on a remote host
ssh -t root@${TARGETHOST} 'systemctl restart sendmail'
Migration of mariadb data
-----------------------------------------------------------------
[root@mail ~]# vi /root/migration/mariadb.migration.sh
-----------------------------------------------------------------
#!/bin/bash

# Description:
# This script will be used to dump mariadb databases on a old host and restore them to a new host.
#
# Version 1.0
# Date 06. July 2021

# Specify variables here
TARGETHOST=10.0.1.33
TARGETFILE=/root/migration/mariadb_full.sql
DB_ROOT=root
DB_PASS=somepassword

# Dump whole database server
mysqldump --all-databases -u ${DB_ROOT} -p${DB_PASS} > ${TARGETFILE}

# Transfer files to a new host
scp ${TARGETFILE} root@${TARGETHOST}:${TARGETFILE}

# Restore dump remotely on a new host and restart mariadb
ssh -t root@${TARGETHOST} 'mysql -u root -p${DB_PASS} < ${TARGETFILE}'
ssh -t root@${TARGETHOST} 'systemctl restart mariadb'
Migration of mail data
-----------------------------------------------------------------
[root@mail ~]# vi /root/migration/mail.migration.sh
-----------------------------------------------------------------
#!/bin/bash

# Description:
# This script will be used to synchronize users mail data from a old to a new host.
#
# Version 1.0
# Date 06. July 2021

# Specify variables here
TARGETHOST=10.0.1.33

# Synchronize folders
rsync -avvzhe ssh --progress /var/spool/mail root@${TARGETHOST}:/var/spool
rsync -avvzhe ssh --progress /home root@${TARGETHOST}:/

Make all script executable

[root@mail ~]# chmod +x /root/migration/*.migration.sh

Configure crontab to migrate data automatically in the background

[root@mail ~]# crontab -e

# Server migration
00 2 * * * /root/migration/user.migration.sh >> /var/log/user.migration.log 2>&1
05 2 * * * /root/migration/opendkim.migration.sh >> /var/log/opendkim.migration.sh 2>&1
10 2 * * * /root/migration/sendmail.migration.sh >> /var/log/sendmail.migration.sh 2>&1
15 2 * * * /root/migration/mariadb.migration.sh >> /var/log/mariadb.migration.sh 2>&1
20 2 * * * /root/migration/mail.migration.sh >> /var/log/mail.migration.log 2>&1

After the first inital synchronisation make sure the correct rights are applied on the new host.

Apply the correct rights to the inbox files in /var/spool/mail

[root@mail ~]# cd /var/spool/mail
[root@mail mail]# for n in *; do chown $n:users $n; done

Apply the correct rights to the inbox files in /home (if required)

[root@mail ~]# cd /home
[root@mail home]# for n in *; do chown -R $n:users $n; done

Appendix

A user of our mailhost was affected with the following problem:  A mailsender got a “Mail Derlivery Error” from the <MAILER DAEMON> as reply to a mail sent to our customer.

The original message was received at Tue, 23 Nov 2021 11:12:03 +0100 from mxout017.mail.xxx.ch [1.2.3.4]
   ----- The following addresses had permanent fatal errors ----- "|/etc/usermin/forward/autoreply.pl /home/info.xxx.ch/autoreply.txt info.treuhand-2000.ch"
    (expanded from: <info@xxx.ch>)
   ----- Transcript of session follows -----
550 5.7.1 /home/info.xxx.ch/.forward: line 2: "|/etc/usermin/forward/autoreply.pl /home/info.xxx.ch/autoreply.txt info.xxx.ch"... User info.xxx.ch@mail.xxx.ch doesn't have a valid shell for mailing to programs

Usually that error message means that the login shell of the affected user is not listed in /etc/shells, so the MTA refuses to honor any pipe destinations in your .forward (because they require invoking your login shell). Either change your login shell to one that is listed in /etc/shells, or add it to /etc/shells.

Our user had the following shell assinged: /sbin/nologin. This shell was not present in /etc/shells – we had to add it, afterwards the issue disappeared. Additionally we also added /usr/bin/nologin to the /etc/shells file.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.