Grommunio 邮件服务器

来自 Alpine Linux

本教程涵盖了在 Alpine Linux 上使用 grommunio 设置邮件服务器的步骤,grommunio 是一个开源的群件解决方案,支持电子邮件、日历和任务管理。Grommunio 以其独特的 MAPI 支持而脱颖而出,能够与 Microsoft Outlook 和其他 MAPI 客户端无缝集成,使其成为专有系统的理想开源替代方案。此设置包括必要的组件,如 MariaDBNginxPHPPostfix,以创建一个功能齐全的邮件服务器。请跟随以下步骤,使用 grommunio 的强大功能构建一个安全、可扩展的通信平台。

先决条件

在继续安装之前,请确保您已设置全新的 Alpine Linux 系统。您需要 root 权限才能执行这些命令。

步骤

  1. 安装和配置 MariaDB
  2. 安装和配置 Nginx
  3. 安装和配置 PHP
  4. 安装和配置 Postfix
  5. 安装和配置 Grommunio
  6. 配置 Valkey (Redis 替代品)
  7. 安装和配置 Rspamd
  8. 完成和验证安装

1. 安装和配置 MariaDB

安装 MariaDB

首先,安装 MariaDB 和必要的实用程序

apk add mariadb mariadb-client mariadb-server-utils


定义稍后在设置和配置中使用的变量。

默认数据路径是 `/var/lib/mysql`,其中包含整个数据库。如果您喜欢其他位置,请在此处定义它并创建一个符号链接。无论如何,grommunio 数据库将相当小,因为它只包含配置。

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


设置默认系统表

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


为兼容性原因,设置到标准 mysql 数据目录的符号链接

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


重启服务

rc-service mariadb restart


运行内置的安全脚本

将新的 root 密码设置为上面定义的密码,并对所有问题回答 'y'

sudo mysql_secure_installation


创建 MariaDB 用户

为 Grommunio 创建一个新用户并分配权限

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 | mariadb -u root --password="${DB_ROOT_PASS}"

配置 MariaDB

编辑 MariaDB 配置以获得更好的性能

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


添加以下配置

[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


为 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


重启 MariaDB 并启用开机启动

rc-update add mariadb default
rc-service mariadb restart


验证 MariaDB 设置

检查 MariaDB 监听器是否正在运行并绑定到正确的接口 (127.0.0.1)

ss -tulpn

创建 Grommunio 数据库

定义数据库参数并创建 Grommunio 数据库

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 | mariadb -u admin --password="${DB_PASS}"


测试数据库连接

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

2. 安装和配置 Nginx

安装 Nginx

安装必要的 Nginx 模块

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


配置 Nginx

备份原始 Nginx 配置并编辑它以设置安全标头和 TLS 设置

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


添加以下配置

#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;


通过重命名禁用默认页面

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


重启 Nginx 并启用开机启动

rc-update add nginx
rc-service nginx restart

3. 安装和配置 PHP

安装 PHP

安装基本的 php 软件包。模块作为 grommunio 依赖项安装

apk add php83 php83-fpm

禁用默认 fpm 配置

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


加强 PHP 配置

备份配置文件 /etc/php83/php.ini

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


禁用远程 PHP 代码执行
注意: 如果您需要 grommunio-sync (ActiveSync),请设置 allow_url_fopen=On

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


禁用信息泄露

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


配置错误处理

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 资源控制 (可选)

#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 


禁用易受攻击的函数
注意: 如果您需要 grommunio-sync (ActiveSync),请删除 escapeshellarg & exec

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 


加强会话安全

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

4. 安装和配置 Postfix

安装 Postfix

安装所需的软件包

apk add postfix postfix-mysql postfix-pcre


配置 Postfix

首先备份原始文件

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


下载准备好的配置文件

wget https://alpinelinuxsupport.com/downloads/postfix-configuration-files.zip


将准备好的配置文件复制到 `/etc/postfix/` 并根据您的环境进行调整。确保您至少更改以下值

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


创建所需的 postmap 文件

newaliases
postmap /etc/postfix/transport


运行 Postfix 设置

newaliases
postmap /etc/postfix/transport


启用 postfix 服务并重启

rc-update add postfix
rc-service postfix restart

验证 Postfix 日志

检查 Postfix 日志中是否有任何错误

tail -f /var/log/maillog

5. 安装和配置 Grommunio

启用 IPv6

首先,启用 ipv6,这对于 grommunio 守护程序是强制性的

编辑 `/etc/hosts` 以确保配置了 IPv6 localhost

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


确保在 `/etc/sysctl.conf` 中启用了 IPv6

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

指定数据库参数

如果需要,指定数据库参数(已在步骤 1 中指定)

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


指定域名参数

FQDN 例如供 Outlook 客户端连接使用。此名称必须存在于使用的证书中。

默认邮件域例如用于未送达报告和生成一些简单的 TLS 证书。在此处仅指定一个域。

根据您的具体设置调整以下内容

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


安装软件包

安装必要的依赖项(需要 util-linux-login 才能使 pam.d 工作)

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


安装 grommunio 软件包

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


可选地,如果需要,安装已弃用的 ActiveSync

apk add grommunio-dav grommunio-sync


重新定位邮件存储

目录 `/var/lib/gromox` 将是最大的目录,其中包含所有邮件和附件。因此,我们将它重新定位到另一个磁盘并创建一个符号链接

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


启用所需服务

启用所有必需的服务

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


配置 Grommunio

使用上面指定的自定义参数修改配置文件。

配置 gromox *.cfg

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


配置 gromox adaptor

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


配置自动发现

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


为发件人映射准备额外的 postfix 文件

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


配置 postfix 文件

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


配置 TLS 证书

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


链接 TLS 证书配置
注意: 由于两个 ssl 文件是相同的,因此链接它们可能更有意义

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


配置 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


准备外部或自签名证书并将它们放入

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


根据 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/


将 gromox 添加到 ssl-cert (或另一个) 组,允许读取私钥

addgroup gromox ssl-cert


检索证书指纹

注意: 仅当您使用中继服务器验证客户端证书时才需要此操作。

将输出添加到中继服务器上的 relay_clientcerts 文件,并使用 postmap 命令对其进行哈希处理。

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


配置 SMTP 的 PAM

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


创建默认 login.defs (util-linux-login 中缺少)

cat > /etc/login.defs <<EOF
# By default, create a group with the name of the user
USERGROUPS_ENAB yes
EOF


配置 SASL 身份验证

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


SMTP 服务的 SASL 配置

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


如果您从另一台服务器迁移,请将 X500-org-name 替换为原始名称

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/*

初始化数据库

初始化数据库

gromox-dbop -C


设置 Grommunio 管理员密码

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


将 grommunio 添加到 adm 组,以使管理 UI 能够读取 `/var/log/maillog`。
注意: 需要额外的自定义补丁(由 alpinelinuxsupport.com 团队提供)才能使日志监控工作

addgroup grommunio adm

配置防火墙

打开必要的防火墙端口

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

6. 配置 Valkey

启用 Syslog

syslog facility 设置为 'local0'。
注意: 建议将 local0 重定向到 syslog.conf 中的 maillog,因为所有其他 grommunio 进程都写入 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


禁用 jemalloc

禁用 jemalloc 后台线程,因为我们使用 libc malloc

sed -i "s/^jemalloc-bg-thread yes/jemalloc-bg-thread no/" /etc/valkey/grommunio.conf


减少 maxclients

减少 maxclients 以避免关于最大打开文件的错误消息

echo "maxclients 4064" >> /etc/valkey/grommunio.conf


启用内存过载

Valkey 坚持在 sysctl 中启用内存过载。如果未设置,则会显示启动警告

cat >> /etc/sysctl.conf <<EOF
# Enable memory overcommit for valkey
vm.overcommit_memory = 1
EOF


更新系统配置

sysctl -p

启动 Valkey 并测试

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

7. 安装和配置 Rspamd

安装 Rspamd

 apk add rspamd rspamd-client


配置 Rspamd

设置常规选项

cat > /etc/rspamd/local.d/options.inc <<EOF
dns {
  enable_dnssec = true;
  timeout = 4s;
  retransmits = 5;
}
EOF


配置 redis/valkey 连接

cat > /etc/rspamd/local.d/redis.conf <<EOF
read_servers = "127.0.0.1";
write_servers = "127.0.0.1";
EOF


配置普通 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


配置代理 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


将 postfix 添加到 rspamd 组以访问套接字

addgroup postfix rspamd


配置控制器 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


创建用户密码并在 worker-controller.inc 中替换它

命令: 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


将 rspamd 日志重定向到 syslog

cat > /etc/rspamd/local.d/logging.inc << EOF
# Redirect rspamd logs to the mail log
type = "syslog";
facility = "mail";
level = "notice";
EOF


配置外部中继

cat > /etc/rspamd/local.d/external_relay.conf << EOF
enabled = true;
rules {
  FETCHMAIL {
    strategy = "local";
  }
}
EOF


配置操作

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


配置 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


配置 dkim 签名

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


指定参数 (MAILDOMAIN 已在上面定义)

MAILDOMAIN="example.com"
SELECTOR="202406"


在配置中替换 maildomain 和 selector

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


创建 DKIM 密钥对
注意: 'pub' 文件包含公钥和创建相应 dns 记录的配置

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

启动 Rspamd 并测试

 rc-update add rspamd
 rcctl start rspamd


测试 rspam 客户端连接获取统计信息 (您需要等待几分钟直到统计信息可用)

#rspamc -h /run/rspamd/worker-controller.sock stat
rspamc stat

8. 完成和验证

重启服务

重启所有服务

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

验证服务状态

检查所有服务的状态

rcctl status


检查日志

检查日志中是否有任何错误或问题

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


Web UI 访问

Admin UI: https://mail.example.local:8443

Web UI: https://mail.example.local


Admin UI - 初始步骤

使用用户 'admin' 和先前创建的 ADMIN_PASS 登录

创建和更改以下实体

  1. 默认值: 设置应用于所有域和用户的总体默认值。如果您使用 PAM,请确保激活标志“允许 SMTP 发送(POP3/IMAP 客户端使用)”
  2. 创建一个 组织
  3. 创建一个属于此组织的。同时选择“创建域管理员角色”
  4. 创建属于该域的 用户


注意: 由于某些原因,第一个用户未正确创建。权限错误,并且未创建 sqlite 数据库。建议创建第二个用户,确保正确设置权限,然后删除并重新创建第一个用户

正确的用户权限如下所示

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 测试

验证您是否可以使用新用户访问 Web UI


测试 saslauthd 身份验证

最后,使用 PAM 测试 saslauthd 身份验证

testsaslauthd -u username -r domain -p password -s smtp
testsaslauthd -u username@domain -p password -s smtp


添加/验证许可证

如果您有许可证,则可以在 grommunio 设置下的管理 UI 中进行配置

https://mail.example.local:8443/license


默认(备用)社区许可证在以下文件中定义

vi /usr/share/grommunio-admin-api/tools/license.py

参见