Debian Postfix + Dovecot + MariaDB 配置连接:SQL 虚拟域名、用户与别名
1. 服务介绍
Postfix 负责 SMTP 邮件收发和队列管理,Dovecot 负责 IMAP/LMTP、邮箱访问和认证,MariaDB 保存虚拟域名、邮箱用户、密码哈希和邮件别名。三者组合可以让一台 Debian 邮件服务器托管多个域名和大量邮箱,而不需要为每个邮箱创建 Linux 系统账号。
本文聚焦 MariaDB 与 Postfix/Dovecot 的连接关系:创建虚拟域名、虚拟用户和别名表;配置 Postfix MySQL map;配置 Dovecot SQL passdb/userdb;使用 vmail 用户保存 Maildir;最后用 SQL map、认证、端口、队列和日志命令验证。
原实验文本包含明文邮箱密码、数据库密码、旧 IP 和不安全的明文密码方案,本文全部移除,改用密码哈希、占位符、最小权限数据库账号和 TLS。
2. 准备运行环境
• 操作系统:Debian 10;其他版本按 Postfix、Dovecot、MariaDB 和 OpenSSL 版本调整。
• 软件包:postfix、postfix-mysql、dovecot-core、dovecot-imapd、dovecot-lmtpd、dovecot-mysql、mariadb-server、mariadb-client。
• 域名:示例使用 example.test 和 mail.example.test,执行前替换为当前实验域名。
• DNS:邮件主机 A/AAAA、域名 MX 和反向解析已准备。
• 数据库:MariaDB 已启动,创建专用读取账号;数据库 3306 尽量只监听本机或受限管理网段。
• 邮箱:使用 /var/mail/vhosts 保存虚拟邮箱,固定 vmail UID/GID。
• TLS:证书 SAN 包含 mail.example.test;客户端使用 993 IMAPS、465 SMTPS 或 587 STARTTLS。
• 凭据:所有数据库和邮箱密码只交互输入,不写入文档、脚本、截图或日志。
3. 相关知识
3.1 三张核心表
• virtual_domains:域名是否由当前邮件服务器负责。
• virtual_users:邮箱地址、密码哈希和 Maildir 相对路径。
• virtual_aliases:别名地址到目标邮箱的映射。
3.2 Postfix map 与 Dovecot SQL
Postfix 使用 MySQL map 查询域名、邮箱和别名;Dovecot 使用 SQL 查询密码哈希和用户目录。两边查询账号只需要 SELECT 权限,不应使用 MariaDB root 账号。
3.3 Maildir 和 LMTP
Postfix 收到邮件后,通过 Dovecot LMTP Socket 投递到 /var/mail/vhosts/域名/用户名/Maildir。Postfix、Dovecot 和 vmail 必须对路径、UID/GID、目录权限保持一致。
3.4 密码安全
邮箱密码使用 doveadm pw -s SHA512-CRYPT 生成哈希。数据库连接密码放在 root 可读的配置文件中,并设置 600 权限;不要使用原实验中的明文密码或 PLAIN 存储。
3.5 防开放中继
Postfix 必须保留 reject_unauth_destination。客户端提交邮件使用 465/587 和 SMTP AUTH;25 主要用于服务器间 SMTP。删除中继限制会导致服务器被滥发邮件。
4. 实验步骤
4.1 设置 FQDN 和 DNS
sudo hostnamectl set-hostname mail.example.test
hostname --fqdn
getent hosts mail.example.test
dig example.test MX +short
dig mail.example.test A +short
MX 目标必须是可解析的邮件主机名,不能直接写 IP。旧实验地址不适用于当前网络,执行前替换占位符。
4.2 安装软件
sudo apt update
sudo apt install -y postfix postfix-mysql \
dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql \
mariadb-server mariadb-client openssl ca-certificates
sudo systemctl enable --now mariadb postfix dovecot
sudo systemctl is-active mariadb
sudo systemctl is-active postfix
sudo systemctl is-active dovecot
Postfix 安装向导选择 Internet Site,系统邮件名填写实际邮件域名。交互密码不写入文档。
4.3 创建 MariaDB 表和最小权限账号
用 MariaDB 管理账号创建数据库和读取账号。DB_READER_PASSWORD 是占位符,必须在受控终端替换,不能保留真实值。
CREATE DATABASE mailserver CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'mailreader'@'localhost' IDENTIFIED BY 'DB_READER_PASSWORD';
GRANT SELECT ON mailserver.* TO 'mailreader'@'localhost';
FLUSH PRIVILEGES;
USE mailserver;
CREATE TABLE virtual_domains (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(190) NOT NULL UNIQUE
);
CREATE TABLE virtual_users (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
domain VARCHAR(190) NOT NULL,
email VARCHAR(190) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
maildir VARCHAR(255) NOT NULL
);
CREATE TABLE virtual_aliases (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
source VARCHAR(190) NOT NULL,
destination VARCHAR(190) NOT NULL
);
4.4 插入测试数据
生成邮箱密码哈希:
sudo doveadm pw -s SHA512-CRYPT
把命令输出的哈希交互写入 SQL,不把明文密码写入数据库:
USE mailserver;
INSERT INTO virtual_domains(name) VALUES ('example.test');
INSERT INTO virtual_users(domain,email,password,maildir)
VALUES ('example.test','[email protected]','{SHA512-CRYPT}HASH_FROM_DOVEADM','example.test/user1');
INSERT INTO virtual_users(domain,email,password,maildir)
VALUES ('example.test','[email protected]','{SHA512-CRYPT}HASH_FROM_DOVEADM','example.test/user2');
INSERT INTO virtual_aliases(source,destination)
VALUES ('[email protected]','[email protected]'),
('[email protected]','[email protected]');
查询时只查看地址和目录:
SELECT id,name FROM virtual_domains;
SELECT id,domain,email,maildir FROM virtual_users;
SELECT id,source,destination FROM virtual_aliases;
4.5 创建 vmail 用户和邮箱目录
sudo groupadd -g 5000 vmail 2>/dev/null || true
sudo useradd -g vmail -u 5000 vmail -d /var/mail \
-s /usr/sbin/nologin 2>/dev/null || true
sudo mkdir -p /var/mail/vhosts/example.test/user1/Maildir
sudo mkdir -p /var/mail/vhosts/example.test/user2/Maildir
sudo chown -R vmail:vmail /var/mail/vhosts
sudo chmod -R 700 /var/mail/vhosts
4.6 配置 Postfix MySQL map
sudo postconf -e 'myhostname = mail.example.test'
sudo postconf -e 'mydomain = example.test'
sudo postconf -e 'inet_interfaces = all'
sudo postconf -e 'virtual_transport = lmtp:unix:private/dovecot-lmtp'
sudo postconf -e 'virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf'
sudo postconf -e 'virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf'
sudo postconf -e 'virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf'
sudo postconf -e 'smtpd_recipient_restrictions = permit_sasl_authenticated, reject_unauth_destination'
创建域名、邮箱、别名查询文件。三个文件都只允许 root 和 Postfix 必要组读取,DB_READER_PASSWORD 只在服务器上填写。
# /etc/postfix/mysql-virtual-mailbox-domains.cf
user = mailreader
password = DB_READER_PASSWORD
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_domains WHERE name='%s'
# /etc/postfix/mysql-virtual-mailbox-maps.cf
user = mailreader
password = DB_READER_PASSWORD
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'
# /etc/postfix/mysql-virtual-alias-maps.cf
user = mailreader
password = DB_READER_PASSWORD
hosts = 127.0.0.1
dbname = mailserver
query = SELECT destination FROM virtual_aliases WHERE source='%s'
sudo chown root:root /etc/postfix/mysql-virtual-*.cf
sudo chmod 640 /etc/postfix/mysql-virtual-*.cf
postmap -q example.test mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
postmap -q [email protected] mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
postmap -q [email protected] mysql:/etc/postfix/mysql-virtual-alias-maps.cf
sudo postfix check
4.7 配置 Dovecot SQL 和 LMTP
设置 Maildir、协议和认证:
sudo sed -i 's|^#\?mail_location.*|mail_location = maildir:/var/mail/vhosts/%d/%n/Maildir|' \
/etc/dovecot/conf.d/10-mail.conf
sudo sed -i 's|^#\?protocols.*|protocols = imap lmtp|' /etc/dovecot/dovecot.conf
sudo sed -i 's|^#\?disable_plaintext_auth.*|disable_plaintext_auth = yes|' \
/etc/dovecot/conf.d/10-auth.conf
sudo sed -i 's|^#\?auth_mechanisms.*|auth_mechanisms = plain login|' \
/etc/dovecot/conf.d/10-auth.conf
auth-sql.conf.ext 使用 SQL passdb 和静态 userdb:
passdb sql {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb static {
driver = static
args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}
dovecot-sql.conf.ext:
driver = mysql
connect = host=127.0.0.1 dbname=mailserver user=mailreader password=DB_READER_PASSWORD
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email AS user, password FROM virtual_users WHERE email='%u'
设置 SQL 配置权限:
sudo chown root:root /etc/dovecot/dovecot-sql.conf.ext
sudo chmod 600 /etc/dovecot/dovecot-sql.conf.ext
在 10-master.conf 配置 LMTP 和 Postfix auth Socket:
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
重启并检查:
sudo doveconf -n >/tmp/dovecot-effective.conf
sudo ls -l /var/spool/postfix/private/auth /var/spool/postfix/private/dovecot-lmtp
sudo systemctl restart dovecot postfix
5. 验证结果
systemctl is-active mariadb
systemctl is-active postfix
systemctl is-active dovecot
ss -lntp | grep -E ':25|:465|:587|:993|:3306'
sudo postfix check
sudo doveconf -n >/dev/null
验证 SQL map 和 Dovecot 认证:
postmap -q example.test mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
postmap -q [email protected] mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
postmap -q [email protected] mysql:/etc/postfix/mysql-virtual-alias-maps.cf
sudo doveadm auth test [email protected]
sudo doveadm user [email protected]
验证邮箱目录、LMTP Socket、队列和日志:
sudo find /var/mail/vhosts -maxdepth 4 -type d -printf '%M %u:%g %p\n'
sudo ls -l /var/spool/postfix/private/auth /var/spool/postfix/private/dovecot-lmtp
sudo postqueue -p
sudo tail -n 100 /var/log/mail.log
验证 TLS:
openssl s_client -connect mail.example.test:993 \
-servername mail.example.test </dev/null 2>&1 \
| grep -E 'subject=|issuer=|Verify return code'
预期结果:Postfix、Dovecot、MariaDB 均为 active;SQL map 返回有效结果;Dovecot 账号认证通过;虚拟邮箱目录属主为 vmail;LMTP Socket 存在;未认证外部中继被拒绝;配置和日志不包含真实数据库密码。
6. 常见问题
6.1 Postfix map 查询为空
检查数据库连接账号、表名、字段名、域名大小写和 SQL 查询。逐个使用 postmap -q 测试,不要直接重启猜测。
6.2 Dovecot 认证失败
检查 dovecot-sql.conf.ext、密码哈希、password_query 和 doveadm auth test。不要改用明文密码绕过认证。
6.3 邮件已接收但 Maildir 没有文件
检查 LMTP Socket、virtual_transport、mail_location、vmail UID/GID 和目录权限;查看 /var/log/mail.log 投递状态。
6.4 数据库连接失败
确认 MariaDB 服务、mailreader 权限、数据库主机、3306 监听和防火墙。远程数据库禁止使用 % 全网授权。
6.5 证书或 IMAP 连接失败
检查 993 监听、证书 SAN、私钥权限和 Dovecot SSL 配置;客户端访问名称必须与证书一致。
6.6 日志查看
sudo journalctl -u mariadb -n 80 --no-pager
sudo journalctl -u postfix -n 100 --no-pager
sudo journalctl -u dovecot -n 100 --no-pager
sudo postqueue -p
7. 实验结论
本实验完成 MariaDB 虚拟域名、虚拟用户和别名表设计,完成 Postfix MySQL map、Dovecot SQL 认证、虚拟 Maildir、LMTP 投递和基础 TLS 验证。最终以 SQL map、Dovecot 认证、邮箱目录、SMTP/IMAP 端口、队列和日志共同确认配置生效。
生产环境必须移除明文密码,使用安全密码哈希、最小权限数据库账号、受限数据库来源、TLS、备份和账号生命周期管理。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/weixin_44524357/article/details/164971784



