Grommunio Mail Server: Difference between revisions
No edit summary |
|||
Line 29: | Line 29: | ||
To start, install MariaDB and necessary utilities | To start, install MariaDB and necessary utilities | ||
apk add mariadb mariadb-client mariadb-server-utils | |||
Line 36: | Line 36: | ||
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. | 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: | 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: | Set a symlink to the standard mysql data directory for compatibility reason: | ||
ln -s /srv/mysql /var/lib/mysql | |||
Restart service: | Restart service: | ||
rc-service mariadb restart | |||
Line 61: | Line 61: | ||
Set the new root password to the one defined above and answer everything with 'y' | Set the new root password to the one defined above and answer everything with 'y' | ||
sudo mysql_secure_installation | |||
Line 67: | Line 67: | ||
Create a new user for Grommunio and assign privileges: | 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}" | |||
Line 78: | Line 78: | ||
Edit the MariaDB configuration for better performance: | Edit the MariaDB configuration for better performance: | ||
vi /etc/my.cnf.d/mariadb-server.cnf | |||
Add the following configuration: | 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: | 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: | Restart MariaDB and enable it to start on boot: | ||
rc-update add mariadb default | |||
rc-service mariadb restart | |||
Line 131: | Line 131: | ||
Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1): | Check if the MariaDB listener is running and bound to the correct interface (127.0.0.1): | ||
ss -tulpn | |||
=== Create Grommunio Database === | === Create Grommunio Database === | ||
Define the database parameters and create the 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: | Test the database connection: | ||
mysql -hlocalhost -u grommunio -p${MYSQL_PASS} grommunio | |||
Line 160: | Line 159: | ||
Download MySQLTuner: | 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: | 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 | |||
Line 173: | Line 172: | ||
NOTE: The perl-doc package is installed because it's the only one containing the perldiag.pod required by mysqltuner.pl | 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: | 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} | |||
Line 187: | Line 186: | ||
Install the necessary Nginx modules: | Install the necessary Nginx modules: | ||
apk add nginx nginx-mod-http-headers-more nginx-mod-http-vts nginx-mod-http-brotli | |||
Line 193: | Line 192: | ||
Backup the original Nginx configuration and edit it for security headers and TLS settings: | 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: | 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: | 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: | Restart Nginx and enable it to start on boot: | ||
rc-update add nginx | |||
rc-service nginx restart | |||
Line 245: | Line 244: | ||
Install the basic php packages. The modules are installed as grommunio dependencies: | Install the basic php packages. The modules are installed as grommunio dependencies: | ||
apk add php83 php83-fpm | |||
Disable default fpm conf: | Disable default fpm conf: | ||
mv /etc/php83/php-fpm.d/www.conf /etc/php83/php-fpm.d/www.conf.default | |||
Line 257: | Line 256: | ||
Backup config file /etc/php83/php.ini | 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 | 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 | 2. Disable information leakage | ||
sed 's/^;\?\(expose_php\).*/\1 = Off/' -i /etc/php83/php.ini | |||
3. Configure Error handling | 3. 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 | |||
4. PHP Resource Control (Optional) | 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 | 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 | |||
Line 300: | Line 299: | ||
sed 's/^;\?\(session.use_only_cookies\).*/\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 | sed 's/^;\?\(session.cookie_httponly\).*/\1 = 1/' -i /etc/php83/php.ini | ||
== 5. Install and Configure Postfix == | == 5. Install and Configure Postfix == | ||
Line 306: | Line 307: | ||
Install Postfix and related modules: | Install Postfix and related modules: | ||
apk add postfix postfix-mysql postfix-pcre | |||
Line 312: | Line 313: | ||
Backup and configure the Postfix settings. Adapt the values as necessary, such as `myhostname`, `mynetworks`, and `smtp_tls_chain_files`: | 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: | Run Postfix setup: | ||
newaliases | |||
postmap /etc/postfix/transport | |||
Enable Postfix service: | Enable Postfix service: | ||
rc-update add postfix | |||
rc-service postfix restart | |||
Line 331: | Line 332: | ||
Check the Postfix logs for any errors: | Check the Postfix logs for any errors: | ||
tail -f /var/log/maillog | tail -f /var/log/maillog | ||
Line 340: | Line 341: | ||
Since Grommunio requires IPv6 for its daemons: | Since Grommunio requires IPv6 for its 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 | |||
Line 356: | Line 358: | ||
Set up your MySQL database connection details: | Set up your MySQL database connection details: | ||
MYSQL_HOST="localhost" | |||
MYSQL_USER="grommunio" | |||
MYSQL_PASS="Passw0rd3" | |||
MYSQL_DB="grommunio" | |||
Line 365: | Line 367: | ||
Adjust the following for your specific setup: | Adjust the following for your specific setup: | ||
FQDN="mail.example.local" | |||
MAILDOMAIN="example.com" | |||
RELAYHOST="123.123.123.1" | |||
ADMIN_PASS="Passw0rd4" | |||
Line 374: | Line 376: | ||
Install necessary dependencies: | 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: | Optionally, install deprecated ActiveSync if needed: | ||
# apk add grommunio-dav grommunio-sync | |||
Line 386: | Line 388: | ||
Move the largest directory `/var/lib/gromox` to another disk and create a symlink: | 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 | |||
Line 393: | Line 395: | ||
Enable all necessary Grommunio 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 | |||
Line 402: | Line 404: | ||
Modify the configuration files to match your environment: | 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.) | |||
Line 410: | Line 412: | ||
Prepare Postfix for integration with Grommunio: | 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 | |||
Line 418: | Line 420: | ||
Link and configure your SSL 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 | |||
Line 427: | Line 429: | ||
Set up authentication services: | 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 | |||
Line 443: | Line 448: | ||
Initialize the database: | Initialize the database: | ||
gromox-dbop -C | |||
Set the Grommunio admin password: | Set the Grommunio admin password: | ||
grommunio-admin passwd --password "${ADMIN_PASS}" | |||
Revision as of 23:34, 30 November 2024
![]() 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. 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
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 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
Since Grommunio requires IPv6 for its daemons:
Edit `/etc/hosts` to include IPv6 localhost:
vi /etc/hosts ----- ::1 localhost ipv6-localhost ipv6-loopback -----
Ensure IPv6 is enabled in `/etc/sysctl.conf`:
sed -i 's/^net\.ipv6\.conf\..*\.disable_ipv6\s=\s1/#&/' /etc/sysctl.conf sysctl -p ping ::1 # Test if IPv6 is working
Configure Database Parameters
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.