<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.alpinelinux.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Midas</id>
	<title>Alpine Linux - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.alpinelinux.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Midas"/>
	<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/wiki/Special:Contributions/Midas"/>
	<updated>2026-04-30T05:15:21Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28878</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28878"/>
		<updated>2025-01-31T09:16:35Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Create MariaDB User */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mariadb -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mariadb -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mariadb -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
== 2. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 6. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 7. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
== 8. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28877</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28877"/>
		<updated>2025-01-31T09:16:12Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Create Grommunio Database */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mariadb -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mariadb -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
== 2. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 6. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 7. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
== 8. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28876</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28876"/>
		<updated>2025-01-31T09:14:06Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 9. Finalize and Verify */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 6. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 7. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
== 8. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28875</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28875"/>
		<updated>2025-01-31T09:13:59Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 8. Install and Configure Rspamd */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 6. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 7. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28874</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28874"/>
		<updated>2025-01-31T09:13:52Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 7. Configure Valkey */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 6. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28873</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28873"/>
		<updated>2025-01-31T09:13:44Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 6. Install and Configure Grommunio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28872</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28872"/>
		<updated>2025-01-31T09:13:32Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 5. Install and Configure Postfix */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28871</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28871"/>
		<updated>2025-01-31T09:13:19Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 4. Install and Configure PHP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28870</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28870"/>
		<updated>2025-01-31T09:13:07Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 3. Install and Configure Nginx */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28869</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28869"/>
		<updated>2025-01-31T09:12:46Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 2. MariaDB Performance Tuning (Optional) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28868</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28868"/>
		<updated>2025-01-31T09:12:28Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Procedure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28721</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28721"/>
		<updated>2025-01-09T11:13:59Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Enable IPv6 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to make sure that IPv6 localhost in configured:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28720</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28720"/>
		<updated>2025-01-09T11:11:18Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Enable Memory Overcommit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment in sysctl. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Enable memory overcommit for valkey&lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28719</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28719"/>
		<updated>2025-01-09T11:10:02Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Enable Memory Overcommit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
 vi /etc/sysctl.conf&lt;br /&gt;
 -----&lt;br /&gt;
 # Enable memory overcommit for valkey  &lt;br /&gt;
 vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28718</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28718"/>
		<updated>2025-01-09T11:09:01Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Admin UI - First steps */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28717</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28717"/>
		<updated>2025-01-09T11:07:50Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Restart Services */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 \&lt;br /&gt;
     gromox-delivery gromox-delivery-queue gromox-event gromox-http gromox-imap \&lt;br /&gt;
     gromox-midb gromox-pop3 gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28716</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28716"/>
		<updated>2025-01-09T11:06:32Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Restart Services */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery \&lt;br /&gt;
     gromox-event gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue \&lt;br /&gt;
     gromox-timer gromox-zcore grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28715</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28715"/>
		<updated>2025-01-09T11:05:46Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Configure Rspamd */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28714</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28714"/>
		<updated>2025-01-09T11:04:43Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Initialize Database */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch (provided by the alpinelinuxsupport.com team) is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28713</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28713"/>
		<updated>2025-01-09T11:03:24Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Initialize Database */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28712</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28712"/>
		<updated>2025-01-09T11:02:39Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Install perl */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28711</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28711"/>
		<updated>2025-01-09T11:02:20Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 7. Configure Valkey */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable jemalloc ===&lt;br /&gt;
&lt;br /&gt;
Disable jemalloc background threads as we use libc malloc&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/&amp;quot; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Reduce maxclients ===&lt;br /&gt;
&lt;br /&gt;
Reduce the maxclients to avoid the error message regarding maximum open files&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;maxclients 4064&amp;quot; &amp;gt;&amp;gt; /etc/valkey/grommunio.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Valkey insists in enabling memory overcommitment. If not set, a startup warning is shown&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28710</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28710"/>
		<updated>2025-01-09T10:54:58Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 7. Configure Valkey */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28709</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28709"/>
		<updated>2025-01-09T10:53:36Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Configure Grommunio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 USERGROUPS_ENAB yes&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28708</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28708"/>
		<updated>2025-01-09T10:52:29Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Configure Grommunio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create default login.defs (missing in util-linux-login):&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/login.defs &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # By default, create a group with the name of the user&lt;br /&gt;
 echo &amp;quot;USERGROUPS_ENAB yes&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28707</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28707"/>
		<updated>2025-01-09T10:44:09Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Harden PHP Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) set allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In case you need &#039;&#039;grommunio-sync&#039;&#039; (ActiveSync) remove escapeshellarg &amp;amp; exec&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28706</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28706"/>
		<updated>2025-01-09T10:39:33Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 4. Install and Configure PHP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; grommunio-sync requires allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28705</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28705"/>
		<updated>2025-01-09T10:37:03Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Harden PHP Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
NOTE: grommunio-sync requires allow_url_fopen=On&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28631</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28631"/>
		<updated>2025-01-02T11:11:32Z</updated>

		<summary type="html">&lt;p&gt;Midas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login linux-pam util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Mail]]&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28008</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28008"/>
		<updated>2024-12-02T08:04:13Z</updated>

		<summary type="html">&lt;p&gt;Midas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
=== Download MySQLTuner ===&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install perl ===&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Execute the script ===&lt;br /&gt;
&lt;br /&gt;
You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28007</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28007"/>
		<updated>2024-12-01T21:03:15Z</updated>

		<summary type="html">&lt;p&gt;Midas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial covers the steps to set up a mail server on &#039;&#039;&#039;Alpine Linux&#039;&#039;&#039; using &#039;&#039;&#039;grommunio&#039;&#039;&#039;, an open-source groupware solution that supports email, calendar, and task management. Grommunio stands out with its unique &#039;&#039;&#039;MAPI&#039;&#039;&#039; support, enabling seamless integration with Microsoft Outlook and other MAPI clients, making it an ideal choice for open-source alternatives to proprietary systems. The setup includes essential components like &#039;&#039;&#039;MariaDB&#039;&#039;&#039;, &#039;&#039;&#039;Nginx&#039;&#039;&#039;, &#039;&#039;&#039;PHP&#039;&#039;&#039;, and &#039;&#039;&#039;Postfix&#039;&#039;&#039; to create a fully functional mail server. Follow along to build a secure, scalable communication platform using grommunio&#039;s powerful features.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28003</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28003"/>
		<updated>2024-12-01T01:04:57Z</updated>

		<summary type="html">&lt;p&gt;Midas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28002</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28002"/>
		<updated>2024-12-01T01:04:08Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 1. Install and Configure MariaDB */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28001</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28001"/>
		<updated>2024-12-01T01:03:15Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 9. Finalize and Verify Installation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28000</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=28000"/>
		<updated>2024-12-01T01:02:44Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 6. Install and Configure Grommunio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27999</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27999"/>
		<updated>2024-12-01T01:02:30Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 6. Install and Configure Grommunio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize Database ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27998</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27998"/>
		<updated>2024-12-01T01:02:01Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 6. Install and Configure Grommunio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Relocate Mail Storage ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27997</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27997"/>
		<updated>2024-12-01T01:01:18Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 6. Install and Configure Grommunio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Domain Parameters ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Move Mail Storage to Another Disk ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27996</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27996"/>
		<updated>2024-12-01T00:59:22Z</updated>

		<summary type="html">&lt;p&gt;Midas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Specify Internal FQDN, Mail Domain, and Relayhost ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Install Dependencies and Grommunio Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Move Mail Storage to Another Disk ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27995</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27995"/>
		<updated>2024-12-01T00:58:58Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Configure Postfix */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you change at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Specify Internal FQDN, Mail Domain, and Relayhost ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Install Dependencies and Grommunio Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Move Mail Storage to Another Disk ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27994</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27994"/>
		<updated>2024-12-01T00:58:25Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Configure Postfix */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files to `/etc/postfix/` and adapt the configuration to your environment. Ensure you adapt at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Specify Internal FQDN, Mail Domain, and Relayhost ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Install Dependencies and Grommunio Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Move Mail Storage to Another Disk ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27993</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27993"/>
		<updated>2024-12-01T00:57:03Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Configure Postfix */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the prepared configuration files:&lt;br /&gt;
&lt;br /&gt;
 https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files. Ensure you adapt at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Specify Internal FQDN, Mail Domain, and Relayhost ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Install Dependencies and Grommunio Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Move Mail Storage to Another Disk ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27992</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27992"/>
		<updated>2024-12-01T00:56:42Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Configure Postfix */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the configuration files&lt;br /&gt;
&lt;br /&gt;
 https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files. Ensure you adapt at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Specify Internal FQDN, Mail Domain, and Relayhost ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Install Dependencies and Grommunio Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Move Mail Storage to Another Disk ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27991</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27991"/>
		<updated>2024-12-01T00:56:15Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 5. Install and Configure Postfix */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the configuration files&lt;br /&gt;
https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files. Ensure you adapt at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Specify Internal FQDN, Mail Domain, and Relayhost ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Install Dependencies and Grommunio Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Move Mail Storage to Another Disk ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Tutorials_and_Howtos&amp;diff=27990</id>
		<title>Tutorials and Howtos</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Tutorials_and_Howtos&amp;diff=27990"/>
		<updated>2024-12-01T00:45:49Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Miscellaneous */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Todo|This material has been re-organized..., but grouping should be checked: &#039;&#039;&#039;Howtos are smaller articles&#039;&#039;&#039; and &#039;&#039;&#039;tutorials are more detailed document&#039;&#039;&#039;}}&lt;br /&gt;
&lt;br /&gt;
[[Image:package_edutainment.svg|right|link=]]&lt;br /&gt;
{{TOC left}}&lt;br /&gt;
&#039;&#039;&#039;Welcome to Tutorials and Howtos, a place of basic and advanced configuration tasks for your Alpine Linux.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The tutorials are hands-on&#039;&#039;&#039; and the reader is expected to try and achieve the goals described in each step, possibly with the help of a good example. The output in one step is the starting point for the following step.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Howtos are smaller articles&#039;&#039;&#039; explaining how to perform a particular task with Alpine Linux, that expects a minimal knowledge from reader to perform actions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; contributions on those pages must be complete articles as well as requesting topics to be covered, don&#039;t override already made contributions. If you want to request a topic, please add your request in this page&#039;s [[Talk:Tutorials_and_Howtos|Discussion]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Clear}}&lt;br /&gt;
&lt;br /&gt;
= Howtos =&lt;br /&gt;
&lt;br /&gt;
== Applications ==&lt;br /&gt;
&lt;br /&gt;
=== Miscellaneous ===&lt;br /&gt;
&lt;br /&gt;
* [[Ansible]] &#039;&#039;(Configuration management)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Monitoring ===&lt;br /&gt;
&lt;br /&gt;
* [[Awstats]] &#039;&#039;(Free log file analyzer)&#039;&#039;&lt;br /&gt;
* [[Cacti: traffic analysis and monitoring network]] &#039;&#039;(Front-end for rrdtool networking monitor)&#039;&#039;&lt;br /&gt;
* [[Cvechecker]] &#039;&#039;(Compare installed packages for Common Vulnerabilities Exposure)&#039;&#039; &amp;lt;!-- Monitoring and Security --&amp;gt;&lt;br /&gt;
* [[Linfo]]&lt;br /&gt;
* [[Obtaining user information via SNMP]] &#039;&#039;(Using squark-auth-snmp as a Squid authentication helper)&#039;&#039; &amp;lt;!-- Networking and Server, &amp;lt;== Using squark-auth-snmp --&amp;gt;&lt;br /&gt;
* [[PhpSysInfo]] &#039;&#039;(A simple application that displays information about the host it&#039;s running on)&#039;&#039;&lt;br /&gt;
* [[Matomo]] &#039;&#039;(A real time web analytics software program)&#039;&#039;&lt;br /&gt;
* [[Setting up A Network Monitoring and Inventory System]] &#039;&#039;(Nagios + OpenAudit and related components)&#039;&#039; &amp;lt;!-- draft, solution, Networking and Monitoring and Server --&amp;gt;&lt;br /&gt;
** [[Setting up NRPE daemon]] &#039;&#039;(Performs remote Nagios checks)&#039;&#039; &amp;lt;!-- Networking and Monitoring --&amp;gt;&lt;br /&gt;
* [[Setting Up Fprobe And Ntop|Ntop]] &#039;&#039;(NetFlow collection and analysis using a remote fprobe instance; for alpine 3.10-3.12 only)&#039;&#039; &amp;lt;!-- Networking and Monitoring --&amp;gt;&lt;br /&gt;
* [[Setting up lm_sensors]]&lt;br /&gt;
* [[SqStat]] &#039;&#039;(Script to look at active squid users connections)&#039;&#039;&lt;br /&gt;
* [[Traffic monitoring]] &amp;lt;!-- Networking and Monitoring --&amp;gt;&lt;br /&gt;
** [[Setting up monitoring using rrdtool (and rrdcollect)]]&lt;br /&gt;
** [[Setting up traffic monitoring using rrdtool (and snmp)]] &amp;lt;!-- Monitoring --&amp;gt;&lt;br /&gt;
* [[Zabbix|Zabbix - the professional complete manager]] &#039;&#039;(Monitor and track the status of network services and hardware)&#039;&#039;&lt;br /&gt;
* [[ZoneMinder video camera security and surveillance]]&lt;br /&gt;
&lt;br /&gt;
=== Networking ===&lt;br /&gt;
&lt;br /&gt;
* Alpine Wall &#039;&#039;(a new firewall management framework)&#039;&#039;&lt;br /&gt;
** [[Alpine Wall]]&lt;br /&gt;
** [https://git.alpinelinux.org/awall/about/ Alpine Wall User&#039;s Guide]&lt;br /&gt;
** [[How-To Alpine Wall]]&lt;br /&gt;
* [[Freeradius Active Directory Integration]]&lt;br /&gt;
* [[GNUnet]]&lt;br /&gt;
* [[Setting up a OpenVPN server|OpenVPN server]] &#039;&#039;(Allowing single users or devices to remotely connect to your network)&#039;&#039;&lt;br /&gt;
* [[OpenVSwitch]]&lt;br /&gt;
* [[Using Alpine on Windows domain with IPSEC isolation]]&lt;br /&gt;
* [[Configure a Wireguard interface (wg)|Wireguard]]&lt;br /&gt;
&lt;br /&gt;
=== Telephony ===&lt;br /&gt;
&lt;br /&gt;
* [[FreePBX|FreePBX on Alpine Linux]]&lt;br /&gt;
* [[Setting up Zaptel/Asterisk on Alpine]]&lt;br /&gt;
* [[Kamailio]] &#039;&#039;(SIP Server, formerly OpenSER)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Backup and data migration ==&lt;br /&gt;
&lt;br /&gt;
* [[Alpine local backup|Alpine local backup (lbu)]] &#039;&#039;(Permanently store your modifications in case your box needs reboot)&#039;&#039;&lt;br /&gt;
** [[Back Up a Flash Memory Installation]]&lt;br /&gt;
** [[Manually editing a existing apkovl]]&lt;br /&gt;
* [[Migrating data]]&lt;br /&gt;
* [[Rsnapshot]] - setting up periodic backups&lt;br /&gt;
&lt;br /&gt;
== Desktop ==&lt;br /&gt;
* [[Daily driver guide]]&lt;br /&gt;
* [[Alpine and UEFI]]&lt;br /&gt;
* [[Default applications]]&lt;br /&gt;
* Desktop cloud&lt;br /&gt;
** [[Nextcloud]] &#039;&#039;(Self hostable cloud suite - Dropbox Alternative)&#039;&#039;&lt;br /&gt;
* [[Desktop environments and Window managers]] (overall information only)&lt;br /&gt;
* [[Gaming on Alpine]]&lt;br /&gt;
* [[Printer Setup]]&lt;br /&gt;
* [[Remote Desktop Server]]&lt;br /&gt;
* Sound Systems&lt;br /&gt;
** [[ALSA]]&lt;br /&gt;
** [[PipeWire]]&lt;br /&gt;
** [[PulseAudio]]&lt;br /&gt;
&lt;br /&gt;
== Power management ==&lt;br /&gt;
&lt;br /&gt;
* [[Configure action when power-button is pressed]]&lt;br /&gt;
* [[Suspend on LID close]]&lt;br /&gt;
* [[Configure Wake-on-LAN]]&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
&lt;br /&gt;
* [[Bluetooth]] - Instructions for installing and configuring Bluetooth&lt;br /&gt;
* [[Bonding]] - Bond (or aggregate) multiple ethernet interfaces&lt;br /&gt;
* [[Bridge]] - Configuring a network bridge&lt;br /&gt;
** [[Bridge wlan0 to eth0]]&lt;br /&gt;
* [[Configure Networking]]&lt;br /&gt;
* [[How to configure static routes]]&lt;br /&gt;
* Modem&lt;br /&gt;
** [[Using HSDPA modem]]&lt;br /&gt;
** [[Using serial modem]]&lt;br /&gt;
* [[mDNS]] - Howto implement multicast DNS resolution in Alpine. &lt;br /&gt;
* [[Multi ISP]] &#039;&#039;(Dual-ISP setup with load-balancing and automatic failover)&#039;&#039;&lt;br /&gt;
* [[PXE boot]]&lt;br /&gt;
* Wi-Fi&lt;br /&gt;
** [[Wi-Fi|Connecting to a wireless access point]]&lt;br /&gt;
** [[How to setup a wireless access point]] &#039;&#039;(Setting up Secure Wireless AP w/ WPA encryption with bridge to wired network)&#039;&#039;&lt;br /&gt;
* [[VLAN]]&lt;br /&gt;
&lt;br /&gt;
== Other Architectures ==&lt;br /&gt;
&lt;br /&gt;
=== ARM ===&lt;br /&gt;
&lt;br /&gt;
* [[Alpine on ARM]]&lt;br /&gt;
&lt;br /&gt;
==== Raspberry Pi ====&lt;br /&gt;
&lt;br /&gt;
* [[Raspberry Pi Bluetooth Speaker|Raspberry Pi - Bluetooth Speaker]]&lt;br /&gt;
* [[Raspberry Pi|Raspberry Pi - Installation]]&lt;br /&gt;
* [[Linux Router with VPN on a Raspberry Pi|Raspberry Pi - Router with VPN]]&lt;br /&gt;
* [[Linux Router with VPN on a Raspberry Pi (IPv6)|Raspberry Pi - Router with VPN (IPv6)]]&lt;br /&gt;
* [[Classic install or sys mode on Raspberry Pi|Raspberry Pi - Sys mode install]]&lt;br /&gt;
* [[Raspberry Pi LVM on LUKS|Raspberry Pi - Sys mode install - LVM on LUKS]]&lt;br /&gt;
* [[RPI Video Receiver|Raspberry Pi - Video Receiver]] &#039;&#039;(network video decoder using Rasperry Pi and omxplayer)&#039;&#039;&lt;br /&gt;
* [[Raspberry Pi 3 - Browser Client]] - kiosk or digital sign&lt;br /&gt;
* [[Raspberry Pi 3 - Configuring it as wireless access point -AP Mode]]&lt;br /&gt;
* [[Raspberry Pi 3 - Setting Up Bluetooth]]&lt;br /&gt;
* [[Raspberry Pi 4 - Persistent system acting as a NAS and Time Machine]]&lt;br /&gt;
* [[How to set up Alpine as a wireless router|Raspberry Pi Zero W - Wireless router]] &#039;&#039;(Setting up a firewalled, Wireless AP with wired network on a Pi Zero W)&#039;&#039;&lt;br /&gt;
* [[RPI Video Receiver]]&lt;br /&gt;
&lt;br /&gt;
=== IBM Z (IBM z Systems) ===&lt;br /&gt;
&lt;br /&gt;
* [[s390x|s390x - Installation]]&lt;br /&gt;
&lt;br /&gt;
=== PowerPC ===&lt;br /&gt;
&lt;br /&gt;
* [[Ppc64le|Powerpc64le - Installation]]&lt;br /&gt;
&lt;br /&gt;
== Post-Install ==&lt;br /&gt;
&lt;br /&gt;
* [[CPU frequency scaling]]&lt;br /&gt;
* [[Repositories#Enabling_the_community_repository|Enable Community repository]] &#039;&#039;(Providing additional packages)&#039;&#039;&lt;br /&gt;
* [[Enable Serial Console on Boot]]&lt;br /&gt;
* [[Alpine Linux Init System|Init System (OpenRC)]] &#039;&#039;(Configure a service to automatically boot at next reboot)&#039;&#039;&lt;br /&gt;
** [[Multiple Instances of Services|Init System - Multiple Instances of Services]]&lt;br /&gt;
** [[Writing Init Scripts|Init System - Writing Init Scripts]]&lt;br /&gt;
* [[Installing Oracle Java|Oracle Java (installation)]]&lt;br /&gt;
* [[IGMPproxy]]&lt;br /&gt;
* [[Alpine Package Keeper|Package Management (apk)]] &#039;&#039;(How to add/remove packages on your Alpine)&#039;&#039;&lt;br /&gt;
** [[Comparison with other distros|Package Management - Comparison with other distros]]&lt;br /&gt;
* [[Running glibc programs]]&lt;br /&gt;
* [[Setting up a new user]]&lt;br /&gt;
* [[Upgrading Alpine]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Remote Administration ==&lt;br /&gt;
&lt;br /&gt;
* ACF&lt;br /&gt;
** [[Changing passwords for ACF|ACF - changing passwords]]&lt;br /&gt;
** [[Generating SSL certs with ACF]] &amp;lt;!-- Generating SSL certs with ACF 1.9 --&amp;gt;&lt;br /&gt;
** [[setup-acf| ACF - setup]] &#039;&#039;(Configures ACF (webconfiguration/webmin) so you can manage your box through https)&#039;&#039;&lt;br /&gt;
* [[Setting up a SSH server]] &#039;&#039;(Using ssh is a good way to administer your box remotely)&#039;&#039;&lt;br /&gt;
** [[HOWTO OpenSSH 2FA with password and Google Authenticator |OpenSSH 2FA]] &#039;&#039;(A simple two factor setup for OpenSSH)&#039;&#039;&lt;br /&gt;
* [[OpenVCP]] &#039;&#039;(VServer Control Panel)&#039;&#039;&lt;br /&gt;
* [[PhpMyAdmin]] &#039;&#039;(Web-based administration tool for MYSQL)&#039;&#039;&lt;br /&gt;
* [[PhpPgAdmin]] &#039;&#039;(Web-based administration tool for PostgreSQL)&#039;&#039;&lt;br /&gt;
* [[Webmin]] &#039;&#039;(A web-based interface for Linux system)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Server ==&lt;br /&gt;
&lt;br /&gt;
* [[Hosting services on Alpine]] &#039;&#039;(Hosting mail, webservices and other services)&#039;&#039;&lt;br /&gt;
* [[Hosting Web/Email services on Alpine]]&lt;br /&gt;
&lt;br /&gt;
=== DNS ===&lt;br /&gt;
&lt;br /&gt;
* [[DNSCrypt-Proxy]] &#039;&#039;Encrypt and authenticate DNS calls from your system&#039;&#039;&lt;br /&gt;
* [[Setting up nsd DNS server]]&lt;br /&gt;
* [[Setting up unbound DNS server]]&lt;br /&gt;
* [[TinyDNS Format]]&lt;br /&gt;
&lt;br /&gt;
=== HTTP ===&lt;br /&gt;
&lt;br /&gt;
* [[Apache]]&lt;br /&gt;
** [[Apache with php-fpm]]&lt;br /&gt;
** [[Setting Up Apache with PHP]]&lt;br /&gt;
** [[Apache authentication: NTLM Single Signon]]&lt;br /&gt;
* [[Darkhttpd]]&lt;br /&gt;
* [[Lighttpd]]&lt;br /&gt;
** [[Lighttpd Advanced security]]&lt;br /&gt;
** [[Setting Up Lighttpd With FastCGI]]&lt;br /&gt;
* [[Nginx]]&lt;br /&gt;
** [[Nginx as reverse proxy with acme (letsencrypt)]]&lt;br /&gt;
** [[Nginx with PHP]]&lt;br /&gt;
* Squid Proxy&lt;br /&gt;
** [[Obtaining user information via SNMP]] &#039;&#039;(Using squark-auth-snmp as a Squid authentication helper)&#039;&#039; &amp;lt;!-- Networking and Server, &amp;lt;== Using squark-auth-snmp --&amp;gt;&lt;br /&gt;
** [[Setting up Explicit Squid Proxy]]&lt;br /&gt;
** [[Setting up Transparent Squid Proxy]] &#039;&#039;(Covers Squid proxy and URL Filtering system)&#039;&#039;&lt;br /&gt;
** [[SqStat]] &#039;&#039;(Script to look at active squid users connections)&#039;&#039;&lt;br /&gt;
* [[Tomcat]]&lt;br /&gt;
&lt;br /&gt;
==== Hostable Content ====&lt;br /&gt;
&lt;br /&gt;
* [[DokuWiki]]&lt;br /&gt;
* [[Drupal]] &#039;&#039;(Content Management System (CMS) written in PHP)&#039;&#039;&lt;br /&gt;
* [[Kopano]] &#039;&#039;(Microsoft Outlook compatible Groupware)&#039;&#039;&lt;br /&gt;
* [[Mahara]] &#039;&#039;(E-portfolio and social networking system)&#039;&#039;&lt;br /&gt;
* [[MediaWiki]] &#039;&#039;(Free web-based wiki software application)&#039;&#039;&lt;br /&gt;
* [[Pastebin]] &#039;&#039;(Pastebin software application)&#039;&#039;&lt;br /&gt;
* [[WordPress]] &#039;&#039;(Web software to create website or blog)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== IRC ===&lt;br /&gt;
&lt;br /&gt;
* [[NgIRCd]] &#039;&#039;(Server for Internet Relay Chat/IRC)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Mail ===&lt;br /&gt;
&lt;br /&gt;
* Exim/Dovecot&lt;br /&gt;
** [[Small-Time Email with Exim and Dovecot]] &#039;&#039;(A simple configuration for your home network.)&lt;br /&gt;
** [[Setting up dovecot with imap and tls]]&lt;br /&gt;
* [[relay email to gmail (msmtp, mailx, sendmail]]&lt;br /&gt;
* [[Roundcube]] &#039;&#039;(Webmail system)&#039;&#039;&lt;br /&gt;
* [[Setting up postfix with virtual domains]]&lt;br /&gt;
* Server protection&lt;br /&gt;
** [[Setting up clamsmtp]]&lt;br /&gt;
&lt;br /&gt;
=== Other Servers ===&lt;br /&gt;
&lt;br /&gt;
* [[apcupsd]] &#039;&#039;(UPS Monitoring with apcupsd)&#039;&#039;&lt;br /&gt;
* [[Chrony and GPSD | Chrony, gpsd, and a garmin LVC 18 as a Stratum 1 NTP source ]]&lt;br /&gt;
* [[Glpi]] &#039;&#039;(Manage inventory of technical resources)&#039;&#039;&lt;br /&gt;
* [[How to setup a Alpine Linux mirror]]&lt;br /&gt;
* [[Setting up an NFS server|nfs-server]]&lt;br /&gt;
* [[nut-ups|NUT UPS]] &#039;&#039;(UPS Monitoring with Network UPS Tools)&#039;&#039;&lt;br /&gt;
* [[Odoo]]&lt;br /&gt;
* [[Configure OpenLDAP | OpenLDAP]] &#039;&#039;(Installing and configuring the Alpine package for OpenLDAP)&#039;&#039;&lt;br /&gt;
* [[Setting up a LLDAP server|lldap-server]] &#039;&#039;(Directory Server)&#039;&#039;&lt;br /&gt;
* [[Setting up a samba-ad-dc|samba-ad-dc]] &#039;&#039;(Active Directory compatible domain controller)&#039;&#039;&lt;br /&gt;
* [[Setting up a Samba server|samba-server]] &#039;&#039;(standard file sharing)&#039;&#039;&lt;br /&gt;
* [[Setting up Transmission (bittorrent) with Clutch WebUI]]&lt;br /&gt;
&lt;br /&gt;
=== Software development ===&lt;br /&gt;
&lt;br /&gt;
* [[Cgit]]&lt;br /&gt;
* [[OsTicket]] &#039;&#039;(Ticket system)&#039;&#039;&lt;br /&gt;
* [[Patchwork]] &#039;&#039;(Patch review management system)&#039;&#039;&lt;br /&gt;
* [[Redmine]] &#039;&#039;(Project management system)&#039;&#039;&lt;br /&gt;
* [[Request Tracker]] &#039;&#039;(Ticket system)&#039;&#039;&lt;br /&gt;
* [[Setting up trac wiki|Trac]] &#039;&#039;(Enhanced wiki and issue tracking system for software development projects)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Storage ==&lt;br /&gt;
&lt;br /&gt;
* [[Setting up disks manually|Manual partitioning]]&lt;br /&gt;
* [[Disk Replication with DRBD|DRBD: Disk Replication]]&lt;br /&gt;
* [[Filesystems]]&lt;br /&gt;
** [[Burning ISOs]]&lt;br /&gt;
* [[Setting up iSCSI|iSCSI Setup]]&lt;br /&gt;
** [[iSCSI Raid and Clustered File Systems]]&lt;br /&gt;
** [[Linux iSCSI Target (TCM)|iSCSI Target (TCM)/LinuxIO (LIO)]]&lt;br /&gt;
** [[Linux iSCSI Target (tgt)|User space iSCSI Target (tgt)]]&lt;br /&gt;
* [[Setting up Logical Volumes with LVM|LVM Setup]]&lt;br /&gt;
** [[Setting up LVM on GPT-labeled disks|LVM on GPT-labeled disks]]&lt;br /&gt;
** [[Installing on GPT LVM|LVM on GPT-labeled disks (updated)]]&lt;br /&gt;
** [[LVM on LUKS]]&lt;br /&gt;
* RAID&lt;br /&gt;
** [[Raid Administration]]&lt;br /&gt;
** [[Setting up a software RAID array]]&lt;br /&gt;
* ZFS&lt;br /&gt;
** [[Root on ZFS with native encryption]]&lt;br /&gt;
** [[Setting up ZFS on LUKS]]&lt;br /&gt;
** [[Setting up ZFS with native encryption]]&lt;br /&gt;
** [[ZFS scrub and trim]]&lt;br /&gt;
* [[CEPH|CEPH]]&lt;br /&gt;
&lt;br /&gt;
== Virtualization ==&lt;br /&gt;
&lt;br /&gt;
* [[Docker]]&lt;br /&gt;
* [[Installing Alpine in a virtual machine]]&lt;br /&gt;
** [[Install Alpine on VMware ESXi]]&lt;br /&gt;
* [[KVM]] &#039;&#039;(Setting up Alpine as a KVM hypervisor)&#039;&#039;&lt;br /&gt;
* [[LXC]] &#039;&#039;(Setting up a Linux container in Alpine Linux)&#039;&#039;&lt;br /&gt;
* [[QEMU]]&lt;br /&gt;
* Xen&lt;br /&gt;
** [[Xen Dom0]] &#039;&#039;(Setting up Alpine as a dom0 for Xen hypervisor)&#039;&#039;&lt;br /&gt;
** [[Xen Dom0 on USB or SD]]&lt;br /&gt;
** [[Create Alpine Linux PV DomU|Xen DomU (paravirtualized)]]&lt;br /&gt;
** [[Xen LiveCD]]&lt;br /&gt;
** [[Xen PCI Passthrough]]&lt;br /&gt;
&lt;br /&gt;
= Tutorials =&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
&lt;br /&gt;
* [[TTY_Autologin|TTY Autologin]]&lt;br /&gt;
* [[Kexec|Faster rebooting with kexec]]&lt;br /&gt;
* [[Dynamic Multipoint VPN (DMVPN)]] combined with [[Small Office Services]]&lt;br /&gt;
* [[DIY Fully working Alpine Linux for Allwinner and Other ARM SOCs]]&lt;br /&gt;
* [[Fault Tolerant Routing with Alpine Linux]]&lt;br /&gt;
* [[High Availability High Performance Web Cache]] &#039;&#039;(uCarp + HAProxy for High Availability Services such as Squid web proxy)&#039;&#039;&lt;br /&gt;
* [[Linux iSCSI Target (TCM)]]&lt;br /&gt;
* [[ISP Mail Server 3.x HowTo]] &#039;&#039;(Postfix+PostfixAdmin+DoveCot+Roundcube+ClamAV+Spamd - A full-service ISP mail server)&#039;&#039;&lt;br /&gt;
* [[Grommunio Mail Server]] &#039;&#039;(Mariadb+Postfix+Rspamd+Grommunio - Full-service mail server as MS exchange replacement)&#039;&#039;&lt;br /&gt;
* [[Replacing non-Alpine Linux with Alpine remotely]]&lt;br /&gt;
* [[Setting up A Network Monitoring and Inventory System]] &#039;&#039;(Nagios + OpenAudit and related components)&#039;&#039; &amp;lt;!-- draft --&amp;gt;&lt;br /&gt;
* [[Streaming Security Camera Video with VLC]]&lt;br /&gt;
* [[Install Alpine on a btrfs filesystem with refind as boot manager]]&lt;br /&gt;
* [[Compile software from source|How to Compile a software from source in Alpine Linux]]&lt;br /&gt;
&lt;br /&gt;
== Newbie corner ==&lt;br /&gt;
&lt;br /&gt;
* [[How to get regular stuff working]] &#039;&#039;some notes on need-to-know topics&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Servers ==&lt;br /&gt;
&lt;br /&gt;
* [[Alpine production deploy]]&lt;br /&gt;
** [[Production Web server: Lighttpd|Production web server: Lighttpd‎‎]]&lt;br /&gt;
** [[MySQL|Production database: MySQL]]&lt;br /&gt;
** [[Production LAMP system: Lighttpd + PHP + MySQL‎‎]]&lt;br /&gt;
* Alpine production monitoring&lt;br /&gt;
** [[Cacti: traffic analysis and monitoring network]]&lt;br /&gt;
** [[Zabbix|Zabbix - the professional complete manager]]&lt;br /&gt;
* Kubernetes&lt;br /&gt;
** [[K8s]] Building a K8s Cluster on Alpine Linux&lt;br /&gt;
&lt;br /&gt;
== Security ==&lt;br /&gt;
&lt;br /&gt;
* [[Securing Alpine Linux]] How to Secure Alpine Linux using Security Technical Implementation Guides (STIGs)&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27989</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27989"/>
		<updated>2024-12-01T00:44:33Z</updated>

		<summary type="html">&lt;p&gt;Midas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the configuration files&lt;br /&gt;
 &#039;&#039;&#039;TODO&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files. Ensure you adapt at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Specify Internal FQDN, Mail Domain, and Relayhost ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Install Dependencies and Grommunio Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Move Mail Storage to Another Disk ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Tutorials_and_Howtos&amp;diff=27988</id>
		<title>Tutorials and Howtos</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Tutorials_and_Howtos&amp;diff=27988"/>
		<updated>2024-12-01T00:43:59Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* Miscellaneous */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Todo|This material has been re-organized..., but grouping should be checked: &#039;&#039;&#039;Howtos are smaller articles&#039;&#039;&#039; and &#039;&#039;&#039;tutorials are more detailed document&#039;&#039;&#039;}}&lt;br /&gt;
&lt;br /&gt;
[[Image:package_edutainment.svg|right|link=]]&lt;br /&gt;
{{TOC left}}&lt;br /&gt;
&#039;&#039;&#039;Welcome to Tutorials and Howtos, a place of basic and advanced configuration tasks for your Alpine Linux.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The tutorials are hands-on&#039;&#039;&#039; and the reader is expected to try and achieve the goals described in each step, possibly with the help of a good example. The output in one step is the starting point for the following step.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Howtos are smaller articles&#039;&#039;&#039; explaining how to perform a particular task with Alpine Linux, that expects a minimal knowledge from reader to perform actions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; contributions on those pages must be complete articles as well as requesting topics to be covered, don&#039;t override already made contributions. If you want to request a topic, please add your request in this page&#039;s [[Talk:Tutorials_and_Howtos|Discussion]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Clear}}&lt;br /&gt;
&lt;br /&gt;
= Howtos =&lt;br /&gt;
&lt;br /&gt;
== Applications ==&lt;br /&gt;
&lt;br /&gt;
=== Miscellaneous ===&lt;br /&gt;
&lt;br /&gt;
* [[Ansible]] &#039;&#039;(Configuration management)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Monitoring ===&lt;br /&gt;
&lt;br /&gt;
* [[Awstats]] &#039;&#039;(Free log file analyzer)&#039;&#039;&lt;br /&gt;
* [[Cacti: traffic analysis and monitoring network]] &#039;&#039;(Front-end for rrdtool networking monitor)&#039;&#039;&lt;br /&gt;
* [[Cvechecker]] &#039;&#039;(Compare installed packages for Common Vulnerabilities Exposure)&#039;&#039; &amp;lt;!-- Monitoring and Security --&amp;gt;&lt;br /&gt;
* [[Linfo]]&lt;br /&gt;
* [[Obtaining user information via SNMP]] &#039;&#039;(Using squark-auth-snmp as a Squid authentication helper)&#039;&#039; &amp;lt;!-- Networking and Server, &amp;lt;== Using squark-auth-snmp --&amp;gt;&lt;br /&gt;
* [[PhpSysInfo]] &#039;&#039;(A simple application that displays information about the host it&#039;s running on)&#039;&#039;&lt;br /&gt;
* [[Matomo]] &#039;&#039;(A real time web analytics software program)&#039;&#039;&lt;br /&gt;
* [[Setting up A Network Monitoring and Inventory System]] &#039;&#039;(Nagios + OpenAudit and related components)&#039;&#039; &amp;lt;!-- draft, solution, Networking and Monitoring and Server --&amp;gt;&lt;br /&gt;
** [[Setting up NRPE daemon]] &#039;&#039;(Performs remote Nagios checks)&#039;&#039; &amp;lt;!-- Networking and Monitoring --&amp;gt;&lt;br /&gt;
* [[Setting Up Fprobe And Ntop|Ntop]] &#039;&#039;(NetFlow collection and analysis using a remote fprobe instance; for alpine 3.10-3.12 only)&#039;&#039; &amp;lt;!-- Networking and Monitoring --&amp;gt;&lt;br /&gt;
* [[Setting up lm_sensors]]&lt;br /&gt;
* [[SqStat]] &#039;&#039;(Script to look at active squid users connections)&#039;&#039;&lt;br /&gt;
* [[Traffic monitoring]] &amp;lt;!-- Networking and Monitoring --&amp;gt;&lt;br /&gt;
** [[Setting up monitoring using rrdtool (and rrdcollect)]]&lt;br /&gt;
** [[Setting up traffic monitoring using rrdtool (and snmp)]] &amp;lt;!-- Monitoring --&amp;gt;&lt;br /&gt;
* [[Zabbix|Zabbix - the professional complete manager]] &#039;&#039;(Monitor and track the status of network services and hardware)&#039;&#039;&lt;br /&gt;
* [[ZoneMinder video camera security and surveillance]]&lt;br /&gt;
&lt;br /&gt;
=== Networking ===&lt;br /&gt;
&lt;br /&gt;
* Alpine Wall &#039;&#039;(a new firewall management framework)&#039;&#039;&lt;br /&gt;
** [[Alpine Wall]]&lt;br /&gt;
** [https://git.alpinelinux.org/awall/about/ Alpine Wall User&#039;s Guide]&lt;br /&gt;
** [[How-To Alpine Wall]]&lt;br /&gt;
* [[Freeradius Active Directory Integration]]&lt;br /&gt;
* [[GNUnet]]&lt;br /&gt;
* [[Setting up a OpenVPN server|OpenVPN server]] &#039;&#039;(Allowing single users or devices to remotely connect to your network)&#039;&#039;&lt;br /&gt;
* [[OpenVSwitch]]&lt;br /&gt;
* [[Using Alpine on Windows domain with IPSEC isolation]]&lt;br /&gt;
* [[Configure a Wireguard interface (wg)|Wireguard]]&lt;br /&gt;
&lt;br /&gt;
=== Telephony ===&lt;br /&gt;
&lt;br /&gt;
* [[FreePBX|FreePBX on Alpine Linux]]&lt;br /&gt;
* [[Setting up Zaptel/Asterisk on Alpine]]&lt;br /&gt;
* [[Kamailio]] &#039;&#039;(SIP Server, formerly OpenSER)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Backup and data migration ==&lt;br /&gt;
&lt;br /&gt;
* [[Alpine local backup|Alpine local backup (lbu)]] &#039;&#039;(Permanently store your modifications in case your box needs reboot)&#039;&#039;&lt;br /&gt;
** [[Back Up a Flash Memory Installation]]&lt;br /&gt;
** [[Manually editing a existing apkovl]]&lt;br /&gt;
* [[Migrating data]]&lt;br /&gt;
* [[Rsnapshot]] - setting up periodic backups&lt;br /&gt;
&lt;br /&gt;
== Desktop ==&lt;br /&gt;
* [[Daily driver guide]]&lt;br /&gt;
* [[Alpine and UEFI]]&lt;br /&gt;
* [[Default applications]]&lt;br /&gt;
* Desktop cloud&lt;br /&gt;
** [[Nextcloud]] &#039;&#039;(Self hostable cloud suite - Dropbox Alternative)&#039;&#039;&lt;br /&gt;
* [[Desktop environments and Window managers]] (overall information only)&lt;br /&gt;
* [[Gaming on Alpine]]&lt;br /&gt;
* [[Printer Setup]]&lt;br /&gt;
* [[Remote Desktop Server]]&lt;br /&gt;
* Sound Systems&lt;br /&gt;
** [[ALSA]]&lt;br /&gt;
** [[PipeWire]]&lt;br /&gt;
** [[PulseAudio]]&lt;br /&gt;
&lt;br /&gt;
== Power management ==&lt;br /&gt;
&lt;br /&gt;
* [[Configure action when power-button is pressed]]&lt;br /&gt;
* [[Suspend on LID close]]&lt;br /&gt;
* [[Configure Wake-on-LAN]]&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
&lt;br /&gt;
* [[Bluetooth]] - Instructions for installing and configuring Bluetooth&lt;br /&gt;
* [[Bonding]] - Bond (or aggregate) multiple ethernet interfaces&lt;br /&gt;
* [[Bridge]] - Configuring a network bridge&lt;br /&gt;
** [[Bridge wlan0 to eth0]]&lt;br /&gt;
* [[Configure Networking]]&lt;br /&gt;
* [[How to configure static routes]]&lt;br /&gt;
* Modem&lt;br /&gt;
** [[Using HSDPA modem]]&lt;br /&gt;
** [[Using serial modem]]&lt;br /&gt;
* [[mDNS]] - Howto implement multicast DNS resolution in Alpine. &lt;br /&gt;
* [[Multi ISP]] &#039;&#039;(Dual-ISP setup with load-balancing and automatic failover)&#039;&#039;&lt;br /&gt;
* [[PXE boot]]&lt;br /&gt;
* Wi-Fi&lt;br /&gt;
** [[Wi-Fi|Connecting to a wireless access point]]&lt;br /&gt;
** [[How to setup a wireless access point]] &#039;&#039;(Setting up Secure Wireless AP w/ WPA encryption with bridge to wired network)&#039;&#039;&lt;br /&gt;
* [[VLAN]]&lt;br /&gt;
&lt;br /&gt;
== Other Architectures ==&lt;br /&gt;
&lt;br /&gt;
=== ARM ===&lt;br /&gt;
&lt;br /&gt;
* [[Alpine on ARM]]&lt;br /&gt;
&lt;br /&gt;
==== Raspberry Pi ====&lt;br /&gt;
&lt;br /&gt;
* [[Raspberry Pi Bluetooth Speaker|Raspberry Pi - Bluetooth Speaker]]&lt;br /&gt;
* [[Raspberry Pi|Raspberry Pi - Installation]]&lt;br /&gt;
* [[Linux Router with VPN on a Raspberry Pi|Raspberry Pi - Router with VPN]]&lt;br /&gt;
* [[Linux Router with VPN on a Raspberry Pi (IPv6)|Raspberry Pi - Router with VPN (IPv6)]]&lt;br /&gt;
* [[Classic install or sys mode on Raspberry Pi|Raspberry Pi - Sys mode install]]&lt;br /&gt;
* [[Raspberry Pi LVM on LUKS|Raspberry Pi - Sys mode install - LVM on LUKS]]&lt;br /&gt;
* [[RPI Video Receiver|Raspberry Pi - Video Receiver]] &#039;&#039;(network video decoder using Rasperry Pi and omxplayer)&#039;&#039;&lt;br /&gt;
* [[Raspberry Pi 3 - Browser Client]] - kiosk or digital sign&lt;br /&gt;
* [[Raspberry Pi 3 - Configuring it as wireless access point -AP Mode]]&lt;br /&gt;
* [[Raspberry Pi 3 - Setting Up Bluetooth]]&lt;br /&gt;
* [[Raspberry Pi 4 - Persistent system acting as a NAS and Time Machine]]&lt;br /&gt;
* [[How to set up Alpine as a wireless router|Raspberry Pi Zero W - Wireless router]] &#039;&#039;(Setting up a firewalled, Wireless AP with wired network on a Pi Zero W)&#039;&#039;&lt;br /&gt;
* [[RPI Video Receiver]]&lt;br /&gt;
&lt;br /&gt;
=== IBM Z (IBM z Systems) ===&lt;br /&gt;
&lt;br /&gt;
* [[s390x|s390x - Installation]]&lt;br /&gt;
&lt;br /&gt;
=== PowerPC ===&lt;br /&gt;
&lt;br /&gt;
* [[Ppc64le|Powerpc64le - Installation]]&lt;br /&gt;
&lt;br /&gt;
== Post-Install ==&lt;br /&gt;
&lt;br /&gt;
* [[CPU frequency scaling]]&lt;br /&gt;
* [[Repositories#Enabling_the_community_repository|Enable Community repository]] &#039;&#039;(Providing additional packages)&#039;&#039;&lt;br /&gt;
* [[Enable Serial Console on Boot]]&lt;br /&gt;
* [[Alpine Linux Init System|Init System (OpenRC)]] &#039;&#039;(Configure a service to automatically boot at next reboot)&#039;&#039;&lt;br /&gt;
** [[Multiple Instances of Services|Init System - Multiple Instances of Services]]&lt;br /&gt;
** [[Writing Init Scripts|Init System - Writing Init Scripts]]&lt;br /&gt;
* [[Installing Oracle Java|Oracle Java (installation)]]&lt;br /&gt;
* [[IGMPproxy]]&lt;br /&gt;
* [[Alpine Package Keeper|Package Management (apk)]] &#039;&#039;(How to add/remove packages on your Alpine)&#039;&#039;&lt;br /&gt;
** [[Comparison with other distros|Package Management - Comparison with other distros]]&lt;br /&gt;
* [[Running glibc programs]]&lt;br /&gt;
* [[Setting up a new user]]&lt;br /&gt;
* [[Upgrading Alpine]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Remote Administration ==&lt;br /&gt;
&lt;br /&gt;
* ACF&lt;br /&gt;
** [[Changing passwords for ACF|ACF - changing passwords]]&lt;br /&gt;
** [[Generating SSL certs with ACF]] &amp;lt;!-- Generating SSL certs with ACF 1.9 --&amp;gt;&lt;br /&gt;
** [[setup-acf| ACF - setup]] &#039;&#039;(Configures ACF (webconfiguration/webmin) so you can manage your box through https)&#039;&#039;&lt;br /&gt;
* [[Setting up a SSH server]] &#039;&#039;(Using ssh is a good way to administer your box remotely)&#039;&#039;&lt;br /&gt;
** [[HOWTO OpenSSH 2FA with password and Google Authenticator |OpenSSH 2FA]] &#039;&#039;(A simple two factor setup for OpenSSH)&#039;&#039;&lt;br /&gt;
* [[OpenVCP]] &#039;&#039;(VServer Control Panel)&#039;&#039;&lt;br /&gt;
* [[PhpMyAdmin]] &#039;&#039;(Web-based administration tool for MYSQL)&#039;&#039;&lt;br /&gt;
* [[PhpPgAdmin]] &#039;&#039;(Web-based administration tool for PostgreSQL)&#039;&#039;&lt;br /&gt;
* [[Webmin]] &#039;&#039;(A web-based interface for Linux system)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Server ==&lt;br /&gt;
&lt;br /&gt;
* [[Hosting services on Alpine]] &#039;&#039;(Hosting mail, webservices and other services)&#039;&#039;&lt;br /&gt;
* [[Hosting Web/Email services on Alpine]]&lt;br /&gt;
&lt;br /&gt;
=== DNS ===&lt;br /&gt;
&lt;br /&gt;
* [[DNSCrypt-Proxy]] &#039;&#039;Encrypt and authenticate DNS calls from your system&#039;&#039;&lt;br /&gt;
* [[Setting up nsd DNS server]]&lt;br /&gt;
* [[Setting up unbound DNS server]]&lt;br /&gt;
* [[TinyDNS Format]]&lt;br /&gt;
&lt;br /&gt;
=== HTTP ===&lt;br /&gt;
&lt;br /&gt;
* [[Apache]]&lt;br /&gt;
** [[Apache with php-fpm]]&lt;br /&gt;
** [[Setting Up Apache with PHP]]&lt;br /&gt;
** [[Apache authentication: NTLM Single Signon]]&lt;br /&gt;
* [[Darkhttpd]]&lt;br /&gt;
* [[Lighttpd]]&lt;br /&gt;
** [[Lighttpd Advanced security]]&lt;br /&gt;
** [[Setting Up Lighttpd With FastCGI]]&lt;br /&gt;
* [[Nginx]]&lt;br /&gt;
** [[Nginx as reverse proxy with acme (letsencrypt)]]&lt;br /&gt;
** [[Nginx with PHP]]&lt;br /&gt;
* Squid Proxy&lt;br /&gt;
** [[Obtaining user information via SNMP]] &#039;&#039;(Using squark-auth-snmp as a Squid authentication helper)&#039;&#039; &amp;lt;!-- Networking and Server, &amp;lt;== Using squark-auth-snmp --&amp;gt;&lt;br /&gt;
** [[Setting up Explicit Squid Proxy]]&lt;br /&gt;
** [[Setting up Transparent Squid Proxy]] &#039;&#039;(Covers Squid proxy and URL Filtering system)&#039;&#039;&lt;br /&gt;
** [[SqStat]] &#039;&#039;(Script to look at active squid users connections)&#039;&#039;&lt;br /&gt;
* [[Tomcat]]&lt;br /&gt;
&lt;br /&gt;
==== Hostable Content ====&lt;br /&gt;
&lt;br /&gt;
* [[DokuWiki]]&lt;br /&gt;
* [[Drupal]] &#039;&#039;(Content Management System (CMS) written in PHP)&#039;&#039;&lt;br /&gt;
* [[Kopano]] &#039;&#039;(Microsoft Outlook compatible Groupware)&#039;&#039;&lt;br /&gt;
* [[Mahara]] &#039;&#039;(E-portfolio and social networking system)&#039;&#039;&lt;br /&gt;
* [[MediaWiki]] &#039;&#039;(Free web-based wiki software application)&#039;&#039;&lt;br /&gt;
* [[Pastebin]] &#039;&#039;(Pastebin software application)&#039;&#039;&lt;br /&gt;
* [[WordPress]] &#039;&#039;(Web software to create website or blog)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== IRC ===&lt;br /&gt;
&lt;br /&gt;
* [[NgIRCd]] &#039;&#039;(Server for Internet Relay Chat/IRC)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Mail ===&lt;br /&gt;
&lt;br /&gt;
* Exim/Dovecot&lt;br /&gt;
** [[Small-Time Email with Exim and Dovecot]] &#039;&#039;(A simple configuration for your home network.)&lt;br /&gt;
** [[Setting up dovecot with imap and tls]]&lt;br /&gt;
* [[relay email to gmail (msmtp, mailx, sendmail]]&lt;br /&gt;
* [[Roundcube]] &#039;&#039;(Webmail system)&#039;&#039;&lt;br /&gt;
* [[Setting up postfix with virtual domains]]&lt;br /&gt;
* Server protection&lt;br /&gt;
** [[Setting up clamsmtp]]&lt;br /&gt;
&lt;br /&gt;
=== Other Servers ===&lt;br /&gt;
&lt;br /&gt;
* [[apcupsd]] &#039;&#039;(UPS Monitoring with apcupsd)&#039;&#039;&lt;br /&gt;
* [[Chrony and GPSD | Chrony, gpsd, and a garmin LVC 18 as a Stratum 1 NTP source ]]&lt;br /&gt;
* [[Glpi]] &#039;&#039;(Manage inventory of technical resources)&#039;&#039;&lt;br /&gt;
* [[How to setup a Alpine Linux mirror]]&lt;br /&gt;
* [[Setting up an NFS server|nfs-server]]&lt;br /&gt;
* [[nut-ups|NUT UPS]] &#039;&#039;(UPS Monitoring with Network UPS Tools)&#039;&#039;&lt;br /&gt;
* [[Odoo]]&lt;br /&gt;
* [[Configure OpenLDAP | OpenLDAP]] &#039;&#039;(Installing and configuring the Alpine package for OpenLDAP)&#039;&#039;&lt;br /&gt;
* [[Setting up a LLDAP server|lldap-server]] &#039;&#039;(Directory Server)&#039;&#039;&lt;br /&gt;
* [[Setting up a samba-ad-dc|samba-ad-dc]] &#039;&#039;(Active Directory compatible domain controller)&#039;&#039;&lt;br /&gt;
* [[Setting up a Samba server|samba-server]] &#039;&#039;(standard file sharing)&#039;&#039;&lt;br /&gt;
* [[Setting up Transmission (bittorrent) with Clutch WebUI]]&lt;br /&gt;
&lt;br /&gt;
=== Software development ===&lt;br /&gt;
&lt;br /&gt;
* [[Cgit]]&lt;br /&gt;
* [[OsTicket]] &#039;&#039;(Ticket system)&#039;&#039;&lt;br /&gt;
* [[Patchwork]] &#039;&#039;(Patch review management system)&#039;&#039;&lt;br /&gt;
* [[Redmine]] &#039;&#039;(Project management system)&#039;&#039;&lt;br /&gt;
* [[Request Tracker]] &#039;&#039;(Ticket system)&#039;&#039;&lt;br /&gt;
* [[Setting up trac wiki|Trac]] &#039;&#039;(Enhanced wiki and issue tracking system for software development projects)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Storage ==&lt;br /&gt;
&lt;br /&gt;
* [[Setting up disks manually|Manual partitioning]]&lt;br /&gt;
* [[Disk Replication with DRBD|DRBD: Disk Replication]]&lt;br /&gt;
* [[Filesystems]]&lt;br /&gt;
** [[Burning ISOs]]&lt;br /&gt;
* [[Setting up iSCSI|iSCSI Setup]]&lt;br /&gt;
** [[iSCSI Raid and Clustered File Systems]]&lt;br /&gt;
** [[Linux iSCSI Target (TCM)|iSCSI Target (TCM)/LinuxIO (LIO)]]&lt;br /&gt;
** [[Linux iSCSI Target (tgt)|User space iSCSI Target (tgt)]]&lt;br /&gt;
* [[Setting up Logical Volumes with LVM|LVM Setup]]&lt;br /&gt;
** [[Setting up LVM on GPT-labeled disks|LVM on GPT-labeled disks]]&lt;br /&gt;
** [[Installing on GPT LVM|LVM on GPT-labeled disks (updated)]]&lt;br /&gt;
** [[LVM on LUKS]]&lt;br /&gt;
* RAID&lt;br /&gt;
** [[Raid Administration]]&lt;br /&gt;
** [[Setting up a software RAID array]]&lt;br /&gt;
* ZFS&lt;br /&gt;
** [[Root on ZFS with native encryption]]&lt;br /&gt;
** [[Setting up ZFS on LUKS]]&lt;br /&gt;
** [[Setting up ZFS with native encryption]]&lt;br /&gt;
** [[ZFS scrub and trim]]&lt;br /&gt;
* [[CEPH|CEPH]]&lt;br /&gt;
&lt;br /&gt;
== Virtualization ==&lt;br /&gt;
&lt;br /&gt;
* [[Docker]]&lt;br /&gt;
* [[Installing Alpine in a virtual machine]]&lt;br /&gt;
** [[Install Alpine on VMware ESXi]]&lt;br /&gt;
* [[KVM]] &#039;&#039;(Setting up Alpine as a KVM hypervisor)&#039;&#039;&lt;br /&gt;
* [[LXC]] &#039;&#039;(Setting up a Linux container in Alpine Linux)&#039;&#039;&lt;br /&gt;
* [[QEMU]]&lt;br /&gt;
* Xen&lt;br /&gt;
** [[Xen Dom0]] &#039;&#039;(Setting up Alpine as a dom0 for Xen hypervisor)&#039;&#039;&lt;br /&gt;
** [[Xen Dom0 on USB or SD]]&lt;br /&gt;
** [[Create Alpine Linux PV DomU|Xen DomU (paravirtualized)]]&lt;br /&gt;
** [[Xen LiveCD]]&lt;br /&gt;
** [[Xen PCI Passthrough]]&lt;br /&gt;
&lt;br /&gt;
= Tutorials =&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
&lt;br /&gt;
* [[TTY_Autologin|TTY Autologin]]&lt;br /&gt;
* [[Kexec|Faster rebooting with kexec]]&lt;br /&gt;
* [[Dynamic Multipoint VPN (DMVPN)]] combined with [[Small Office Services]]&lt;br /&gt;
* [[DIY Fully working Alpine Linux for Allwinner and Other ARM SOCs]]&lt;br /&gt;
* [[Fault Tolerant Routing with Alpine Linux]]&lt;br /&gt;
* [[High Availability High Performance Web Cache]] &#039;&#039;(uCarp + HAProxy for High Availability Services such as Squid web proxy)&#039;&#039;&lt;br /&gt;
* [[Linux iSCSI Target (TCM)]]&lt;br /&gt;
* [[ISP Mail Server 3.x HowTo]]] &#039;&#039;(Postfix+PostfixAdmin+DoveCot+Roundcube+ClamAV+Spamd - A full-service ISP mail server)&#039;&#039;&lt;br /&gt;
* [[Grommunio Mail Server]]] &#039;&#039;(Mariadb+Postfix+Rspamd+Grommunio - Full-service mail server as MS exchange replacement)&#039;&#039;&lt;br /&gt;
* [[Replacing non-Alpine Linux with Alpine remotely]]&lt;br /&gt;
* [[Setting up A Network Monitoring and Inventory System]] &#039;&#039;(Nagios + OpenAudit and related components)&#039;&#039; &amp;lt;!-- draft --&amp;gt;&lt;br /&gt;
* [[Streaming Security Camera Video with VLC]]&lt;br /&gt;
* [[Install Alpine on a btrfs filesystem with refind as boot manager]]&lt;br /&gt;
* [[Compile software from source|How to Compile a software from source in Alpine Linux]]&lt;br /&gt;
&lt;br /&gt;
== Newbie corner ==&lt;br /&gt;
&lt;br /&gt;
* [[How to get regular stuff working]] &#039;&#039;some notes on need-to-know topics&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Servers ==&lt;br /&gt;
&lt;br /&gt;
* [[Alpine production deploy]]&lt;br /&gt;
** [[Production Web server: Lighttpd|Production web server: Lighttpd‎‎]]&lt;br /&gt;
** [[MySQL|Production database: MySQL]]&lt;br /&gt;
** [[Production LAMP system: Lighttpd + PHP + MySQL‎‎]]&lt;br /&gt;
* Alpine production monitoring&lt;br /&gt;
** [[Cacti: traffic analysis and monitoring network]]&lt;br /&gt;
** [[Zabbix|Zabbix - the professional complete manager]]&lt;br /&gt;
* Kubernetes&lt;br /&gt;
** [[K8s]] Building a K8s Cluster on Alpine Linux&lt;br /&gt;
&lt;br /&gt;
== Security ==&lt;br /&gt;
&lt;br /&gt;
* [[Securing Alpine Linux]] How to Secure Alpine Linux using Security Technical Implementation Guides (STIGs)&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27987</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27987"/>
		<updated>2024-12-01T00:36:51Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* HOWTO: Install AlpineLinux Mail Server with Grommunio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Draft|This is a work in progress}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= HOWTO: Install AlpineLinux Mail Server with Grommunio =&lt;br /&gt;
&lt;br /&gt;
This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the configuration files&lt;br /&gt;
 &#039;&#039;&#039;TODO&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files. Ensure you adapt at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Specify Internal FQDN, Mail Domain, and Relayhost ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Install Dependencies and Grommunio Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Move Mail Storage to Another Disk ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27986</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27986"/>
		<updated>2024-12-01T00:35:31Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 9. Finalize and Verify Installation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Draft|This is a work in progress}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= HOWTO: Install AlpineLinux Mail Server with Grommunio =&lt;br /&gt;
&lt;br /&gt;
This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the configuration files&lt;br /&gt;
 &#039;&#039;&#039;TODO&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files. Ensure you adapt at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Specify Internal FQDN, Mail Domain, and Relayhost ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Install Dependencies and Grommunio Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Move Mail Storage to Another Disk ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: https://mail.example.local:8443&lt;br /&gt;
&lt;br /&gt;
Web UI: https://mail.example.local&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users. If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== 10. End User Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== Admin UI ===&lt;br /&gt;
Log into the Admin UI with the username `admin` and the previously created `ADMIN_PASS`.&lt;br /&gt;
&lt;br /&gt;
=== License Configuration ===&lt;br /&gt;
If you have a license, you can configure it under &#039;&#039;&#039;Grommunio settings&#039;&#039;&#039; in the Admin UI.&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27985</id>
		<title>Grommunio Mail Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Grommunio_Mail_Server&amp;diff=27985"/>
		<updated>2024-12-01T00:34:36Z</updated>

		<summary type="html">&lt;p&gt;Midas: /* 9. Finalize and Verify Installation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Draft|This is a work in progress}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= HOWTO: Install AlpineLinux Mail Server with Grommunio =&lt;br /&gt;
&lt;br /&gt;
This tutorial outlines the steps for setting up a mail server on Alpine Linux using &#039;&#039;&#039;Grommunio&#039;&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
Before proceeding with the installation, ensure you have a fresh Alpine Linux system setup. You&#039;ll need root privileges to execute these commands.&lt;br /&gt;
&lt;br /&gt;
== Procedure ==&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
# Install and configure MariaDB&lt;br /&gt;
# MariaDB performance tuning (optional)&lt;br /&gt;
# Install and configure Nginx&lt;br /&gt;
# Install and configure PHP&lt;br /&gt;
# Install and configure Postfix&lt;br /&gt;
# Install and configure Grommunio&lt;br /&gt;
# Configure Valkey (Redis replacement)&lt;br /&gt;
# Install and configure Rspamd&lt;br /&gt;
# Finalize and verify installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Install and Configure MariaDB ==&lt;br /&gt;
&lt;br /&gt;
=== Install MariaDB ===&lt;br /&gt;
To start, install MariaDB and necessary utilities&lt;br /&gt;
&lt;br /&gt;
 apk add mariadb mariadb-client mariadb-server-utils&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Define the variables used later in the setup setup and configuration.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
 DB_DATA_PATH=&amp;quot;/srv/mysql&amp;quot;&lt;br /&gt;
 DB_ROOT_PASS=&amp;quot;Passw0rd1&amp;quot;&lt;br /&gt;
 DB_USER=&amp;quot;admin&amp;quot;&lt;br /&gt;
 DB_PASS=&amp;quot;Passw0rd2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Setup the default system tables:&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set a symlink to the standard mysql data directory for compatibility reason:&lt;br /&gt;
&lt;br /&gt;
 ln -s /srv/mysql /var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart service:&lt;br /&gt;
&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run the built-in security script:&lt;br /&gt;
&lt;br /&gt;
Set the new root password to the one defined above and answer everything with &#039;y&#039;&lt;br /&gt;
&lt;br /&gt;
 sudo mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create MariaDB User for Grommunio ===&lt;br /&gt;
Create a new user for Grommunio and assign privileges:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;127.0.0.1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;localhost&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;GRANT ALL ON *.* TO ${DB_USER}@&#039;::1&#039; IDENTIFIED BY &#039;${DB_PASS}&#039; WITH GRANT OPTION;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;DELETE FROM mysql.user WHERE User=&#039;&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;FLUSH PRIVILEGES;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u root --password=&amp;quot;${DB_ROOT_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure MariaDB for Grommunio ===&lt;br /&gt;
Edit the MariaDB configuration for better performance:&lt;br /&gt;
&lt;br /&gt;
 vi /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 &lt;br /&gt;
 ## Configuration for grommunio (most values are default)&lt;br /&gt;
 innodb_log_buffer_size=16M&lt;br /&gt;
 innodb_log_file_size=32M&lt;br /&gt;
 innodb_read_io_threads=4&lt;br /&gt;
 innodb_write_io_threads=4&lt;br /&gt;
 &lt;br /&gt;
 join_buffer_size=512K&lt;br /&gt;
 query_cache_size=0&lt;br /&gt;
 query_cache_type=0&lt;br /&gt;
 query_cache_limit=2M&lt;br /&gt;
 &lt;br /&gt;
 # Activate performance schema&lt;br /&gt;
 performance_schema=ON&lt;br /&gt;
 &lt;br /&gt;
 # Bind to localhost only&lt;br /&gt;
 bind-address = 127.0.0.1&lt;br /&gt;
 &lt;br /&gt;
 # Disable DNS lookups as we only use localhost connections&lt;br /&gt;
 skip-name-resolve=ON&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a default charset configuration for MariaDB:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysqld]&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 [mysql]&lt;br /&gt;
 default-character-set = utf8mb4&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart MariaDB and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add mariadb default&lt;br /&gt;
 rc-service mariadb restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify MariaDB Setup ===&lt;br /&gt;
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1):&lt;br /&gt;
&lt;br /&gt;
 ss -tulpn&lt;br /&gt;
&lt;br /&gt;
=== Create Grommunio Database ===&lt;br /&gt;
Define the database parameters and create the Grommunio database:&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;create database $MYSQL_DB character set &#039;utf8mb4&#039;;&amp;quot; &amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;grant select, insert, update, delete, create, drop, index, alter, create temporary tables, lock tables on $MYSQL_DB.* TO $MYSQL_USER@$MYSQL_HOST identified by &#039;$MYSQL_PASS&#039;;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 echo &amp;quot;flush privileges;&amp;quot; &amp;gt;&amp;gt; /tmp/sql&lt;br /&gt;
 cat /tmp/sql | mysql -u admin --password=&amp;quot;${DB_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test the database connection:&lt;br /&gt;
&lt;br /&gt;
 mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. MariaDB Performance Tuning (Optional) ==&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Download MySQLTuner:&lt;br /&gt;
&lt;br /&gt;
 wget -v https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl -O /tmp/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move it to the correct directory and set permissions:&lt;br /&gt;
&lt;br /&gt;
 mv /tmp/mysqltuner.pl /usr/local/bin/mysqltuner.pl&lt;br /&gt;
 chmod 755 /usr/local/bin/mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install perl:&lt;br /&gt;
&lt;br /&gt;
NOTE: The perl-doc package is installed because it&#039;s the only one containing the perldiag.pod required by mysqltuner.pl&lt;br /&gt;
&lt;br /&gt;
 apk add perl perl-doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Execute the script. You will be prompted to enter the credentials of your administrative MariaDB account:&lt;br /&gt;
&lt;br /&gt;
 /usr/local/bin/mysqltuner.pl --user admin --pass ${DB_PASS}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Install and Configure Nginx ==&lt;br /&gt;
&lt;br /&gt;
=== Install Nginx ===&lt;br /&gt;
Install the necessary Nginx modules:&lt;br /&gt;
&lt;br /&gt;
 apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Nginx ===&lt;br /&gt;
Backup the original Nginx configuration and edit it for security headers and TLS settings:&lt;br /&gt;
&lt;br /&gt;
 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig&lt;br /&gt;
 vi /etc/nginx/nginx.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add the following configuration:&lt;br /&gt;
&lt;br /&gt;
 #error_log /var/log/nginx/error.log warn;&lt;br /&gt;
 error_log syslog:server=unix:/dev/log,facility=local2,nohostname warn;&lt;br /&gt;
 &lt;br /&gt;
 ### Common headers for security&lt;br /&gt;
 # TODO: Set temporary to a lower value until we are sure it&#039;s working&lt;br /&gt;
 #more_set_headers &amp;quot;Strict-Transport-Security : max-age=15768000; includeSubDomains; preload&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Strict-Transport-Security : max-age=2592000; includeSubDomains;&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Frame-Options : SAMEORIGIN&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Content-Security-Policy : default-src https: data: &#039;unsafe-inline&#039; &#039;unsafe-eval&#039; always&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Xss-Protection : 1; mode=block&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;X-Content-Type-Options : nosniff&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Referrer-Policy : strict-origin-when-cross-origin&amp;quot;;&lt;br /&gt;
 more_set_headers &amp;quot;Server : Follow the white rabbit.&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 ### TLS settings&lt;br /&gt;
 ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
 ssl_session_cache shared:SSL:1m;&lt;br /&gt;
 ssl_session_timeout 5m;&lt;br /&gt;
 &lt;br /&gt;
 log_format main_ssl &#039;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &#039;&lt;br /&gt;
         &#039;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &#039;&lt;br /&gt;
         &#039;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &#039;&lt;br /&gt;
         &#039;client_ciphers=&amp;quot;$ssl_ciphers&amp;quot; client_curves=&amp;quot;$ssl_curves&amp;quot;&#039;;&lt;br /&gt;
 &lt;br /&gt;
 #access_log /var/log/nginx/access.log main_ssl; # Disabled for performance&lt;br /&gt;
 #access_log syslog:server=unix:/dev/log,facility=local2,nohostname main; # Disabled for performance&lt;br /&gt;
 access_log off;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the default page by renaming it:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/nginx/http.d/default.conf /etc/nginx/http.d/default.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Restart Nginx and enable it to start on boot:&lt;br /&gt;
&lt;br /&gt;
 rc-update add nginx&lt;br /&gt;
 rc-service nginx restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Install and Configure PHP ==&lt;br /&gt;
&lt;br /&gt;
=== Install PHP ===&lt;br /&gt;
Install the basic php packages. The modules are installed as grommunio dependencies:&lt;br /&gt;
&lt;br /&gt;
 apk add php83 php83-fpm&lt;br /&gt;
&lt;br /&gt;
Disable default fpm conf:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Harden PHP Configuration ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Backup config file /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
 cp /etc/php83/php.ini /etc/php83/php-fpm.d/php.ini.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable remote PHP code execution:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_fopen\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(allow_url_include\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable information leakage:&lt;br /&gt;
  &lt;br /&gt;
 sed &#039;s/^;\?\(expose_php\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure Error handling:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(display_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(display_startup_errors\).*/\1 = Off/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(log_errors\).*/\1 = On/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(error_log = syslog\).*/\1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Resource Control (Optional):&lt;br /&gt;
&lt;br /&gt;
 #sed &#039;s/^\(max_execution_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(max_input_time\).*/\1 = 25/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(memory_limit\).*/\1 = 30M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^\(post_max_size\).*/\1 = 1M/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 #sed &#039;s/^;\?\(max_input_vars\).*/\1 = 1000/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable vulnerable functions:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;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/&#039; -i /etc/php83/php.ini &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Harden Session Security:&lt;br /&gt;
&lt;br /&gt;
 sed &#039;s/^;\?\(session.use_strict_mode\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_secure\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.use_only_cookies\).*/\1 = 1/&#039; -i /etc/php83/php.ini &lt;br /&gt;
 sed &#039;s/^;\?\(session.cookie_httponly\).*/\1 = 1/&#039; -i /etc/php83/php.ini&lt;br /&gt;
&lt;br /&gt;
== 5. Install and Configure Postfix ==&lt;br /&gt;
&lt;br /&gt;
=== Install Postfix ===&lt;br /&gt;
Install the required packages:&lt;br /&gt;
&lt;br /&gt;
 apk add postfix postfix-mysql postfix-pcre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Postfix ===&lt;br /&gt;
&lt;br /&gt;
First backup the original files:&lt;br /&gt;
 mv /etc/postfix/main.cf /etc/postfix/main.cf.orig&lt;br /&gt;
 mv /etc/postfix/master.cf /etc/postfix/master.cf.orig&lt;br /&gt;
 mv /etc/postfix/header_checks /etc/postfix/header_checks.orig&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the configuration files&lt;br /&gt;
 &#039;&#039;&#039;TODO&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copy the prepared configuration files. Ensure you adapt at least the following values:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;main.cf&#039;&#039;&#039;: myhostname, mynetworks, smtp_tls_chain_files, smtpd_tls_chain_files, local_recipient_maps, mydestination, &lt;br /&gt;
         virtual_*, relayhost, mua_sender_restrictions, smtpd_recipient_restrictions&lt;br /&gt;
 &#039;&#039;&#039;master.cf&#039;&#039;&#039;: smtpd_tls_chain_files=/etc/ssl/private/internal-server-key-and-cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the required postmap files:&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Run Postfix setup:&lt;br /&gt;
&lt;br /&gt;
 newaliases&lt;br /&gt;
 postmap /etc/postfix/transport&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enable the postfix service and restart:&lt;br /&gt;
&lt;br /&gt;
 rc-update add postfix&lt;br /&gt;
 rc-service postfix restart&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Postfix Logs ===&lt;br /&gt;
Check the Postfix logs for any errors:&lt;br /&gt;
&lt;br /&gt;
 tail -f /var/log/maillog&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Install and Configure Grommunio ==&lt;br /&gt;
&lt;br /&gt;
=== Enable IPv6 ===&lt;br /&gt;
First of all, turn on ipv6 which is mandatory for grommunio daemons&lt;br /&gt;
&lt;br /&gt;
Edit `/etc/hosts` to include IPv6 localhost:&lt;br /&gt;
 vi /etc/hosts&lt;br /&gt;
 -----&lt;br /&gt;
 ::1		localhost ipv6-localhost ipv6-loopback&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ensure IPv6 is enabled in `/etc/sysctl.conf`:&lt;br /&gt;
&lt;br /&gt;
 sed -i &#039;s/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&amp;amp;/&#039; /etc/sysctl.conf&lt;br /&gt;
 sysctl -p&lt;br /&gt;
 ping ::1  # Test if IPv6 is working&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Specify Database Parameters ===&lt;br /&gt;
Specify DB parameters if necessary (already specified above in step 1)&lt;br /&gt;
&lt;br /&gt;
 MYSQL_HOST=&amp;quot;localhost&amp;quot;&lt;br /&gt;
 MYSQL_USER=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
 MYSQL_PASS=&amp;quot;Passw0rd3&amp;quot;&lt;br /&gt;
 MYSQL_DB=&amp;quot;grommunio&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Specify Internal FQDN, Mail Domain, and Relayhost ===&lt;br /&gt;
The &#039;&#039;&#039;FQDN&#039;&#039;&#039; is for example used by Outlook clients to connect. This name will have to be present in the used certificate.&lt;br /&gt;
&lt;br /&gt;
The default &#039;&#039;&#039;Mail Domain&#039;&#039;&#039; is for example used for Non-Delivery Reports and for generation of some simple TLS certificates. Specify ONLY ONE domain here.&lt;br /&gt;
&lt;br /&gt;
Adjust the following for your specific setup:&lt;br /&gt;
&lt;br /&gt;
 FQDN=&amp;quot;mail.example.local&amp;quot;&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 RELAYHOST=&amp;quot;123.123.123.1&amp;quot;&lt;br /&gt;
 ADMIN_PASS=&amp;quot;Passw0rd4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Install Dependencies and Grommunio Packages ===&lt;br /&gt;
&lt;br /&gt;
Install necessary dependencies (util-linux-login is required to get pam.d working):&lt;br /&gt;
&lt;br /&gt;
 apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Install grommunio packages:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-gromox grommunio-web grommunio-admin-api grommunio-admin-web grommunio-index grommunio-error-pages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Optionally, install deprecated ActiveSync if needed:&lt;br /&gt;
&lt;br /&gt;
 apk add grommunio-dav grommunio-sync&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Move Mail Storage to Another Disk ===&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 mv /var/lib/gromox /srv/gromox&lt;br /&gt;
 ln -s /srv/gromox /var/lib/gromox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Required Services ===&lt;br /&gt;
Enable all required services:&lt;br /&gt;
&lt;br /&gt;
 rc-update add grommunio-admin-api&lt;br /&gt;
 rc-update add gromox-delivery&lt;br /&gt;
 rc-update add gromox-delivery-queue&lt;br /&gt;
 rc-update add gromox-event&lt;br /&gt;
 rc-update add gromox-http&lt;br /&gt;
 rc-update add gromox-imap&lt;br /&gt;
 rc-update add gromox-midb&lt;br /&gt;
 rc-update add gromox-pop3&lt;br /&gt;
 rc-update add gromox-timer&lt;br /&gt;
 rc-update add gromox-zcore&lt;br /&gt;
 rc-update add valkey@grommunio&lt;br /&gt;
 rc-update add php-fpm83 &lt;br /&gt;
 rc-update add saslauthd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Grommunio ===&lt;br /&gt;
Modify the configuration files with the custom parameters specified above.&lt;br /&gt;
&lt;br /&gt;
Configure gromox *.cfg:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
 sed -i &amp;quot;s/example.com/${MAILDOMAIN}/g&amp;quot; /etc/gromox/*.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure gromox adaptor:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
 cat /etc/gromox/mysql_adaptor.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure autodiscovery:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/gromox/autodiscover.ini&lt;br /&gt;
 cat /etc/gromox/autodiscover.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare additional postfix file for sender maps:&lt;br /&gt;
 cp -p /etc/postfix/grommunio-virtual-mailbox-maps.cf /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 sed -i &#039;/^query =/d&#039; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
 echo &amp;quot;query = SELECT username FROM users WHERE username=&#039;%s&#039; UNION SELECT aliasname FROM aliases WHERE mainname=&#039;%s&#039;&amp;quot; &amp;gt;&amp;gt; /etc/postfix/grommunio-virtual-mailbox-sender-maps.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure postfix files:&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/postfix/grommunio*.cf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure TLS certificates:&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-common/nginx/ssl_certificate.conf&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Link TLS certificate configuration:&lt;br /&gt;
&lt;br /&gt;
Since both ssl files are identical it might make more sense to link them&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure grommunio admin:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/mail.example.local/${FQDN}/g&amp;quot; /etc/grommunio-admin-common/config.json&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;password&amp;gt;/${MYSQL_PASS}/g&amp;quot; /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
 cat /etc/grommunio-admin-api/conf.d/database.yaml&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prepare external or self-signed certificate and put them to:&lt;br /&gt;
 /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
 /etc/ssl/private/${FQDN}.key.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Concatenate key and cert as needed by postfix:&lt;br /&gt;
 cat /etc/ssl/private/${FQDN}.key.pem \&lt;br /&gt;
     /etc/ssl/certs/${FQDN}.cert.pem \&lt;br /&gt;
   &amp;gt; /etc/ssl/private/${FQDN}.key_cert.pem&lt;br /&gt;
 chmod 640 /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 chown root:ssl-cert /etc/ssl/private/*.key_cert.pem&lt;br /&gt;
 ls -al /etc/ssl/private/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add gromox to ssl-cert (or another) group allowed to read the private keys:&lt;br /&gt;
 addgroup gromox ssl-cert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Retrieve the certificate fingerprint:&lt;br /&gt;
&lt;br /&gt;
NOTE: This is only required if you work with a relay server authenticating the client cert.&lt;br /&gt;
&lt;br /&gt;
Add the output to the relay_clientcerts file on the relay server and hash it with the postmap command.&lt;br /&gt;
&lt;br /&gt;
 openssl x509 -noout -fingerprint -sha384 -in /etc/ssl/certs/${FQDN}.cert.pem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure PAM for SMTP:&lt;br /&gt;
&lt;br /&gt;
 mv /etc/pam.d/smtp /etc/pam.d/smtp.orig&lt;br /&gt;
 cat &amp;gt; /etc/pam.d/smtp &amp;lt;&amp;lt;EOF&lt;br /&gt;
 #%PAM-1.0&lt;br /&gt;
 # config for grommunio auth services&lt;br /&gt;
 auth    required pam_gromox.so service=smtp&lt;br /&gt;
 account required pam_permit.so&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure SASL authentication:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/conf.d/saslauthd &amp;lt;&amp;lt;EOF&lt;br /&gt;
 # Configuration for /etc/init.d/saslauthd&lt;br /&gt;
 SASLAUTHD_OPTS=&amp;quot;-a pam -r&amp;quot;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SASL configuration for SMTP service:&lt;br /&gt;
&lt;br /&gt;
 mkdir /etc/sasl2&lt;br /&gt;
 cat &amp;gt; /etc/sasl2/smtpd.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 pwcheck_method: saslauthd&lt;br /&gt;
 mech_list: plain login&lt;br /&gt;
 EOF&lt;br /&gt;
 chmod 600 /etc/sasl2/smtpd.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In case you migrate from another server replace X500-org-name with the original one:&lt;br /&gt;
&lt;br /&gt;
 X500_ORG_NAME_OLD=$(grep &#039;x500_org_name=&#039; /etc/gromox/zcore.cfg | cut -d= -f2)&lt;br /&gt;
 X500_ORG_NAME_NEW=&amp;lt;original-key&amp;gt;&lt;br /&gt;
 sed -i &amp;quot;s/$X500_ORG_NAME_OLD/$X500_ORG_NAME_NEW/g&amp;quot; /etc/gromox/*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Database and Set Admin Password ===&lt;br /&gt;
Initialize the database:&lt;br /&gt;
&lt;br /&gt;
 gromox-dbop -C&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Set the Grommunio admin password:&lt;br /&gt;
&lt;br /&gt;
 grommunio-admin passwd --password &amp;quot;${ADMIN_PASS}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add grommunio to the adm group to enable admin UI to read `/var/log/maillog`.&lt;br /&gt;
&lt;br /&gt;
NOTE: Additional custom patch is needed to make the log monitoring work&lt;br /&gt;
&lt;br /&gt;
 addgroup grommunio adm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Firewall Ports ===&lt;br /&gt;
Open the necessary firewall ports:&lt;br /&gt;
&lt;br /&gt;
 25/tcp&lt;br /&gt;
 80/tcp&lt;br /&gt;
 110/tcp&lt;br /&gt;
 143/tcp&lt;br /&gt;
 443/tcp&lt;br /&gt;
 587/tcp&lt;br /&gt;
 993/tcp&lt;br /&gt;
 995/tcp&lt;br /&gt;
 8080/tcp&lt;br /&gt;
 8443/tcp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Configure Valkey ==&lt;br /&gt;
&lt;br /&gt;
=== Enable Syslog ===&lt;br /&gt;
&lt;br /&gt;
The syslog facility is set to &#039;local0&#039;.&lt;br /&gt;
&lt;br /&gt;
NOTE: It is recommended to redirect local0 to the maillog in syslog.conf as all other grommunio processes write to maillog&lt;br /&gt;
&lt;br /&gt;
 vi /etc/valkey/grommunio.conf&lt;br /&gt;
 -----&lt;br /&gt;
 #pidfile /var/run/valkey/default.pid&lt;br /&gt;
 #logfile /var/log/valkey/default.log&lt;br /&gt;
 syslog-enabled yes&lt;br /&gt;
 syslog-ident valkey&lt;br /&gt;
 syslog-facility local0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Enable Memory Overcommit ===&lt;br /&gt;
&lt;br /&gt;
Add the following sysctl property for valkey&lt;br /&gt;
&lt;br /&gt;
  vi /etc/sysctl.conf&lt;br /&gt;
  -----&lt;br /&gt;
  # Enable memory overcommit for valkey  &lt;br /&gt;
  vm.overcommit_memory = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Update the system configuration&lt;br /&gt;
  &lt;br /&gt;
 sysctl -p&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Valkey and Test ===&lt;br /&gt;
&lt;br /&gt;
 rcctl restart valkey@grommunio&lt;br /&gt;
 valkey-cli ping  # Expected result: &#039;PONG&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Install and Configure Rspamd ==&lt;br /&gt;
&lt;br /&gt;
=== Install Rspamd ===&lt;br /&gt;
&lt;br /&gt;
  apk add rspamd rspamd-client&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configure Rspamd ===&lt;br /&gt;
Set general options:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/options.inc &amp;lt;&amp;lt;EOF&lt;br /&gt;
 dns {&lt;br /&gt;
   enable_dnssec = true;&lt;br /&gt;
   timeout = 4s;&lt;br /&gt;
   retransmits = 5;&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure redis/valkey connection:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/redis.conf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 read_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 write_servers = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure normal worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-normal.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Normal worker is intended to scan messages for spam&lt;br /&gt;
 # You might disable normal worker to free up system resources as we use the proxy worker in self-scan mode&lt;br /&gt;
 enabled = false;&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11333&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-normal.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure proxy worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-proxy.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Proxy worker is used as postfix milter&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 milter = yes;&lt;br /&gt;
 #bind_socket = &amp;quot;127.0.0.1:11332&amp;quot;;&lt;br /&gt;
 bind_socket = &amp;quot;/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 timeout = 120s;&lt;br /&gt;
 upstream &amp;quot;local&amp;quot; {&lt;br /&gt;
   default = yes; # Self-scan upstreams are always default&lt;br /&gt;
   self_scan = yes; # Enable self-scan&lt;br /&gt;
 }&lt;br /&gt;
 count = 4; # Spawn more processes in self-scan mode&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Add postfix to rspamd group to access the socket:&lt;br /&gt;
&lt;br /&gt;
 addgroup postfix rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure controller worker:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/worker-controller.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI&lt;br /&gt;
 # If the mailer is running on the same host use a unix socket&lt;br /&gt;
 # NOTE: grommunio connects over http&lt;br /&gt;
 bind_socket = &amp;quot;127.0.0.1:11334&amp;quot;;&lt;br /&gt;
 #bind_socket = &amp;quot;/var/run/rspamd/worker-controller.sock mode=0660 owner=rspamd&amp;quot;;&lt;br /&gt;
 # password for read-only commands&lt;br /&gt;
 password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;;&lt;br /&gt;
 # password for write commands&lt;br /&gt;
 enable_password = &amp;quot;&amp;lt;encrypted_password_string&amp;gt;&amp;quot;&lt;br /&gt;
 secure_ip = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create the user password and replace it in worker-controller.inc:&lt;br /&gt;
&lt;br /&gt;
Command: rspamadm pw --encrypt -p P4ssword&lt;br /&gt;
&lt;br /&gt;
 sed -i s/\&amp;lt;encrypted_password_string\&amp;gt;/$(rspamadm pw --encrypt -p &amp;quot;${ADMIN_PASS}&amp;quot;)/ /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
 cat /etc/rspamd/local.d/worker-controller.inc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redirect rspamd logs to syslog:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/logging.inc &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Redirect rspamd logs to the mail log&lt;br /&gt;
 type = &amp;quot;syslog&amp;quot;;&lt;br /&gt;
 facility = &amp;quot;mail&amp;quot;;&lt;br /&gt;
 level = &amp;quot;notice&amp;quot;;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure external relay:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/external_relay.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 rules {&lt;br /&gt;
   FETCHMAIL {&lt;br /&gt;
     strategy = &amp;quot;local&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure actions:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/actions.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 reject = 15; # Reject when reaching this score&lt;br /&gt;
 add_header = 4; # Add spam header when reaching this score&lt;br /&gt;
 greylist = 3; # Apply greylisting when reaching this score (will emit &#039;soft reject action&#039;)&lt;br /&gt;
 &lt;br /&gt;
 #rewrite_subject = 6; # Rewrite subject to indicate spam. Cannot be combined with add_header&lt;br /&gt;
 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly&lt;br /&gt;
 #subject = &amp;quot;***SPAM*** %s&amp;quot;; # Set rewrite subject to this value (%s is replaced by the original subject)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure milter_headers:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/milter_headers.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enables x-spamd-result, x-rspamd-server and x-rspamd-queue-id headers (default false)&lt;br /&gt;
 extended_spam_headers = true;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for local IPs (default true)&lt;br /&gt;
 skip_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to always add headers for authenticated users (default true)&lt;br /&gt;
 skip_authenticated = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set false to keep pre-existing spam flag added by an upstream spam filter (default true)&lt;br /&gt;
 remove_upstream_spam_flag = true;&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Configure dkim signing:&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; /etc/rspamd/local.d/dkim_signing.conf &amp;lt;&amp;lt; EOF&lt;br /&gt;
 # Enable DKIM signing&lt;br /&gt;
 enabled = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages with empty envelope from are not signed&lt;br /&gt;
 allow_envfrom_empty = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, envelope/header domain mismatch is ignored&lt;br /&gt;
 allow_hdrfrom_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # If true, multiple from headers are allowed (but only first is used)&lt;br /&gt;
 allow_hdrfrom_multiple = false;&lt;br /&gt;
 &lt;br /&gt;
 # If true, username does not need to contain matching domain&lt;br /&gt;
 allow_username_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Default path to key, can include &#039;$domain&#039; and &#039;$selector&#039; variables&lt;br /&gt;
 path = &amp;quot;/var/lib/rspamd/dkim/\$domain-\$selector.key&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Default selector to use&lt;br /&gt;
 selector = &amp;quot;dkim&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from authenticated users are not selected for signing&lt;br /&gt;
 sign_authenticated = true;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from local networks are not selected for signing&lt;br /&gt;
 sign_local = false;&lt;br /&gt;
 &lt;br /&gt;
 # Map file of IP addresses/subnets to consider for signing&lt;br /&gt;
 #sign_networks = &amp;quot;/some/file&amp;quot;; # or url&lt;br /&gt;
 &lt;br /&gt;
 # Symbol to add when message is signed&lt;br /&gt;
 symbol = &amp;quot;DKIM_SIGNED&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If false, messages from domains not defined here will not be signed&lt;br /&gt;
 try_fallback = false;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing: can be &amp;quot;header&amp;quot; (MIME From), &amp;quot;envelope&amp;quot; (SMTP From), &lt;br /&gt;
 #   &amp;quot;recipient&amp;quot; (SMTP To), &amp;quot;auth&amp;quot; (SMTP username) or directly specified domain name&lt;br /&gt;
 use_domain = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is in sign_networks (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_networks = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Domain to use for DKIM signing when sender is a local IP (&amp;quot;header&amp;quot;/&amp;quot;envelope&amp;quot;/&amp;quot;auth&amp;quot;)&lt;br /&gt;
 #use_domain_sign_local = &amp;quot;header&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to normalise domains to eSLD&lt;br /&gt;
 use_esld = true;&lt;br /&gt;
 &lt;br /&gt;
 # Whether to get keys from Redis&lt;br /&gt;
 use_redis = false;&lt;br /&gt;
 &lt;br /&gt;
 # Hash for DKIM keys in Redis&lt;br /&gt;
 key_prefix = &amp;quot;DKIM_KEYS&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; names of selectors (since rspamd 1.5.3)&lt;br /&gt;
 #selector_map = &amp;quot;/etc/rspamd/dkim_selectors.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # map of domains -&amp;gt; paths to keys (since rspamd 1.5.3)&lt;br /&gt;
 #path_map = &amp;quot;/etc/rspamd/dkim_paths.map&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 # If `true` get pubkey from DNS record and check if it matches private key&lt;br /&gt;
 check_pubkey = false;&lt;br /&gt;
 &lt;br /&gt;
 # Set to `false` if you want to skip signing if public and private keys mismatch&lt;br /&gt;
 allow_pubkey_mismatch = true;&lt;br /&gt;
 &lt;br /&gt;
 # Domain specific settings&lt;br /&gt;
 domain {&lt;br /&gt;
   &amp;lt;maildomain&amp;gt; { selector = &amp;quot;&amp;lt;selector&amp;gt;&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specify parameters (MAILDOMAIN already defined above):&lt;br /&gt;
&lt;br /&gt;
 MAILDOMAIN=&amp;quot;example.com&amp;quot;&lt;br /&gt;
 SELECTOR=&amp;quot;202406&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Replace maildomain and selector in configuration:&lt;br /&gt;
&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;maildomain&amp;gt;/${MAILDOMAIN}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
 sed -i &amp;quot;s/&amp;lt;selector&amp;gt;/${SELECTOR}/g&amp;quot; /etc/rspamd/local.d/dkim_signing.conf&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create DKIM Key Pair: &lt;br /&gt;
&lt;br /&gt;
NOTE: The &#039;pub&#039; file contains the public key and the configuration to create the corresponding dns record&lt;br /&gt;
&lt;br /&gt;
 mkdir -p /var/lib/rspamd/dkim&lt;br /&gt;
 rspamadm dkim_keygen -s ${SELECTOR} -t ED25519 -d ${MAILDOMAIN} -k /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key &amp;gt; /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
 chown -R rspamd:grommunio /var/lib/rspamd/dkim&lt;br /&gt;
 chmod 640 /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.key&lt;br /&gt;
 cat /var/lib/rspamd/dkim/${MAILDOMAIN}-${SELECTOR}.pub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Start Rspamd and Test ===&lt;br /&gt;
&lt;br /&gt;
  rc-update add rspamd&lt;br /&gt;
  rcctl start rspamd&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Test rspam client connection getting statistics (you need to wait some minutes until stats are available):&lt;br /&gt;
&lt;br /&gt;
 #rspamc -h /run/rspamd/worker-controller.sock stat&lt;br /&gt;
 rspamc stat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Finalize and Verify Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Restart Services ===&lt;br /&gt;
Restart all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \&lt;br /&gt;
     gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \&lt;br /&gt;
     grommunio-admin-api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Verify Service Status ===&lt;br /&gt;
Check the status of all services:&lt;br /&gt;
&lt;br /&gt;
 rcctl status&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Check Logs ===&lt;br /&gt;
Inspect logs for any errors or issues:&lt;br /&gt;
&lt;br /&gt;
 find /var/log -type f | xargs tail -n50 | grep -iE &#039;==&amp;gt;|fail|crit|error|alert|corrupt|warning&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Access ===&lt;br /&gt;
Admin UI: [https://mail.example.local:8443](https://mail.example.local:8443)&lt;br /&gt;
&lt;br /&gt;
Web UI: [https://mail.example.local](https://mail.example.local)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Admin UI - First steps ===&lt;br /&gt;
Log in with user &#039;admin&#039; and the previously created ADMIN_PASS&lt;br /&gt;
&lt;br /&gt;
Create and change the following entities:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Defaults:&#039;&#039;&#039; Set the overall defaults to be applied to all domains and users&lt;br /&gt;
     If you use PAM, ensure that the flag &#039;Allow SMTP sending (used by POP3/IMAP clients)&#039; is activated&lt;br /&gt;
# Create an &#039;&#039;&#039;Organization&#039;&#039;&#039;&lt;br /&gt;
# Create a &#039;&#039;&#039;Domain&#039;&#039;&#039; belonging to this organization. Select as well &amp;quot;Create domain admin role&amp;quot;&lt;br /&gt;
# Create &#039;&#039;&#039;Users&#039;&#039;&#039; belonging to the domain&lt;br /&gt;
&lt;br /&gt;
NOTE: For some reason, the first user is not created properly. Permissions are wrong and the sqlite database is not created. It is suggested to create a second user, ensure that the permissions are set correctly and then delete and recreate the first user&lt;br /&gt;
 &lt;br /&gt;
Correct user permissions are like follows:&lt;br /&gt;
&lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 user1&lt;br /&gt;
 &lt;br /&gt;
 ls -l /var/lib/gromox/user/example.com/user1&lt;br /&gt;
 drwxrwx---    8 grommuni gromox      4.0K Jun 21 14:05 .&lt;br /&gt;
 drwxr-xr-x    4 grommuni gromox      4.0K Jun 21 14:05 ..&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 cid&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 config&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 eml&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 exmdb&lt;br /&gt;
 drwxrwx---    2 grommuni gromox      4.0K Jun 21 14:05 ext&lt;br /&gt;
 -rw-r--r--    1 gromox   gromox         0 Jun 21 14:05 tables.sqlite3&lt;br /&gt;
 drwxrwx---    4 grommuni gromox      4.0K Jun 21 14:05 tmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Web UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Verify if you can access the web UI with your new user&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test saslauthd authentication ===&lt;br /&gt;
&lt;br /&gt;
Finally, test saslauthd authentication with PAM&lt;br /&gt;
&lt;br /&gt;
 testsaslauthd -u username -r domain -p password -s smtp&lt;br /&gt;
 testsaslauthd -u username@domain -p password -s smtp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add/verify the license ===&lt;br /&gt;
&lt;br /&gt;
In case you have a license you can configure it in the admin UI under grommunio settings:&lt;br /&gt;
 https://mail.example.local:8443/license&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default (fallback) community license is defined in the following file&lt;br /&gt;
 vi /usr/share/grommunio-admin-api/tools/license.py&lt;br /&gt;
&lt;br /&gt;
== 10. End User Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== Admin UI ===&lt;br /&gt;
Log into the Admin UI with the username `admin` and the previously created `ADMIN_PASS`.&lt;br /&gt;
&lt;br /&gt;
=== License Configuration ===&lt;br /&gt;
If you have a license, you can configure it under &#039;&#039;&#039;Grommunio settings&#039;&#039;&#039; in the Admin UI.&lt;/div&gt;</summary>
		<author><name>Midas</name></author>
	</entry>
</feed>