Postfix + Dovecot 自托管邮箱
最近在服务器上折腾了一下邮箱自托管。使用 postfix 作为 MTA&MDA 收信,dovecot 作为 imap server。因为 vps 会拦截目标端口25的出站流量,所以发信使用第三方服务了(smtp2go)。服务器上也没有发信需求,所以 postfix 完全没有配发信。
postfix 和 dovecot 通过 Arch Linux 官方仓库安装。别的安装方式的默认配置文件的位置可能不同。
Postfix 配置
目标:只收不发;多个域名上的多个虚拟用户,无对应 unix 用户。
基本知识
配置文件
- main.cf: 默认配置
- master.cf: 每个 service 的配置,会覆盖 main.cf 中的默认配置
hash
main.cf 中可以用 hash:/path/to/file 来指定加载 hash。例:
# main.cf
# postfix 实际会寻找 /etc/postfix/bar.db 文件
foo = hash:/etc/postfix/bar
# /etc/postfix/bar
key1 value1, value2
key2 value3
用 postmap [-F] bar
来生成 bar.db
。 -F
会将 value 视为文件路径列表,将文件内容用 base64 编码、连接。
基本配置
- main.cf
- myhostname: 互联网域名(比如对 ip reverse DNS 得到的域名)
- 其余默认(因为不考虑发信)
smtpd 开启 starttls
据说强制 tls 是不推荐的配置。
以下配置在开启 587 端口 starttls 的同时保留 25 端口明文传输。
# main.cf
# tls 相关日志
smtpd_tls_loglevel = 1
# 声明支持 StartTLS
smtpd_tls_security_level = may
smtpd_tls_protocols = >=TLSv1.2
smtpd_tls_exclude_ciphers = aNULL, eNULL, EXPORT, DES, RC4, MD5, PSK, aECDH, EDH-DSS-DES-CBC3-SHA, EDH-RSA-DES-CBC3-SHA, KRB5-DES, CBC3-SHA
smtpd_tls_dh1024_param_file = /etc/postfix/dhparams.pem
# 默认使用的 chain,密钥+证书
smtpd_tls_chain_files = /etc/postfix/cert/chain.pem
# master.cf
# 以下服务的端口是 postfix 默认配置
# 25 端口
smtp inet n - n - - smtpd
# 587 端口 声明 STARTTLS 并且只允许 STARTTLS
submission inet n - n - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_tls_auth_only=yes
-o milter_macro_daemon_name=ORIGINATING
开启 sni,对不同域名使用不同证书
# main.cf
tls_server_sni_maps = hash:/etc/postfix/sni
# /etc/postfix/sni
# 这个文件在 postmap 时要用 -F
domain.name /path/to/chain, /path/to/another/chain
anotherdomain.name /path/to/chain
使用虚拟账户
将不同用户的邮件投递到指定目录。可以创建一个单独的用户来拥有这个目录,然后把 uid 和 gid 写在这里。
# main.cf
virtual_mailbox_domains = domain1, domain2
virtual_mailbox_base = /base/path/to/mail/dir
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_uid_maps = static:1000
virtual_gid_maps = static:1000
# /etc/postfix/vmailbox
# 这里路径结尾有/,表明使用 Maildir 风格存储邮件(Maildir 是 dovecot 的默认方式)
# 这些路径在下面 dovecot 的配置中会被用到
user1@domain1 domain1/user1/
user2@domain1 domain1/user2/
user1@domain2 domain2/user1/
Dovecot
dovecot.conf
protocols
: 只启用 imap
10-master.cf
可以设置自定义 port。设置为0则关闭对应服务(可以以此来关闭 imap 只保留 imaps)
service imap-login {
inet_listener imap {
port = 0
}
inet_listener imaps {
port = 993
}
}
10-ssl.conf
启用 tls 并弃用不安全的配置
ssl = required
ssl_cert = </path/to/cert
ssl_key = </path/to/key
ssl_dh = </path/to/dhparam
ssl_min_protocol = TLSv1.2
ssl_cipher_list=ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
ssl_prefer_server_ciphers = yes
sni:
local_name imap.example.org {
ssl_cert = </path/to/imap.example.org/cert
ssl_key = </path/to/imap.example.org/key
}
local_name imap.example2.org {
ssl_cert = </path/to/imap.example2.org/cert
ssl_key = </path/to/imap.example2.org/key
}
10-auth.conf
密码由 tls 保护所以此处保留默认的明文认证
auth_mechanisms = plain
使用 auth-passwdfile.conf.ext 作为 userdb
!include auth-passwdfile.conf.ext
auth-passwdfile.conf.ext
首先用和 /etc/shadow 一样的格式写明各个用户的用户名和密码。密码直接存明文了就(
这里的 uid 和 gid 要与下面 auth-passwdfile.conf.ext 中指定的目录的所有者一致(或者拥有该目录的 rwx 权限)。一般对应上面 postfix 配置时设置的用户(这里)。
user1@domain:{PLAIN}password:1000:1000
user2@domain:{PLAIN}123456:1000:1000
在 auth-passwdfile.conf.ext 中写 shadow 文件的路径:
# auth-passwdfile.conf.ext
mail_location = maildir:/path/to/virtual/mailbox/%d/%n
passdb {
driver = passwd-file
args = username_format=%n@%d /path/to/shadow/file
}
userdb {
driver = passwd-file
args = username_format=%n@%d /path/to/shadow/file
}
杂项
使用 openssl 验证 starttls
如验证 smtp 的 starttls:
openssl s_client -servername xxx -connect xxx:port -starttls smtp