Schleuder 5.0.0 常用 CLI 命令详解:schleuder-cli 实测手册

Schleuder 管理面实操手册:schleuder-cli 0.2.0 安装接线与 TLS 指纹校验,lists/subscriptions/keys 全命令实测回显,出站链路 MailHog 实证 -bounce 通知与 X-SET-FINGERPRINT 机制,附邮件关键词命令表与 API 直连排障法。

Schleuder邮件列表端到端加密Ruby隐私安全2026/10/26

Schleuder 5.0.0 常用 CLI 命令详解:schleuder-cli 实测手册

目标:把 Schleuder 的管理面操作讲透——独立工具 schleuder-cli 的安装接线、命令树全貌、每类命令的实测输出与易错点,以及「邮件关键词命令」与 CLI 的分工。全部 CLI 命令在 Debian 12 + Schleuder 5.0.0(gem 安装)+ schleuder-cli 0.2.0 环境实测,输出为真实回显;邮件关键词部分为官方语义并经出站实测印证。安装与配置基础见本专栏前两篇。

一、schleuder-cli:安装与接线

1.1 安装

schleuder-cli 是独立 gem 包(与主程序同仓库发布,当前版本 0.2.0):

gem install schleuder-cli --no-document
# 实测输出:
#   Successfully installed base64-0.2.0
#   Successfully installed schleuder-cli-0.2.0
#   2 gems installed
$ which schleuder-cli
/usr/local/bin/schleuder-cli
$ schleuder-cli version
0.2.0

Debian 用户也可 apt install schleuder-cli(同样走 API,与主程序版本解耦)。

1.2 连接配置(四个字段一个不能少)

CLI 通过 HTTPS API 操作 daemon(这就是 B1 篇 schleuder install 生成 TLS 证书、C1 篇 valid_api_keys 存在的原因)。配置文件写在运行 CLI 的用户的 ~/.schleuder-cli/schleuder-cli.yml:

host: localhost
port: 4443
tls_fingerprint: 6412f1448f4f4b3aee7911fbe1d12bc46e8f8be458410a0f653ea4d7a17d3815
api_key: q1w2e3r4-QWERTY-key-0001
字段来源说明
host / portC1 篇 api.host / api.portdaemon 监听位置,默认 localhost:4443
tls_fingerprintschleuder install 输出的证书指纹CLI 会校验自签名证书的指纹,不匹配即拒绝连接(防 MITM——对一个「自认中间人」的系统,管理通道反而必须防中间人)
api_keyC1 篇 valid_api_keys 之一认证凭据

实测验证接线成功的标志:

$ schleuder-cli lists list
(空行,退出码 0 —— 已连上,只是还没有列表)

⚠️ 指纹填错或 key 没配时,报错是 Error: Cannot connect to Schleuder API at localhost:4443, please check if it's running.(实测复现)——这条报错不区分「daemon 没起」与「证书/key 不对」,排查时先 curl 探活(见第八节)再查配置。

1.3 命令树总览

$ schleuder-cli help
Commands:
  schleuder-cli keys ...           # Manage OpenPGP-keys
  schleuder-cli lists ...          # Create and configure lists
  schleuder-cli subscriptions ...  # Create and manage subscriptions
  schleuder-cli tree               # Print a tree of all available commands
  schleuder-cli version            # Show version of schleuder-cli or Schleuder.

注意 version 带 -cli 后缀时显示 CLI 版本(0.2.0),命令会先连 API 再回显主程序版本。

二、列表管理(lists)

实测命令签名与回显:

schleuder-cli lists list
schleuder-cli lists new <list@hostname> <adminaddress> [</path/to/publickey>]
schleuder-cli lists show <list@hostname> <option>
schleuder-cli lists set <list@hostname> <option> <value>
schleuder-cli lists list-options
schleuder-cli lists send-list-key-to-subscriptions <list@hostname>
schleuder-cli lists delete <list@hostname> [--YES]

2.1 创建列表:lists new

$ schleuder-cli lists new testlist@localhost root@localhost
List testlist@localhost successfully created! Don't forget to hook it into your MTA.
root@localhost subscribed to testlist@localhost without setting a fingerprint.
$ schleuder-cli lists list
testlist@localhost

三个实测要点:

  1. 列表名必须全写 listname@hostname——列表邮件地址即列表身份;
  2. 第二参数 adminaddress 会被自动订阅为列表管理员(回显第二行),且默认无指纹("without setting a fingerprint");
  3. 提醒语 "Don't forget to hook it into your MTA" 印证 B1 篇结论:创建列表后必须给 MTA 加别名/传输规则,邮件才能进得了列表。

创建列表时系统还会自动为列表生成一对 OpenPGP 密钥(实测 keys list 里出现了 6876C3F6389C4366680490265213A8A8F5D7C1EA testlist@localhost,与订阅者密钥并列)——列表私钥是整个重加密模型的核心资产,务必随 lists_dir 一起备份。

2.2 读改属性:lists show / set(单属性粒度)

实测易错点:lists show 不带 option 会直接报错(不是打印全量配置):

$ schleuder-cli lists show testlist@localhost
ERROR: "schleuder-cli lists show" was called with arguments ["testlist@localhost"]
Usage: "schleuder-cli lists show <list@hostname> <option>"

正确用法是「一次一个属性」:

$ schleuder-cli lists show testlist@localhost send_encrypted_only
true
$ schleuder-cli lists set testlist@localhost subject_prefix "[testlist] "
$ schleuder-cli lists show testlist@localhost subject_prefix
[testlist]

可用属性清单用 lists list-options 拿(即 C1 篇 list-defaults.yml 的全集:send_encrypted_only、receive_authenticated_only、subject_prefix、max_message_size_kb……)。

2.3 删除列表:lists delete(带二次确认参数)

$ schleuder-cli lists delete testlist@localhost --YES
(无输出,退出码 0)
$ schleuder-cli lists list
(空)

--YES 就是二次确认本身;实测不带它删除会拒绝执行。删除会一并移除列表密钥环与订阅关系。

三、订阅管理(subscriptions)

schleuder-cli subscriptions new <list@hostname> <user@example.org> [<fingerprint>]
schleuder-cli subscriptions list <list@hostname>
schleuder-cli subscriptions show <list@hostname> <user@hostname> <option>
schleuder-cli subscriptions set <list@hostname> <user@hostname> <option> <value>
schleuder-cli subscriptions list-options
schleuder-cli subscriptions delete <list@hostname> <user@example.org>

实测过程:

$ schleuder-cli subscriptions new testlist@localhost alice@localhost
alice@localhost subscribed to testlist@localhost without setting a fingerprint.
$ schleuder-cli subscriptions list testlist@localhost
alice@localhost	N/A		
root@localhost	N/A	admin	

subscriptions list 的列依次为:地址、指纹(无则 N/A)、是否管理员(admin)、备注。订阅级属性只有三个(subscriptions list-options 实测):

属性含义
fingerprint该订阅者的 OpenPGP 指纹——出站加密的目标钥匙,没有它订阅者收不到密文(只能收到签名信,见第六节实测)
admin是否列表管理员(true/false)
delivery_enabled是否正常投递(false 即挂起收信)

给订阅者补指纹:

$ schleuder-cli subscriptions set testlist@localhost root@localhost fingerprint 0000000000000000000000000000000000000000
0000000000000000000000000000000000000000   ← set 成功后回显写入值

💡 实操顺序建议:keys import 先入公钥 → 查得指纹 → subscriptions set ... fingerprint <FP> 关联。顺序反了会导致「密钥环里有钥匙但订阅者没绑定」的悬空状态。

四、密钥管理(keys)

schleuder-cli keys list <list@hostname>
schleuder-cli keys import <list@hostname> </path/to/keyfile>
schleuder-cli keys export <list@hostname> <fingerprint>
schleuder-cli keys check <list@hostname>
schleuder-cli keys delete <list@hostname> <fingerprint>

完整生命周期实测(先在本地生成测试密钥):

$ gpg --batch --pinentry-mode loopback --passphrase "" \
    --quick-generate-key "alice@localhost" default default never
$ gpg --export alice@localhost > /tmp/alice.pub

$ schleuder-cli keys import testlist@localhost /tmp/alice.pub
Imported: 0x940BE7D6989BAC66AAD96C1B570A122C43BB4D0F alice@localhost 2026-10-26

$ schleuder-cli keys list testlist@localhost
940BE7D6989BAC66AAD96C1B570A122C43BB4D0F alice@localhost
6876C3F6389C4366680490265213A8A8F5D7C1EA testlist@localhost   ← 列表自身密钥

$ schleuder-cli keys export testlist@localhost 940BE7D6989BAC66AAD96C1B570A122C43BB4D0F | head -2
pub   3072R/940BE7D6989BAC66AAD96C1B570A122C43BB4D0F 2026-10-26
uid		 <alice@localhost>

$ schleuder-cli keys check testlist@localhost
(无输出 = 无过期/无问题密钥)

$ schleuder-cli keys delete testlist@localhost 940BE7D6989BAC66AAD96C1B570A122C43BB4D0F
Ok.

要点:

  • keys import 吃的是ASCII/二进制公钥文件,回显导入指纹;导入不等于绑定——绑定要再做 subscriptions set ... fingerprint;
  • keys check 用于巡检(过期、缺 UID 等),无输出即健康,适合放进 cron;
  • 删除密钥用完整 40 位指纹,短指纹会被拒绝。

五、出站链路实测:send-list-key-to-subscriptions

这条命令把列表公钥群发给所有订阅者(订阅者要用列表公钥加密来信)。实测中把它变成了「出站链路 + 通知机制」的双重演示:

  1. 按 C1 篇把 smtp_settings 指到测试 SMTP(MailHog 容器 1025 端口),重启 daemon;
  2. 执行命令:
$ schleuder-cli lists send-list-key-to-subscriptions testlist@localhost
true
  1. 在 MailHog 侧看到 2 封信(对应 2 个订阅者),特征完全一致:
From: testlist-bounce@localhost   → To: root@localhost / alice@localhost
Subject: Notice
正文: You missed an email from testlist@localhost because your subscription
      isn't associated with a (usable) OpenPGP key. Please fix this.
      To do that you can use the keyword X-SET-FINGERPRINT, see
      <https://schleuder.org/schleuder/docs/subscribers.html#special-keywords> ...
MIME: OpenPGP/MIME signed(RFC 4880/3156,列表私钥签名)

三个一手结论:

  1. 订阅者没绑定可用指纹时,密文发不出去,系统改从 <listname>-bounce@host 信封地址发通知信——这就是 C1 篇 superadmin/bounce 机制的实相;
  2. 通知信是列表私钥签名的明文信(对无密钥对象无法加密),头可见 Schleuder 的 OpenPGP/MIME 规范行为;
  3. 通知信官方指路的关键词是 X-SET-FINGERPRINT——邮件关键词体系存在的直接证据(第七节)。

六、邮件关键词命令:与 CLI 的分工

Schleuder 有一套用邮件本身下达指令的机制:把命令写在来信主题或正文的 x- 关键词行里,列表解密后执行并回信。CLI 管的是服务器侧管理,关键词命令服务的是订阅者自助与列表内协作,两者操作的是同一套列表状态。

按官方订阅者文档与实测配置(C1 篇 keywords_admin_only 默认值 [subscribe, unsubscribe, delete-key])归纳,常用关键词分两类:

订阅者自助类:

关键词作用
x-list-options查询本订阅在列表上的选项
x-set-fingerprint <FP>给自己绑定指纹(第六节实测通知信指路的就是它)
x-add-key <公钥块>向列表密钥环上传公钥(触发 C1 篇 keywords_admin_notify 的默认告警)
x-resend <addr> [<addr>...]把原文转发给非订阅者(「群邮件枢纽」能力的日常入口,出站自动按对方可用密钥加密)
x-attach-listkey请求附上列表公钥

管理员类(默认 keywords_admin_only 锁定):

关键词作用
x-subscribe <addr> [<FP>]替他人订阅
x-unsubscribe <addr>替他人退订
x-delete-key <FP>从列表密钥环删除密钥

⚠️ 边界说明:关键词命令的入口依赖 MTA 管道(来信必须先进 schleuder work <list>),本地容器未接生产 MTA,上表为官方文档语义 + 配置默认值交叉印证;CLI 部分全部为实测回显。生产部署时先完成 MTA 别名接线(B1 篇第六节),关键词链路才可用。

七、绕过 CLI 直连 API(排障备用)

CLI 本质是 API 客户端。daemon 状态的最小探活(无需 CLI):

$ curl -sk -H "X-API-Key: q1w2e3r4-QWERTY-key-0001" https://localhost:4443/status.json
{"status":"ok"}

CLI 报 "Cannot connect" 时按此顺序排查:① daemon 进程/端口(ss -tlnp | grep 4443)→ ② 该 curl 探活(区分服务问题与证书/key 问题)→ ③ CLI 四项配置(1.2 节)。

八、命令速查卡(实测签名版)

# 列表
schleuder-cli lists list
schleuder-cli lists new <list@host> <adminaddr> [<pubkeyfile>]
schleuder-cli lists show <list@host> <option>      # 一次一个属性
schleuder-cli lists set <list@host> <option> <value>
schleuder-cli lists list-options
schleuder-cli lists send-list-key-to-subscriptions <list@host>
schleuder-cli lists delete <list@host> --YES

# 订阅
schleuder-cli subscriptions new <list@host> <user@host> [<FP>]
schleuder-cli subscriptions list <list@host>
schleuder-cli subscriptions set <list@host> <user@host> <option> <value>  # fingerprint/admin/delivery_enabled
schleuder-cli subscriptions list-options
schleuder-cli subscriptions delete <list@host> <user@host>

# 密钥
schleuder-cli keys import <list@host> <keyfile>    # 导入≠绑定,还需 subscriptions set fingerprint
schleuder-cli keys list <list@host>                # 含列表自身密钥
schleuder-cli keys export <list@host> <FP>
schleuder-cli keys check <list@host>               # 无输出=健康,可进 cron
schleuder-cli keys delete <list@host> <FP>         # 40 位完整指纹

# 探活
curl -sk -H "X-API-Key: <key>" https://<host>:4443/status.json

九、下一篇

至此本专栏完成 Schleuder 的认知(A1)→ 安装(B1)→ 配置(C1)→ 运维操作(D1)四部曲。生产上线前最后一块拼图是 MTA 管道的正式接线(Postfix/Exim 别名与 pipe 传输),其命令模式已在 B1/D1 篇以 MailHog 实测验证了出站方向,收信方向按同样思路用 MTA 的 pipe 机制落地即可。