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