# Postfix + Dovecot 配置 Let's Encrypt SSL 证书

> 为 SMTP、邮件提交和 IMAP 配置 Let's Encrypt 证书：Postfix smtpd_tls_chain_files、Dovecot 2.3/2.4 写法、续期后自动重载、STARTTLS 测试。

Source: https://ssl.sh/zh/guides/postfix-dovecot-tls/
Last updated: 2026-11-10

Postfix 和 Dovecot 可以共用一张 `mail.example.com` 的 Let's Encrypt 证书：Postfix 在 25 端口提供 STARTTLS、在 587 和 465 提交端口提供 TLS，Dovecot 在 993 端口提供 IMAPS。Certbot 续期后由部署钩子重载两个服务。适用于 Debian、Ubuntu、RHEL 系发行版上的 Postfix 3.4 及以上、Dovecot 2.3 或 2.4，Certbot 4.1 及以上。

## 前提条件

邮件服务器需要一张覆盖客户端和其他服务器连接所用域名的证书。

- Postfix 和 Dovecot 已安装，不开 TLS 时能正常工作，提交端口通过 Dovecot 做 SASL 认证。
- DNS：`mail.example.com` 的 A/AAAA 记录（例如 `203.0.113.10`），域名的 MX 指向它，并配置对应的反向解析（PTR）。
- 安全组和防火墙放行入方向 TCP 25、465、587、993；HTTP-01 验证还需要 80 端口（不通就用 [DNS-01](https://ssl.sh/zh/guides/acme-sh-dnspod-aliyun-dns/)）。
- 已用 snap 安装 Certbot：`sudo snap install --classic certbot && sudo ln -s /snap/bin/certbot /usr/local/bin/certbot`。

## 第一步：为邮件主机名申请证书

证书签给邮件主机名 `mail.example.com`。80 端口没有被占用时用 standalone 模式：

```bash
sudo certbot certonly --standalone -d mail.example.com
```

同一台机器上已有 Web 服务占用 80 端口的，改用 `--webroot -w /var/www/html` 或 `--nginx`。证书在 `/etc/letsencrypt/live/mail.example.com/`。

## 第二步：配置 Postfix

Postfix 用 `smtpd_tls_chain_files` 同时指定私钥和证书链，私钥写在前面。设置证书、25 端口的机会性 TLS 和日志：

```bash
sudo postconf -e 'smtpd_tls_chain_files = /etc/letsencrypt/live/mail.example.com/privkey.pem, /etc/letsencrypt/live/mail.example.com/fullchain.pem'
sudo postconf -e 'smtpd_tls_security_level = may'
sudo postconf -e 'smtpd_tls_mandatory_protocols = >=TLSv1.2'
sudo postconf -e 'smtp_tls_security_level = may'
sudo postconf -e 'smtpd_tls_loglevel = 1'
sudo postconf -e 'smtp_tls_loglevel = 1'
```

在 `/etc/postfix/master.cf` 里开启 submission（587，STARTTLS）和 submissions（465，直接 TLS）：

```text
submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
submissions inet n      -       y       -       -       smtpd
  -o syslog_name=postfix/submissions
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
```

```bash
sudo postfix check && sudo systemctl reload postfix
```

## 第三步：配置 Dovecot

Dovecot 2.3 和 2.4 的证书配置项名称不同。Dovecot 2.3（Ubuntu 24.04、Debian 12）编辑 `/etc/dovecot/conf.d/10-ssl.conf`：

```text
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
ssl_min_protocol = TLSv1.2
```

Dovecot 2.4（例如 Debian 13）改了配置项名称，直接写路径：

```text
ssl = required
ssl_server_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_server_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
```

用 `dovecot --version` 确认版本，然后检查并重载：

```bash
sudo doveconf -n | grep -E '^ssl'
sudo systemctl reload dovecot
```

## 第四步：续期后重载两个服务

Postfix 和 Dovecot 不会自己读取续期后的证书，要靠 Certbot 的部署钩子重载：

```bash
sudo tee /etc/letsencrypt/renewal-hooks/deploy/mail.sh > /dev/null <<'EOF'
#!/bin/sh
case "$RENEWED_DOMAINS" in
  *mail.example.com*) systemctl reload postfix dovecot ;;
esac
EOF
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/mail.sh
```

发布了 DANE TLSA 记录的，用 `--reuse-key` 重新签发一次，以后续期就会保留同一把私钥：`sudo certbot certonly --standalone -d mail.example.com --reuse-key --force-renewal`。

## 验证

配置正确时，25、587、465、993 四个端口都返回 `mail.example.com` 的 Let's Encrypt 证书，OpenSSL 显示 `Verify return code: 0 (ok)`。从另一台机器逐个端口测试，SMTP 可以用 [STARTTLS 检查](https://ssl.sh/zh/tools/starttls-checker/)，也可以用 OpenSSL：

```bash
openssl s_client -connect mail.example.com:25 -starttls smtp -servername mail.example.com </dev/null | head -n 20
openssl s_client -connect mail.example.com:587 -starttls smtp -servername mail.example.com </dev/null | grep -E 'subject|issuer|Verify'
openssl s_client -connect mail.example.com:465 -servername mail.example.com </dev/null | grep -E 'subject|issuer|Verify'
openssl s_client -connect mail.example.com:993 -servername mail.example.com </dev/null | grep -E 'subject|issuer|Verify'
```

这台主机同时提供 HTTPS 的话，[SSL 证书检查](https://ssl.sh/zh/tools/ssl-checker/) 或 `curl ssl.sh/mail.example.com` 能看到同一张证书的证书链和到期时间。

## 自动续期

snap 版 Certbot 每天两次运行 `certbot renew`，4.1 及以上按 ARI 建议时间续期，之后部署钩子重载 Postfix 和 Dovecot。standalone 续期时 80 端口必须空闲；以后加了 Web 服务，就用 `sudo certbot reconfigure --cert-name mail.example.com --webroot -w /var/www/html` 改成 webroot。

```bash
sudo certbot renew --dry-run --run-deploy-hooks
```

邮件客户端不会缓存证书，Let's Encrypt 有效期缩短（2027 年 2 月 10 日起 64 天）不需要改配置。把 `mail.example.com` 加到 [ssl.sh 监控](https://ssl.sh/zh/monitor/)（开发中）。

## 常见问题排查

- **warning: cannot get RSA private key from file**：`smtpd_tls_chain_files` 顺序错了，先写私钥，再写证书链。
- **Dovecot 报 ssl_cert: Can't open file**：2.3 漏了 `<` 前缀，或在 2.4 上用了旧配置项名称，用 `doveconf -n` 查看实际生效的配置。
- **客户端提示证书链不受信任或不完整**：用了 `cert.pem`，改成 `fullchain.pem`，见 [缺少中间证书](https://ssl.sh/zh/errors/missing-intermediate-certificate/)。
- **邮件客户端提示证书域名不匹配**：客户端连接的域名（比如主域名）不在证书里，见 [NET::ERR_CERT_COMMON_NAME_INVALID](https://ssl.sh/zh/errors/net-err-cert-common-name-invalid/)。
- **对方服务器拒绝你的邮件服务器出示的客户端证书**：Let's Encrypt 证书已不含客户端认证 EKU，见 [客户端认证 EKU 被移除](https://ssl.sh/zh/errors/client-auth-eku-removed/)。
