Stalwart 日常运维手册
Stalwart v0.16.26 日常运维实操手册:日志体系、邮件队列管理、DKIM 轮换与 DNS 维护、备份恢复、版本升级演练与排障实录,全部命令实测通过
Stalwart 日常运维手册
目标:面向已完成部署的 Stalwart v0.16.26 管理员,提供一套可落地的日常运维操作手册——日志体系与查看方法、邮件队列管理、DKIM 密钥与 DNS 维护、数据备份与恢复、版本升级演练与日常巡检清单。所有操作与回显均在 Ubuntu 22.04 + Stalwart v0.16.26 实测通过,遇到故障可直接对照第五章的排障实录处理。
一、环境信息
- 操作系统:Ubuntu 22.04,Stalwart v0.16.26,systemd 托管(服务名
stalwart) - 目录布局:二进制
/usr/local/bin/stalwart、配置/etc/stalwart/、数据/var/lib/stalwart/、日志/var/log/stalwart/ - 管理面:WebAdmin
http://<服务器>:8080,JMAP 管理 APIhttp://127.0.0.1:8080/jmap,CLIstalwart-cli(1.0.13) - 管理员凭据:
admin@lab.example.com/q1w2e3r4(CLI 通过环境变量注入,见 3.1) - 测试域
lab.example.com、测试账号demo@lab.example.com(密码同)
二、日志体系与日常查看
2.1 日志的双通道布局
v0.16 的日志走两条通道,各有用途:
ls -la /var/log/stalwart/
实测输出:
total 124
drwxr-x--- 2 stalwart stalwart 4096 Oct 18 08:57 .
drwxr-xr-x 1 root root 4096 Oct 18 08:49 ..
-rw-r--r-- 1 stalwart stalwart 109236 Oct 18 09:35 stalwart.2026-10-18
- 文件通道:
/var/log/stalwart/stalwart.<日期>按天一个文件,结构化键值格式,是排障主力; - journald 通道:进程 stdout 经
SyslogIdentifier=stalwart进 journald,journalctl -u stalwart查看,适合跟踪启动与服务级事件。
日志行的统一格式为 <ISO8601时间> <级别> <事件标识> <键值对...>,实测样例(队列投递事件):
2026-10-18T09:33:16Z INFO Delivery attempt ended (delivery.attempt-end) queueId = 335619801751750656, queueName = "remote", from = "demo@lab.example.com", to = ["test@gmail.com"], size = 221, total = 1, elapsed = 3756ms
解读要点:括号内的事件标识(如 delivery.attempt-end)是 grep 的最佳锚点;queueId 可与队列管理(三章)联动追踪单笔邮件。
2.2 高频查看命令速查
# 实时跟踪日志(文件通道)
tail -f /var/log/stalwart/stalwart.$(date +%F)
# 按事件标识过滤(投递、认证、DKIM)
grep "delivery" /var/log/stalwart/stalwart.2026-10-18 | tail -20
grep -E "auth|535" /var/log/stalwart/stalwart.2026-10-18 | tail -10
# 启动/服务级事件(journald 通道)
journalctl -u stalwart --since today --no-pager | head -30
第三条实测输出(启动段节选,可看到监听器逐个起启):
localhost systemd[1]: Started Stalwart.
localhost stalwart[3017]: Started listener smtp ([::]:25)
localhost stalwart[3017]: Started listener submissions ([::]:465)
localhost stalwart[3017]: Started listener submission ([::]:587)
localhost stalwart[3017]: Started listener imaps ([::]:993)
...
2.3 邮件身份校验日志解读
每封入站邮件的身份校验结果都会留痕,排"为什么被判垃圾/被拒收"时先看这三类事件:
grep -E "spf|dkim" /var/log/stalwart/stalwart.2026-10-18 | head -5
实测输出(测试环境无公网 DNS,故 SPF/DKIM 校验为 none/fail 属预期):
2026-10-18T09:03:53Z INFO SPF EHLO check failed (smtp.spf-ehlo-fail) listenerId = "smtp", localPort = 25, remoteIp = 127.0.0.1, ..., domain = "mail.lab.example.com", result = No SPF record (spf.none), elapsed = 472ms
2026-10-18T09:03:54Z INFO SPF From check failed (smtp.spf-from-fail) ... result = No SPF record (spf.none), ...
2026-10-18T09:03:54Z INFO DKIM verification failed (smtp.dkim-fail) listenerId = "smtp", localPort = 25, remoteIp = 127.0.0.1, strict = false, result = [], elapsed = 0ms
解读:spf.none 表示查询域没有发布 SPF 记录(不是校验出错);smtp.dkim-fail 中 strict = false 表示非严格模式、result = [] 表示信上无可验签名。公网生产环境 DNS 配好后,正常邮件这里会是 spf.pass / dkim.pass 类结果。
2.4 WebAdmin 的日志与遥测
WebAdmin 左侧 Logs/Telemetry 面板对同一份遥测数据做了可视化(按时间过滤、按事件类型筛选、查看单封邮件完整轨迹),日常巡检可直接用网页替代命令行;数据同源,结论一致。
三、邮件队列管理
3.1 CLI 连接准备
所有队列操作用官方 stalwart-cli(1.0.13 实测),先注入连接环境变量:
export STALWART_URL=http://127.0.0.1:8080 \
STALWART_USER=admin@lab.example.com \
STALWART_PASSWORD=q1w2e3r4
(可写入 /root/.bashrc 或独立的运维脚本文件;密码文件注意 chmod 600。)
3.2 查看队列与消息详情
stalwart-cli query QueuedMessage
实测输出(一封发往外部域、正在重试的邮件):
Id Sender Next Retry Received Size
jkc2qxlsadqa demo@lab.example.com 2026-10-18T09:34:00Z 2026-10-18T09:34:00Z 236
stalwart-cli get QueuedMessage jkc2qxlsadqa
实测输出(完整结构):
Sender
Sender: demo@lab.example.com
Recipients:
Key Next Retry Retry Count Next Notification Notify Count Queue Flags Original Recipient
retrytest@gmail.com 2026-10-18T09:34:00Z 0 2026-10-19T09:34:00Z 0 remote <none> <none>
Size: 236
Delivery
Next Retry: 2026-10-18T09:34:00Z
Next Notification: 2026-10-19T09:34:00Z
Details
Priority: 0
Envelope ID: <none>
Flags: Message was received from an authenticated session
Origin
Received From IP: 127.0.0.1
字段解读:Retry Count 已重试次数;Next Notification 下次向发件人发延迟告警(DSN)的时间;Queue = remote 远程投递队列(本地投递为 local);Priority 数值越大越优先投递。
3.3 队列消息的改期/优先级/清除
实测三个管理动作(消息 ID 同上):
# 延后重试时间(人工窗口避让)
stalwart-cli update QueuedMessage jkc2qxlsadqa --json '{"nextRetry":"2026-10-18T11:30:00Z"}'
实测输出:
Updated QueuedMessage jkc2qxlsadqa
# 提升优先级
stalwart-cli update QueuedMessage jkc2qxlsadqa --json '{"priority":1}'
实测输出:
Updated QueuedMessage jkc2qxlsadqa
# 清除(放弃投递)
stalwart-cli delete QueuedMessage --ids jkc2qxlsadqa
实测输出:
jkc2qxlsadqa deleted
1 deleted, 0 failed
清除后 query QueuedMessage 确认队列已空(实测无输出即空队列)。批量清除用逗号拼接:--ids id1,id2,id3。
3.4 队列事件与 DSN 机制
队列的自动行为在日志里全量留痕,两个最典型场景(实测日志):
场景一,收件域不存在(DNS 无 MX),立即永久失败并自动生成退信(DSN):
2026-10-18T09:32:41Z INFO MX record lookup failed (delivery.mx-lookup-failed) queueId = ..., domain = "slowmx.test", details = "No MX records were found, attempting implicit MX.", ...
2026-10-18T09:32:41Z INFO DSN permanent failure notification (delivery.dsn-perm-fail) ... to = ["test@slowmx.test"], details = "DNS lookup failed: no MX record found.", ...
2026-10-18T09:32:41Z INFO Queued DSN for delivery (queue.dsn-queued) ... from = "<>", to = ["demo@lab.example.com"], ...
场景二,对端返回 5xx 拒收(收件人不存在),同样永久失败 + DSN:
2026-10-18T09:33:16Z INFO DSN permanent failure notification (delivery.dsn-perm-fail) ... details = "Unexpected response for RCPT TO:<test@gmail.com>: Code: 550, ... The email account that you tried to reach does not exist. ..."
运维要点:永久失败(5xx/DNS 无记录)不占队列、自动退信;临时失败(超时/4xx)留在队列按退避策略自动重试,只有"确认不再投"或"等不及人工放行"时才需要 3.3 节的人工干预。
四、DKIM 密钥与 DNS 维护
4.1 现状确认
v0.16 在域名上启用 Automatic DKIM 管理后,签名密钥全自动轮换(《Stalwart v0.16.26 配置参数详解》 4.4/4.5 节有对象级解读):实测域名 lab.example.com 的轮换参数为 90 天轮换(rotateAfter)、7 天退役(retireAfter)、30 天后删除(deleteAfter),选择器模板 v{version}-{algorithm}-{date-%Y%m%d},当前活跃签名 v1-rsa-20261018 与 v1-ed25519-20261018(stage = active)。密钥生成时日志有留痕:
2026-10-18T08:57:49Z INFO DKIM signature created (dkim.signature-created) id = "v1-ed25519-20261018", details = "lab.example.com"
2026-10-18T08:57:49Z INFO DKIM signature created (dkim.signature-created) id = "v1-rsa-20261018", details = "lab.example.com"
4.2 DNS 记录维护流程
轮换产生新选择器后,必须把新公钥的 TXT 记录发布到 DNS,否则新签名无法被对端验证。日常维护节奏:
- 加新域后:从域名对象导出
dnsZoneFile(MX/SPF/DKIM/DMARC/MTA-STS 全套),整体发布到 DNS(导出命令与完整实测输出见 《Ubuntu 22.04 安装 Stalwart v0.16.26 指南》 4.4 节); - 日常巡检:对比当前
stage = active签名的 selector 与 DNS 已发布记录是否一致(dig TXT v1-rsa-20261018._domainkey.lab.example.com); - 轮换窗口:新签名创建后先发布 DNS,再等旧选择器过了
retireAfter自然退役——顺序不能反,否则对端验签失败。
注意 DNS 记录的生效依赖域名 DNS 配置权限,本手册不伪造验证结果;测试/内网环境可按 2.3 节日志判断校验行为。
五、数据备份与恢复
5.1 备份什么
Stalwart 的全部状态(账号、配置对象、邮件、队列、遥测)都在数据存储里,因此备份的核心是数据存储;再辅以两份配置文件即可完整复原一个实例:
| 备份对象 | 路径 | 方式 |
|---|---|---|
| 数据存储全量 | RocksDB /var/lib/stalwart/ | stalwart --export(官方逻辑导出,推荐) |
| 引导配置 | /etc/stalwart/config.json | 文件复制 |
| 环境变量 | /etc/stalwart/stalwart.env | 文件复制 |
5.2 导出实测(--export)
导出需停服保证一致性(小流量窗口内操作):
systemctl stop stalwart
mkdir -p /var/backups/stalwart
/usr/local/bin/stalwart --config=/etc/stalwart/config.json --export /var/backups/stalwart/snapshot-20261018
实测输出(逐个子空间导出):
Exporting database to /var/backups/stalwart/snapshot-20261018/subspace_p.
Exporting database to /var/backups/stalwart/snapshot-20261018/subspace_s.
Exporting database to /var/backups/stalwart/snapshot-20261018/subspace_b.
Exporting database to /var/backups/stalwart/snapshot-20261018/subspace_g.
Exporting database to /var/backups/stalwart/snapshot-20261018/subspace_d.
Exporting database to /var/backups/stalwart/snapshot-20261018/subspace_o.
Exporting database to /var/backups/stalwart/snapshot-20261018/subspace_l.
Exporting database to /var/backups/stalwart/snapshot-20261018/subspace_e.
Exporting database to /var/backups/stalwart/snapshot-20261018/subspace_x.
Exporting database to /var/backups/stalwart/snapshot-20261018/subspace_q.
产物与体量:
ls -la /var/backups/stalwart/snapshot-20261018/ | head -6
du -sh /var/backups/stalwart/snapshot-20261018
实测输出:
-rw-r--r-- 1 root root 21 Oct 18 09:34 subspace_a
-rw-r--r-- 1 root root 26723 Oct 18 09:34 subspace_b
-rw-r--r-- 1 root root 1747 Oct 18 09:34 subspace_d
...
808K /var/backups/stalwart/snapshot-20261018
(subspace_* 按存储内名字空间拆分:目录、配置、邮件、Blob、队列等各有归属;测试环境体量小,生产环境随邮件量增长。)完成后恢复服务:
systemctl start stalwart && sleep 8 && systemctl is-active stalwart
实测输出:
active
5.3 恢复(--import)与日常备份建议
恢复是导出的逆过程:在空数据目录的目标实例上执行 stalwart --config=/etc/stalwart/config.json --import /path/to/snapshot-xxx(帮助信息实测:-i, --import <PATH> Import store data from a specific path),导入完成再启动服务。
日常备份建议(结合 5.1 的三件套):
- 每周全量
--export+ 每日/var/lib/stalwart文件级快照(停服窗口或接受 RocksDB 快照的轻微不一致); - 备份产物异地存放(对象存储/另一台机器),本地保留 2~4 份轮换;
- 每季度做一次恢复演练:在隔离环境用备份 + 两份配置文件拉起实例,验证能登录 WebAdmin、能查收历史邮件。没演练过的备份等于没备份。
六、版本升级
v0.16 的升级就是"换二进制 + 重启",数据存储格式由服务自行兼容迁移。以下流程在实测环境完整演练(重装同版本,生产换新版本号即可):
# 1) 备份(升级前必做,见五章)
systemctl stop stalwart
/usr/local/bin/stalwart --config=/etc/stalwart/config.json --export /var/backups/stalwart/pre-upgrade-$(date +%F)
# 2) 下载新版本并校验(以 v0.16.26 为例)
cd /tmp
curl -fsSL -O "https://github.com/stalwartlabs/stalwart/releases/download/v0.16.26/stalwart-x86_64-unknown-linux-gnu.tar.gz"
curl -fsSL -O "https://github.com/stalwartlabs/stalwart/releases/download/v0.16.26/stalwart-x86_64-unknown-linux-gnu.tar.gz.sha256"
sha256sum -c stalwart-x86_64-unknown-linux-gnu.tar.gz.sha256
实测输出:
stalwart-x86_64-unknown-linux-gnu.tar.gz: OK
# 3) 替换二进制并启动
tar zxf stalwart-x86_64-unknown-linux-gnu.tar.gz
install -m 0755 stalwart /usr/local/bin/stalwart
systemctl start stalwart && sleep 8
# 4) 验证
systemctl is-active stalwart && stalwart --version
实测输出:
active
0.16.26
再补两个冒烟检查:ss -ltn 确认监听端口齐、WebAdmin 能登录。回滚预案:保留上一版本二进制副本(cp /usr/local/bin/stalwart /usr/local/bin/stalwart.v0.16.25.bak),新版本异常时停服换回旧二进制启动即可;跨大版本升级(如 v0.13 → v0.16)涉及配置模型迁移,必须先读官方 UPGRADING 文档并在隔离环境演练。
七、日常巡检清单
给一条可 cron 化的巡检命令序列(每项都有"健康标准"):
# 1. 服务活性:期望 active
systemctl is-active stalwart
# 2. 端口齐备:期望列出 25/465/587/143/993/995/4190/443/8080
ss -ltn | grep -E ':(25|465|587|143|993|995|4190|443|8080)\b'
# 3. 队列积压:正常应接近空(远端重试除外)
export STALWART_URL=http://127.0.0.1:8080 STALWART_USER=admin@lab.example.com STALWART_PASSWORD=q1w2e3r4
stalwart-cli query QueuedMessage
# 4. 错误日志扫描:期望无 ERROR/WARN 突增
grep -cE " ERROR | WARN " /var/log/stalwart/stalwart.$(date +%F)
# 5. 磁盘水位:数据目录与日志目录
df -h /var/lib/stalwart /var/log/stalwart | tail -2
# 6. 冒烟收发(内网闭环)
swaks --to demo@lab.example.com --from test@lab.example.com \
--server 127.0.0.1:25 --helo mail.lab.example.com \
--header "Subject: daily probe $(date +%T)" --body "probe" 2>&1 | grep -c "250"
任一项不满足健康标准,按第五章开始定位。
八、常见问题(排障实录)
以下问题均在本次实测中真实出现,按"现象 → 定位 → 处理"整理。
8.1 端口被占用,服务起不来或监听缺失
现象:ss -ltn 缺端口,或启动日志报 Address already in use。
定位与处理:
ss -ltnp | grep -E ':(25|587|143|8080)\b'
输出会显示占用进程(常见:遗留 postfix/exim4、其他服务占用)。停用冲突服务(systemctl disable --now postfix 等);脚本安装的 unit 自带 Conflicts=postfix.service sendmail.service exim4.service 会自动处理 systemd 服务,其他平台级端口映射需自行调整。
8.2 认证失败(535)
现象:Submission 587 认证被拒。实测回显(错误密码场景):
<~* 535 5.7.8 Authentication credentials invalid.
*** No authentication type succeeded
定位顺序:① 凭据本身输错/密码已轮换(用管理 API 核对账号凭据再试);② 未 STARTTLS(587 明文直连服务器不提供 AUTH 机制,swaks 加 -tls);③ 账号被停用。日志侧 grep "auth" /var/log/stalwart/stalwart.$(date +%F) 可看到每次失败尝试。
8.3 DKIM/SPF 校验失败
现象:日志出现 smtp.spf-ehlo-fail / smtp.spf-from-fail(result = No SPF record (spf.none))或 smtp.dkim-fail(实测样例见 2.3 节)。
定位思路:这类事件多数是 DNS 配置问题而非程序故障——发件域没发布 SPF、DKIM 选择器记录缺失/未同步(对照四章 4.2 的轮换流程)、或查询域根本无 MX。内网/测试环境没有公网 DNS 时 spf.none/dkim-fail 属预期,不影响本地投递;公网生产按 DNS 侧逐项补齐即可。
8.4 外域投递失败与退信(DNS/对端拒收)
现象:发往外域的邮件消失或收到退信。实测两类根因日志(见 3.4 节):
delivery.mx-lookup-failed+delivery.dsn-perm-fail:收件域 DNS 无 MX,永久失败,系统自动向发件人投递退信(DSN);- 对端 550 拒收(收件人不存在)同样走 DSN。
处理:核对收件地址拼写与目标域 DNS;确认本机可解析公网(getent hosts gmail-smtp-in.l.google.com)。注意 v0.16 使用自身 DNS 解析逻辑,/etc/hosts 的域名映射对出站投递不生效(实测黑洞域名走 hosts 未被命中,仍按 DNS 查询)。
8.5 RocksDB 锁冲突(LOCK 文件)
现象:启动报错(实测回显):
⚠️ Startup failed: Failed to open database: Error { message: "IO error: While lock file: /var/lib/stalwart//LOCK: Resource temporarily unavailable" }
原因:已有 stalwart 进程持有数据目录锁(多进程误启、旧进程未退干净)。处理:ps aux | grep [s]talwart 找到全部进程,只保留一个实例(杀干净旧进程或重启服务器)后再启动。日常避免手工重复拉起进程,统一走 systemd。
8.6 WebAdmin 资源加载失败
现象:/admin 页面空白,日志出现 Failed to fetch webui bundle 类告警。
原因:WebAdmin 前端资源包需从外部拉取,无外网/直连 GitHub 受限时失败。处理:在 /etc/stalwart/stalwart.env 配置 https_proxy/http_proxy 后重启服务(实测配置代理后资源下载成功、页面正常)。
8.7 升级后数据不一致/服务异常
现象:换二进制后起不来或行为异常。
处理:先看 journalctl -u stalwart -n 50 定位报错;多数情况用五章备份回退——停服、清空数据目录、--import 升级前快照、换回旧版二进制、启动。跨大版本必须先在隔离环境演练迁移。
九、参考链接
- Stalwart 官方文档(管理/运维章节):https://docs.stalw.art
- 队列与投递管理:https://docs.stalw.art/management/queue
- 备份与恢复:https://docs.stalw.art/management/backup
- DKIM 管理:https://docs.stalw.art/management/dkim
- stalwart-cli 使用:https://github.com/stalwartlabs/cli
- 版本升级说明(UPGRADING):https://github.com/stalwartlabs/stalwart/tree/main/UPGRADING
- swaks(SMTP 测试工具):http://www.jetmore.org/john/code/swaks/