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
1. 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
2. Disable information leakage
sed 's/^;\?\(expose_php\).*/\1 = Off/' -i /etc/php83/php.ini
3. 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
4. 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
5. 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
6. 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 Postfix and related modules:
apk add postfix postfix-mysql postfix-pcre
Configure Postfix
Backup and configure the Postfix settings. Adapt the values as necessary, such as `myhostname`, `mynetworks`, and `smtp_tls_chain_files`:
mv /etc/postfix/main.cf /etc/postfix/main.cf.orig mv /etc/postfix/master.cf /etc/postfix/master.cf.orig
Run Postfix setup:
newaliases postmap /etc/postfix/transport
Enable Postfix service:
rc-update add postfix 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
Since Grommunio requires IPv6 for its daemons:
1. Edit `/etc/hosts` to include IPv6 localhost:
vi /etc/hosts ----- ::1 localhost ipv6-localhost ipv6-loopback -----
2. Ensure IPv6 is enabled in `/etc/sysctl.conf`:
sed -i 's/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&/' /etc/sysctl.conf sysctl -p ping ::1 # Test if IPv6 is working
Configure Database Parameters
Set up your MySQL database connection details:
MYSQL_HOST="localhost" MYSQL_USER="grommunio" MYSQL_PASS="Passw0rd3" MYSQL_DB="grommunio"
Specify Internal FQDN, Mail Domain, and Relayhost
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:
apk add valkey valkey-cli cyrus-sasl cyrus-sasl-login util-linux-login 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
Move the largest directory `/var/lib/gromox` 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 necessary Grommunio services:
rc-update add grommunio-admin-api rc-update add gromox-delivery rc-update add gromox-delivery-queue # Add all the other grommunio services
Configure Grommunio Files
Modify the configuration files to match your environment:
sed -i "s/mail.example.local/${FQDN}/g" /etc/gromox/*.cfg sed -i "s/example.com/${MAILDOMAIN}/g" /etc/gromox/*.cfg # Continue modifying other configuration files (mysql_adaptor.cfg, autodiscover.ini, etc.)
Configure Postfix
Prepare Postfix for integration with Grommunio:
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 TLS Certificates
Link and configure your SSL certificates:
ln -s /etc/grommunio-common/nginx/ssl_certificate.conf /etc/grommunio-admin-common/nginx-ssl.conf cat /etc/ssl/private/${FQDN}.key.pem /etc/ssl/certs/${FQDN}.cert.pem > /etc/ssl/private/${FQDN}.key_cert.pem chmod 640 /etc/ssl/private/*.key_cert.pem addgroup gromox ssl-cert
Configure PAM and SASL
Set up authentication services:
# Configure PAM for SMTP cat > /etc/pam.d/smtp <<EOF #%PAM-1.0 auth required pam_gromox.so service=smtp account required pam_permit.so EOF
# Configure SASL authentication cat > /etc/conf.d/saslauthd <<EOF SASLAUTHD_OPTS="-a pam -r" EOF
Initialize the Database and Set Admin Password
Initialize the database:
gromox-dbop -C
Set the Grommunio admin password:
grommunio-admin passwd --password "${ADMIN_PASS}"
Configure Firewall Ports
Open the necessary firewall ports:
# Required ports: 25, 80, 443, etc.
7. Configure Valkey (Redis Replacement)
Enable Syslog
vi /etc/valkey/grommunio.conf ----- syslog-enabled yes syslog-ident valkey syslog-facility local0 -----
Enable Memory Overcommit
vi /etc/sysctl.conf ----- vm.overcommit_memory = 1 ----- sysctl -p
Start Valkey and Test
rcctl restart valkey@grommunio valkey-cli ping # Expected result: 'PONG'
8. Install and Configure Rspamd
Install Rspamd
apk add rspamd rspamd-client
Configure Rspamd
Modify Rspamd configuration files:
cat > /etc/rspamd/local.d/options.inc <<EOF dns { enable_dnssec = true; timeout = 4s; retransmits = 5; } EOF
cat > /etc/rspamd/local.d/redis.conf <<EOF read_servers = "127.0.0.1"; write_servers = "127.0.0.1"; EOF
cat > /etc/rspamd/local.d/worker-proxy.inc <<EOF milter = yes; bind_socket = "/var/run/rspamd/worker-proxy.sock mode=0660 owner=rspamd"; timeout = 120s; upstream "local" { default = yes; self_scan = yes; } count = 4; EOF
Add Postfix to Rspamd Group
addgroup postfix rspamd
Configure DKIM Signing
cat > /etc/rspamd/local.d/dkim_signing.conf <<EOF enabled = true; path = "/var/lib/rspamd/dkim/\$domain-\$selector.key"; selector = "dkim"; sign_authenticated = true; sign_local = false; domain { example.com { selector = "202406"; } } EOF
Generate DKIM Key Pair
mkdir -p /var/lib/rspamd/dkim rspamadm dkim_keygen -s 202406 -t ED25519 -d example.com -k /var/lib/rspamd/dkim/example.com-202406.key > /var/lib/rspamd/dkim/example.com-202406.pub
Start Rspamd
rc-update add rspamd rcctl start rspamd
9. Finalize and Verify Installation
Restart Services
Restart all services:
rcctl restart postfix saslauthd rspamd valkey@grommunio nginx php-fpm83 gromox-delivery gromox-event \ gromox-http gromox-imap gromox-midb gromox-pop3 gromox-delivery-queue gromox-timer gromox-zcore \ grommunio-admin-api
Verify Service Status
Check the status of all services:
rcctl status
Ensure that all services (Postfix, MariaDB, Nginx, PHP, Grommunio) are running correctly:
ss -tulpn
Verify Mail Functionality
Test sending and receiving emails using a mail client and verifying server logs for any errors.
Check Logs
Inspect logs for any errors or issues:
find /var/log -type f | xargs tail -n50 | grep -iE '==>|fail|crit|error|alert|corrupt|warning'
Web UI Access
Admin UI: [1](https://mail.example.local:8443)
10. End User Configuration
Admin UI
Log into the Admin UI with the username `admin` and the previously created `ADMIN_PASS`.
License Configuration
If you have a license, you can configure it under Grommunio settings in the Admin UI.