Grommunio Mail Server: Difference between revisions

From Alpine Linux
Line 354: Line 354:


=== Enable IPv6 ===
=== Enable IPv6 ===
Since Grommunio requires IPv6 for its daemons:
First of all, turn on ipv6 which is mandatory for grommunio daemons


Edit `/etc/hosts` to include IPv6 localhost:
Edit `/etc/hosts` to include IPv6 localhost:
Line 360: Line 360:
  -----
  -----
  ::1 localhost ipv6-localhost ipv6-loopback
  ::1 localhost ipv6-localhost ipv6-loopback
-----




Line 371: Line 370:


=== Configure Database Parameters ===
=== Configure Database Parameters ===
Set up your MySQL database connection details:
Specify DB parameters if necessary (already specified above in step 1)


  MYSQL_HOST="localhost"
  MYSQL_HOST="localhost"
Line 380: Line 379:


=== Specify Internal FQDN, Mail Domain, and Relayhost ===
=== Specify Internal FQDN, Mail Domain, and Relayhost ===
The FQDN is for example used by Outlook clients to connect. This name will have to be present in the used certificate.
The default Mail Domain is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.
Adjust the following for your specific setup:
Adjust the following for your specific setup:


Line 389: Line 392:


=== Install Dependencies and Grommunio Packages ===
=== Install Dependencies and Grommunio Packages ===
Install necessary dependencies:
 
Install necessary dependencies (util-linux-login is required to get pam.d working):


  apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login
  apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login
Install grommunio packages:
  apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages
  apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages


Line 397: Line 405:
Optionally, install deprecated ActiveSync if needed:
Optionally, install deprecated ActiveSync if needed:


  # apk add grommunio-dav grommunio-sync
  apk add grommunio-dav grommunio-sync




=== Move Mail Storage to Another Disk ===
=== Move Mail Storage to Another Disk ===
Move the largest directory `/var/lib/gromox` to another disk and create a symlink:
The directory `/var/lib/gromox` will be the largest directory containing all the mails and attachments. We therefore relocate it to another disk and create a symlink:


  mv /var/lib/gromox /srv/gromox
  mv /var/lib/gromox /srv/gromox
Line 408: Line 416:


=== Enable Required Services ===
=== Enable Required Services ===
Enable all necessary Grommunio services:
Enable all required services:


  rc-update add grommunio-admin-api
  rc-update add grommunio-admin-api
  rc-update add gromox-delivery
  rc-update add gromox-delivery
  rc-update add gromox-delivery-queue
  rc-update add gromox-delivery-queue
  # Add all the other grommunio services
  rc-update add gromox-event
rc-update add gromox-http
rc-update add gromox-imap
rc-update add gromox-midb
rc-update add gromox-pop3
rc-update add gromox-timer
rc-update add gromox-zcore
rc-update add valkey@grommunio
rc-update add php-fpm83
rc-update add saslauthd




=== Configure Grommunio Files ===
=== Configure Grommunio ===
Modify the configuration files to match your environment:
Modify the configuration files with the parameters defined above.
 
Configure gromox *.cfg:


  sed -i "s/mail.example.local/${FQDN}/g" /etc/gromox/*.cfg
  sed -i "s/mail.example.local/${FQDN}/g" /etc/gromox/*.cfg
  sed -i "s/example.com/${MAILDOMAIN}/g" /etc/gromox/*.cfg
  sed -i "s/example.com/${MAILDOMAIN}/g" /etc/gromox/*.cfg
# Continue modifying other configuration files (mysql_adaptor.cfg, autodiscover.ini, etc.)




=== Configure Postfix ===
Configure gromox adaptor:
Prepare Postfix for integration with Grommunio:
sed -i "s/<password>/${MYSQL_PASS}/g" /etc/gromox/mysql_adaptor.cfg
cat /etc/gromox/mysql_adaptor.cfg
 
 
Configure autodiscovery:
sed -i "s/mail.example.local/${FQDN}/g" /etc/gromox/autodiscover.ini
sed -i "s/<password>/${MYSQL_PASS}/g" /etc/gromox/autodiscover.ini
cat /etc/gromox/autodiscover.ini
 


Prepare additional postfix file for sender maps:
  cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf
  cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf
  sed -i '/^query =/d' /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf
  sed -i '/^query =/d' /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf
Line 432: Line 459:




=== Configure TLS Certificates ===
Configure postfix files:
Link and configure your SSL certificates:
sed -i "s/<password>/${MYSQL_PASS}/g" /etc/postfix/grommunio*.cf
 
 
Configure TLS certificates:
sed -i "s/mail.example.local/${FQDN}/g" /etc/grommunio-common/nginx/ssl_certificate.conf
sed -i "s/mail.example.local/${FQDN}/g" /etc/grommunio-admin-common/nginx-ssl.conf
 
 
Link TLS certificate configuration:
 
Since both ssl files are identical it might make more sense to link them


  ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf
  ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf
  cat /etc/ssl/private/${FQDN}.key.pem /etc/ssl/certs/${FQDN}.cert.pem > /etc/ssl/private/${FQDN}.key_cert.pem
 
 
Configure grommunio admin:
 
sed -i "s/mail.example.local/${FQDN}/g" /etc/grommunio-admin-common/config.json
sed -i "s/<password>/${MYSQL_PASS}/g" /etc/grommunio-admin-api/conf.d/database.yaml
cat /etc/grommunio-admin-api/conf.d/database.yaml
 
 
Prepare external or self-signed certificate and put them to:
/etc/ssl/certs/${FQDN}.cert.pem
/etc/ssl/private/${FQDN}.key.pem
 
 
Concatenate key and cert as needed by postfix:
  cat /etc/ssl/private/${FQDN}.key.pem \
    /etc/ssl/certs/${FQDN}.cert.pem \
  > /etc/ssl/private/${FQDN}.key_cert.pem
  chmod 640 /etc/ssl/private/*.key_cert.pem
  chmod 640 /etc/ssl/private/*.key_cert.pem
chown root:ssl-cert /etc/ssl/private/*.key_cert.pem
ls -al /etc/ssl/private/
Add gromox to ssl-cert (or another) group allowed to read the private keys:
  addgroup gromox ssl-cert
  addgroup gromox ssl-cert




=== Configure PAM and SASL ===
Retrieve the certificate fingerprint:
Set up authentication services:
 
NOTE: This is only required if you work with a relay server authenticating the client cert.
 
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.
 
openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem
 


Configure PAM for SMTP:
Configure PAM for SMTP:


mv /etc/pam.d/smtp /etc/pam.d/smtp.orig
  cat > /etc/pam.d/smtp <<EOF
  cat > /etc/pam.d/smtp <<EOF
  #%PAM-1.0
  #%PAM-1.0
  auth required pam_gromox.so service=smtp
  # config for grommunio auth services
auth    required pam_gromox.so service=smtp
  account required pam_permit.so
  account required pam_permit.so
  EOF
  EOF
Line 456: Line 523:


  cat > /etc/conf.d/saslauthd <<EOF
  cat > /etc/conf.d/saslauthd <<EOF
# Configuration for /etc/init.d/saslauthd
  SASLAUTHD_OPTS="-a pam -r"
  SASLAUTHD_OPTS="-a pam -r"
  EOF
  EOF
SASL configuration for SMTP service:
mkdir /etc/sasl2
cat > /etc/sasl2/smtpd.conf <<EOF
pwcheck_method: saslauthd
mech_list: plain login
EOF
chmod 600 /etc/sasl2/smtpd.conf
In case you migrate from another server replace X500-org-name with the original one:
X500_ORG_NAME_OLD=$(grep 'x500_org_name=' /etc/gromox/zcore.cfg | cut -d= -f2)
X500_ORG_NAME_NEW=<original-key>
sed -i "s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g" /etc/gromox/*




Line 464: Line 549:


  gromox-dbop -C
  gromox-dbop -C


Set the Grommunio admin password:
Set the Grommunio admin password:


  grommunio-admin passwd --password "${ADMIN_PASS}"
  grommunio-admin passwd --password "${ADMIN_PASS}"
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.
NOTE: Additional custom patch is needed to make the log monitoring work
addgroup grommunio adm




Line 473: Line 567:
Open the necessary firewall ports:
Open the necessary firewall ports:


  # Required ports: 25, 80, 443, etc.
25/tcp
 
80/tcp
 
110/tcp
143/tcp
443/tcp
587/tcp
993/tcp
995/tcp
8080/tcp
8443/tcp


== 7. Configure Valkey (Redis Replacement) ==
== 7. Configure Valkey (Redis Replacement) ==

Revision as of 00:05, 1 December 2024

This material is work-in-progress ...

This is a work in progress
(Last edited by Midas on 1 Dec 2024.)


HOWTO: Install AlpineLinux Mail Server with Grommunio

This tutorial outlines the steps for setting up a mail server on Alpine Linux using Grommunio, a modern, open-source groupware solution that supports email and calendar services. The installation includes MariaDB, Nginx, PHP, Postfix, and other components necessary for a fully functioning mail server.

Prerequisites

Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You'll need root privileges to execute these commands.

Procedure

  1. Install and configure MariaDB
  2. MariaDB performance tuning (optional)
  3. Install and configure Nginx
  4. Install and configure PHP
  5. Install and configure Postfix
  6. Install and configure Grommunio
  7. Configure Valkey (Redis replacement)
  8. Install and configure Rspamd
  9. Finalize and verify installation


1. Install and Configure MariaDB

Install MariaDB

To start, install MariaDB and necessary utilities

apk add mariadb mariadb-client mariadb-server-utils


Define the variables used later in the setup setup and configuration.

The default datapath is /var/lib/mysql and contains the entire database. If you prefer another location define it here and create a symlink. In any case, the grommunio database will be rather small as it only contains the configuration.

DB_DATA_PATH="/srv/mysql"
DB_ROOT_PASS="Passw0rd1"
DB_USER="admin"
DB_PASS="Passw0rd2"


Setup the default system tables:

sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}


Set a symlink to the standard mysql data directory for compatibility reason:

ln -s /srv/mysql /var/lib/mysql


Restart service:

rc-service mariadb restart


Run the built-in security script:

Set the new root password to the one defined above and answer everything with 'y'

sudo mysql_secure_installation


Create MariaDB User for Grommunio

Create a new user for Grommunio and assign privileges:

echo "GRANT ALL ON *.* TO ${DB_USER}@'127.0.0.1' IDENTIFIED BY '${DB_PASS}' WITH GRANT OPTION;" > /tmp/sql
echo "GRANT ALL ON *.* TO ${DB_USER}@'localhost' IDENTIFIED BY '${DB_PASS}' WITH GRANT OPTION;" >> /tmp/sql
echo "GRANT ALL ON *.* TO ${DB_USER}@'::1' IDENTIFIED BY '${DB_PASS}' WITH GRANT OPTION;" >> /tmp/sql
echo "DELETE FROM mysql.user WHERE User=;" >> /tmp/sql
echo "FLUSH PRIVILEGES;" >> /tmp/sql
cat /tmp/sql | mysql -u root --password="${DB_ROOT_PASS}"


Configure MariaDB for Grommunio

Edit the MariaDB configuration for better performance:

vi /etc/my.cnf.d/mariadb-server.cnf


Add the following configuration:

[mysqld]
#skip-networking

## Configuration for grommunio (most values are default)
innodb_log_buffer_size=16M
innodb_log_file_size=32M
innodb_read_io_threads=4
innodb_write_io_threads=4

join_buffer_size=512K
query_cache_size=0
query_cache_type=0
query_cache_limit=2M

# Activate performance schema
performance_schema=ON

# Bind to localhost only
bind-address = 127.0.0.1

# Disable DNS lookups as we only use localhost connections
skip-name-resolve=ON


Create a default charset configuration for MariaDB:

cat > /etc/my.cnf.d/mariadb-server-default-charset.cnf << EOF
[client]
default-character-set = utf8mb4

[mysqld]
collation_server = utf8mb4_general_ci
character_set_server = utf8mb4

[mysql]
default-character-set = utf8mb4
EOF


Restart MariaDB and enable it to start on boot:

rc-update add mariadb default
rc-service mariadb restart


Verify MariaDB Setup

Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):

ss -tulpn

Create Grommunio Database

Define the database parameters and create the Grommunio database:

MYSQL_HOST="localhost"
MYSQL_USER="grommunio"
MYSQL_PASS="Passw0rd3"
MYSQL_DB="grommunio"
echo "create database $MYSQL_DB character set 'utf8mb4';" > /tmp/sql
echo "grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by '$MYSQL_PASS';" >> /tmp/sql
echo "flush privileges;" >> /tmp/sql
cat /tmp/sql | mysql -u admin --password="${DB_PASS}"


Test the database connection:

mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio


2. MariaDB Performance Tuning (Optional)

To assist us in checking and tuning the configuration as per our specific needs, we can install mysqltuner, a script that will provide suggestions to improve the performance of our database server and increase its stability

Download MySQLTuner:

wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl


Move it to the correct directory and set permissions:

mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl
chmod 755 /usr/local/bin/mysqltuner.pl


Install perl:

NOTE: The perl-doc package is installed because it's the only one containing the perldiag.pod required by mysqltuner.pl

apk add perl perl-doc


Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:

/usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}


3. Install and Configure Nginx

Install Nginx

Install the necessary Nginx modules:

apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli


Configure Nginx

Backup the original Nginx configuration and edit it for security headers and TLS settings:

cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig
vi /etc/nginx/nginx.conf


Add the following configuration:

#error_log /var/log/nginx/error.log warn;
error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;

### Common headers for security
# TODO: Set temporary to a lower value until we are sure it's working
#more_set_headers "Strict-Transport-Security : max-age=15768000; includeSubDomains; preload";
more_set_headers "Strict-Transport-Security : max-age=2592000; includeSubDomains;";
more_set_headers "X-Frame-Options : SAMEORIGIN";
more_set_headers "Content-Security-Policy : default-src https: data: 'unsafe-inline' 'unsafe-eval' always";
more_set_headers "X-Xss-Protection : 1; mode=block";
more_set_headers "X-Content-Type-Options : nosniff";
more_set_headers "Referrer-Policy : strict-origin-when-cross-origin";
more_set_headers "Server : Follow the white rabbit.";

### TLS settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

log_format main_ssl '$remote_addr - $remote_user [$time_local] "$request" '
        '$status $body_bytes_sent "$http_referer" '
        '"$http_user_agent" "$http_x_forwarded_for" '
        'client_ciphers="$ssl_ciphers" client_curves="$ssl_curves"';

#access_log /var/log/nginx/access.log main_ssl; # Disabled for performance
#access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance
access_log off;


Disable the default page by renaming it:

mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig


Restart Nginx and enable it to start on boot:

rc-update add nginx
rc-service nginx restart


4. Install and Configure PHP

Install PHP

Install the basic php packages. The modules are installed as grommunio dependencies:

apk add php83 php83-fpm

Disable default fpm conf:

mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default


Harden PHP Configuration

Backup config file /etc/php83/php.ini

cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig


Disable remote PHP code execution:

sed 's/^;\?\(allow_url_fopen\).*/\1 = Off/' -i /etc/php83/php.ini 
sed 's/^;\?\(allow_url_include\).*/\1 = Off/' -i /etc/php83/php.ini 


Disable information leakage:

sed 's/^;\?\(expose_php\).*/\1 = Off/' -i /etc/php83/php.ini 


Configure Error handling:

sed 's/^;\?\(display_errors\).*/\1 = Off/' -i /etc/php83/php.ini 
sed 's/^;\?\(display_startup_errors\).*/\1 = Off/' -i /etc/php83/php.ini 
sed 's/^;\?\(log_errors\).*/\1 = On/' -i /etc/php83/php.ini 
sed 's/^;\?\(error_log = syslog\).*/\1/' -i /etc/php83/php.ini 


PHP Resource Control (Optional):

#sed 's/^\(max_execution_time\).*/\1 = 25/' -i /etc/php83/php.ini 
#sed 's/^\(max_input_time\).*/\1 = 25/' -i /etc/php83/php.ini 
#sed 's/^\(memory_limit\).*/\1 = 30M/' -i /etc/php83/php.ini 
#sed 's/^\(post_max_size\).*/\1 = 1M/' -i /etc/php83/php.ini 
#sed 's/^;\?\(max_input_vars\).*/\1 = 1000/' -i /etc/php83/php.ini 


Disable vulnerable functions:

sed 's/^\(disable_functions\).*/\1 = apache_note, apache_setenv, chgrp, curl_multi_exec, define_sys, define_syslog_variables, debugger_off, debugger_on, diskfreespace, _getppid, escapeshellarg, escapeshellcmd, exec, getmyuid, ini_restore, leak, listen, parse_ini_file, passthru, pcntl_alarm, pcntl_async_signals, pcntl_exec, pcntl_fork, pcntl_get_last_error, pcntl_getpriority, pcntl_setpriority, pcntl_signal, pcntl_signal_dispatch, pcntl_signal_get_handler, pcntl_sigprocmask, pcntl_sigtimedwait, pcntl_sigwaitinfo, pcntl_strerror, pcntl_unshare, pcntl_wait, pcntl_waitpid, pcntl_wexitstatus, pcntl_wifcontinued, pcntl_wifexited, pcntl_wifsignaled, pcntl_wifstopped, pcntl_wstopsig, pcntl_wtermsig, posix, posix_ctermid, posix_getcwd, posix_getegid, posix_geteuid, posix_getgid, posix_getgrgid, posix_getgrnam, posix_getgroups, posix_getlogin, posix_getpgid, posix_getpgrp, posix_getpid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_getsid, posix_isatty, posix_kill, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, posix_times, posix_ttyname, posix_uname, popen, proc_close, proc_get_status, proc_nice, proc_open, proc_terminate, shell_exec, show_source, system, url_exec/' -i /etc/php83/php.ini 


Harden Session Security:

sed 's/^;\?\(session.use_strict_mode\).*/\1 = 1/' -i /etc/php83/php.ini 
sed 's/^;\?\(session.use_cookies\).*/\1 = 1/' -i /etc/php83/php.ini 
sed 's/^;\?\(session.cookie_secure\).*/\1 = 1/' -i /etc/php83/php.ini 
sed 's/^;\?\(session.use_only_cookies\).*/\1 = 1/' -i /etc/php83/php.ini 
sed 's/^;\?\(session.cookie_httponly\).*/\1 = 1/' -i /etc/php83/php.ini

5. Install and Configure Postfix

Install Postfix

Install the required packages:

apk add postfix postfix-mysql postfix-pcre


Configure Postfix

First backup the original files:

mv /etc/postfix/main.cf /etc/postfix/main.cf.orig
mv /etc/postfix/master.cf /etc/postfix/master.cf.orig
mv /etc/postfix/header_checks /etc/postfix/header_checks.orig


Download the configuration files

TODO


Copy the prepared configuration files. Ensure you adapt at least the following values:

main.cf: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, 
        virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions
master.cf: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem


Create the required postmap files:

newaliases
postmap /etc/postfix/transport


Run Postfix setup:

newaliases
postmap /etc/postfix/transport


Enable the postfix service and restart:

rc-update add postfix
rc-service postfix restart


Verify Postfix Logs

Check the Postfix logs for any errors:

tail -f /var/log/maillog


6. Install and Configure Grommunio

Enable IPv6

First of all, turn on ipv6 which is mandatory for grommunio daemons

Edit `/etc/hosts` to include IPv6 localhost:

vi /etc/hosts
-----
::1		localhost ipv6-localhost ipv6-loopback


Ensure IPv6 is enabled in `/etc/sysctl.conf`:

sed -i 's/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&/' /etc/sysctl.conf
sysctl -p
ping ::1  # Test if IPv6 is working


Configure Database Parameters

Specify DB parameters if necessary (already specified above in step 1)

MYSQL_HOST="localhost"
MYSQL_USER="grommunio"
MYSQL_PASS="Passw0rd3"
MYSQL_DB="grommunio"


Specify Internal FQDN, Mail Domain, and Relayhost

The FQDN is for example used by Outlook clients to connect. This name will have to be present in the used certificate.

The default Mail Domain is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.

Adjust the following for your specific setup:

FQDN="mail.example.local"
MAILDOMAIN="example.com"
RELAYHOST="123.123.123.1"
ADMIN_PASS="Passw0rd4"


Install Dependencies and Grommunio Packages

Install necessary dependencies (util-linux-login is required to get pam.d working):

apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login


Install grommunio packages:

apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages


Optionally, install deprecated ActiveSync if needed:

apk add grommunio-dav grommunio-sync


Move Mail Storage to Another Disk

The directory `/var/lib/gromox` will be the largest directory containing all the mails and attachments. We therefore relocate it to another disk and create a symlink:

mv /var/lib/gromox /srv/gromox
ln -s /srv/gromox /var/lib/gromox


Enable Required Services

Enable all required services:

rc-update add grommunio-admin-api
rc-update add gromox-delivery
rc-update add gromox-delivery-queue
rc-update add gromox-event
rc-update add gromox-http
rc-update add gromox-imap
rc-update add gromox-midb
rc-update add gromox-pop3
rc-update add gromox-timer
rc-update add gromox-zcore
rc-update add valkey@grommunio
rc-update add php-fpm83 
rc-update add saslauthd


Configure Grommunio

Modify the configuration files with the parameters defined above.

Configure gromox *.cfg:

sed -i "s/mail.example.local/${FQDN}/g" /etc/gromox/*.cfg
sed -i "s/example.com/${MAILDOMAIN}/g" /etc/gromox/*.cfg


Configure gromox adaptor:

sed -i "s/<password>/${MYSQL_PASS}/g" /etc/gromox/mysql_adaptor.cfg
cat /etc/gromox/mysql_adaptor.cfg


Configure autodiscovery:

sed -i "s/mail.example.local/${FQDN}/g" /etc/gromox/autodiscover.ini
sed -i "s/<password>/${MYSQL_PASS}/g" /etc/gromox/autodiscover.ini
cat /etc/gromox/autodiscover.ini


Prepare additional postfix file for sender maps:

cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf
sed -i '/^query =/d' /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf
echo "query = SELECT username FROM users WHERE username='%s' UNION SELECT aliasname FROM aliases WHERE mainname='%s'" >> /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf


Configure postfix files:

sed -i "s/<password>/${MYSQL_PASS}/g" /etc/postfix/grommunio*.cf


Configure TLS certificates:

sed -i "s/mail.example.local/${FQDN}/g" /etc/grommunio-common/nginx/ssl_certificate.conf
sed -i "s/mail.example.local/${FQDN}/g" /etc/grommunio-admin-common/nginx-ssl.conf


Link TLS certificate configuration:

Since both ssl files are identical it might make more sense to link them

ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf


Configure grommunio admin:

sed -i "s/mail.example.local/${FQDN}/g" /etc/grommunio-admin-common/config.json
sed -i "s/<password>/${MYSQL_PASS}/g" /etc/grommunio-admin-api/conf.d/database.yaml
cat /etc/grommunio-admin-api/conf.d/database.yaml


Prepare external or self-signed certificate and put them to:

/etc/ssl/certs/${FQDN}.cert.pem
/etc/ssl/private/${FQDN}.key.pem


Concatenate key and cert as needed by postfix:

cat /etc/ssl/private/${FQDN}.key.pem \
    /etc/ssl/certs/${FQDN}.cert.pem \
  > /etc/ssl/private/${FQDN}.key_cert.pem
chmod 640 /etc/ssl/private/*.key_cert.pem
chown root:ssl-cert /etc/ssl/private/*.key_cert.pem
ls -al /etc/ssl/private/


Add gromox to ssl-cert (or another) group allowed to read the private keys:

addgroup gromox ssl-cert


Retrieve the certificate fingerprint:

NOTE: This is only required if you work with a relay server authenticating the client cert.

Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.

openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem


Configure PAM for SMTP:

mv /etc/pam.d/smtp /etc/pam.d/smtp.orig
cat > /etc/pam.d/smtp <<EOF
#%PAM-1.0
# config for grommunio auth services
auth    required pam_gromox.so service=smtp
account required pam_permit.so
EOF


Configure SASL authentication:

cat > /etc/conf.d/saslauthd <<EOF
# Configuration for /etc/init.d/saslauthd
SASLAUTHD_OPTS="-a pam -r"
EOF


SASL configuration for SMTP service:

mkdir /etc/sasl2
cat > /etc/sasl2/smtpd.conf <<EOF
pwcheck_method: saslauthd
mech_list: plain login
EOF
chmod 600 /etc/sasl2/smtpd.conf


In case you migrate from another server replace X500-org-name with the original one:

X500_ORG_NAME_OLD=$(grep 'x500_org_name=' /etc/gromox/zcore.cfg | cut -d= -f2)
X500_ORG_NAME_NEW=<original-key>
sed -i "s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g" /etc/gromox/*


Initialize the Database and Set Admin Password

Initialize the database:

gromox-dbop -C


Set the Grommunio admin password:

grommunio-admin passwd --password "${ADMIN_PASS}"


Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.

NOTE: Additional custom patch is needed to make the log monitoring work

addgroup grommunio adm


Configure Firewall Ports

Open the necessary firewall ports:

25/tcp
80/tcp
110/tcp
143/tcp
443/tcp
587/tcp
993/tcp
995/tcp
8080/tcp
8443/tcp

7. Configure Valkey (Redis Replacement)

Enable Syslog

 vi /etc/valkey/grommunio.conf
 -----
 syslog-enabled yes
 syslog-ident valkey
 syslog-facility local0
 -----


Enable Memory Overcommit

 vi /etc/sysctl.conf
 -----
 vm.overcommit_memory = 1
 -----
 sysctl -p


Start Valkey and Test

 rcctl restart valkey@grommunio
 valkey-cli ping  # Expected result: 'PONG'


8. Install and Configure Rspamd

Install Rspamd

 apk add rspamd rspamd-client


Configure Rspamd

Modify Rspamd configuration files:

 cat > /etc/rspamd/local.d/options.inc <<EOF
 dns {
   enable_dnssec = true;
   timeout = 4s;
  retransmits = 5;
 }
 EOF
 cat > /etc/rspamd/local.d/redis.conf <<EOF
 read_servers = "127.0.0.1";
 write_servers = "127.0.0.1";
 EOF
 cat > /etc/rspamd/local.d/worker-proxy.inc <<EOF
 milter = yes;
 bind_socket = "/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd";
 timeout = 120s;
 upstream "local" {
   default = yes;
   self_scan = yes;
 }
 count = 4;
 EOF


Add Postfix to Rspamd Group

 addgroup postfix rspamd


Configure DKIM Signing

 cat > /etc/rspamd/local.d/dkim_signing.conf <<EOF
 enabled = true;
 path = "/var/lib/rspamd/dkim/\$domain-\$selector.key";
 selector = "dkim";
 sign_authenticated = true;
 sign_local = false;
 domain {
   example.com { selector = "202406"; }
 }
 EOF


Generate DKIM Key Pair

 mkdir -p /var/lib/rspamd/dkim
 rspamadm dkim_keygen -s 202406 -t ED25519 -d example.com -k /var/lib/rspamd/dkim/example.com-202406.key > 
 /var/lib/rspamd/dkim/example.com-202406.pub


Start Rspamd

 rc-update add rspamd
 rcctl start rspamd


9. Finalize and Verify Installation

Restart Services

Restart all services:

 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \
   gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \
   grommunio-admin-api


Verify Service Status

Check the status of all services:

 rcctl status


Ensure that all services (Postfix, MariaDB, Nginx, PHP, Grommunio) are running correctly:

 ss -tulpn


Verify Mail Functionality

Test sending and receiving emails using a mail client and verifying server logs for any errors.


Check Logs

Inspect logs for any errors or issues:

 find /var/log -type f | xargs tail -n50 | grep -iE '==>|fail|crit|error|alert|corrupt|warning'


Web UI Access

Admin UI: [1](https://mail.example.local:8443)


10. End User Configuration

Admin UI

Log into the Admin UI with the username `admin` and the previously created `ADMIN_PASS`.

License Configuration

If you have a license, you can configure it under Grommunio settings in the Admin UI.