SMTP 子系统(config + mail 包 + Secret + TUI 的 e 配置屏)是 2026-07-20 加进来的,felis-api 从环境变量 FELIS_SMTP_PASSWORD 取密码。全新安装没问题 —— 渲染 Deployment 时会带上这个 env var。已经部署的安装取不到它:Deployment 是在这个 env var 存在之前渲染的。
e
felis-api
FELIS_SMTP_PASSWORD
结果是邮件功能在老安装上静默失效。owner 解锁流程(SMTP → passkey → 验证邮箱)走不通,op.console 的登录会 404。
kubectl rollout restart 修不了这个 —— 它重建 Pod,但 Pod 是照着 Deployment spec 建的,spec 里没有的 env var 重启多少次也不会长出来。felis setup 也修不了:它在已部署的主机上会跳过 bootstrap(setup.go:69-74 的 hostBootstrapReady 门控),所以够不到控制面 bundle。
kubectl rollout restart
felis setup
setup.go:69-74
hostBootstrapReady
在受影响的主机上重跑装机器:
sudo bash deploy/bootstrap.sh
它是幂等的,会重渲染并 apply 整个控制面 bundle(:1982-1987),Deployment 更新后 FELIS_SMTP_PASSWORD 就在了。三个 flag 全部来自脚本内的变量,操作者不需要记住装机时用了什么参数。
:1982-1987
密码本身仍要由 felis-smtp Secret 提供 —— env var 是 Optional: true 的 secretKeyRef,Secret 不在时 Pod 照样起,只是取不到值。
felis-smtp
Optional: true
Identified by Claude Opus 5 (claude-opus-5) while auditing the SMTP subsystem's deployment path on 2026-07-28.
internal/platform/workloads.go:241-253 —— 这个 env var 是无条件 append 的,和两个 S3 变量并排,没有任何配置判断:
internal/platform/workloads.go:241-253
env = append(env, corev1.EnvVar{Name: UploadsS3AccessKeyEnv, ...}, corev1.EnvVar{Name: UploadsS3SecretKeyEnv, ...}, // The [smtp] relay password, same optional-Secret pattern: absent until the // setup wizard's "configure email" step creates felis-smtp. corev1.EnvVar{Name: SMTPPasswordEnv, ValueFrom: &corev1.EnvVarSource{SecretKeyRef: ...}}, )
所以任何一次重渲染必定带上它,与配置里有没有 [smtp] 段无关。
[smtp]
重跑不会冲掉 TUI 写的 [smtp] 配置 —— write_felis_toml() 第一件事就是把它抠出来带走:
write_felis_toml()
write_felis_toml() { local target="$1" db_host="$2" smtp_block smtp_block="$(persisted_smtp_block)" if [ -n "$smtp_block" ]; then log "carrying forward the configured [smtp] relay"
persisted_smtp_block() 依次读 ${STATE_DIR}/felis.host.toml 和 felis.pod.toml,awk 从 [smtp] 打到下一个 section header 为止。
persisted_smtp_block()
${STATE_DIR}/felis.host.toml
felis.pod.toml
2026-07-28 更正:这条原本写成 issue #1 的症状之一,那是归错了。FELIS_SMTP_PASSWORD 住在 felis-api 的 Deployment 上,不在 MinecraftServer CR 上,refreshDerivedEnv 的 create-if-absent 限制够不到它。收敛路径一直存在,只是没人把它写下来。
refreshDerivedEnv
kubectl get deployment felis-api -o jsonpath='{.spec.template.spec.containers[0].env[*].name}' 能看到 FELIS_SMTP_PASSWORD,且发一封测试邮件能到达。
kubectl get deployment felis-api -o jsonpath='{.spec.template.spec.containers[0].env[*].name}'
需要在集群主机上执行,我这边的工具链拿不到写权限,所以挂 help wanted。
help wanted
发信路径有一个已经踩过的坑,值得在验证时留意:Fastmail 在 DATA 结束时才拒绝发件人身份。MAIL FROM 阶段它回 250,一直到 w.Close() 才报错。所以任何在 DATA 之前就停下的预检(连上了、EHLO 通了、认证过了)都会给出假绿灯。要验证就得真发一封出去。
MAIL FROM
w.Close()
注记(老装机一次性操作,非代码缺陷——保持打开做待办跟踪): FELIS_SMTP_PASSWORD 住在 felis-api Deployment 上,重跑 deploy/bootstrap.sh 会重渲染 Deployment 的 env(并把 felis-smtp Secret 复制到需要它的命名空间),即自动收敛。已在运行、暂不重跑安装器的机器,走 panel 的 configure email 流程同样会刷新环境(#29 修复后该路径不再被 namespace 冲突吞掉)。
deploy/bootstrap.sh
收敛路径已落到文档,VM 上实测过。
7c2fa08
docs/operations.md
felis converge
felis converge -user-rcon
bootstrap.sh
kubectl -n felis get deploy felis-api -o jsonpath='{...env[*].name}'
验收的后半句(真发一封信到达)这次没做:VM 上没有配置 SMTP relay,也不往真实地址发信。env var 这一半已满足,发信验证留给配好 relay 的主机按文档最后一段执行。
No dependencies set.
The note is not visible to the blocked user.
问题
SMTP 子系统(config + mail 包 + Secret + TUI 的
e配置屏)是 2026-07-20 加进来的,felis-api从环境变量FELIS_SMTP_PASSWORD取密码。全新安装没问题 —— 渲染 Deployment 时会带上这个 env var。已经部署的安装取不到它:Deployment 是在这个 env var 存在之前渲染的。结果是邮件功能在老安装上静默失效。owner 解锁流程(SMTP → passkey → 验证邮箱)走不通,op.console 的登录会 404。
kubectl rollout restart修不了这个 —— 它重建 Pod,但 Pod 是照着 Deployment spec 建的,spec 里没有的 env var 重启多少次也不会长出来。felis setup也修不了:它在已部署的主机上会跳过 bootstrap(setup.go:69-74的hostBootstrapReady门控),所以够不到控制面 bundle。收敛命令
在受影响的主机上重跑装机器:
它是幂等的,会重渲染并 apply 整个控制面 bundle(
:1982-1987),Deployment 更新后FELIS_SMTP_PASSWORD就在了。三个 flag 全部来自脚本内的变量,操作者不需要记住装机时用了什么参数。密码本身仍要由
felis-smtpSecret 提供 —— env var 是Optional: true的 secretKeyRef,Secret 不在时 Pod 照样起,只是取不到值。证据
Identified by Claude Opus 5 (claude-opus-5) while auditing the SMTP subsystem's deployment path on 2026-07-28.
internal/platform/workloads.go:241-253—— 这个 env var 是无条件 append 的,和两个 S3 变量并排,没有任何配置判断:所以任何一次重渲染必定带上它,与配置里有没有
[smtp]段无关。重跑不会冲掉 TUI 写的
[smtp]配置 ——write_felis_toml()第一件事就是把它抠出来带走:persisted_smtp_block()依次读${STATE_DIR}/felis.host.toml和felis.pod.toml,awk 从[smtp]打到下一个 section header 为止。验收
kubectl get deployment felis-api -o jsonpath='{.spec.template.spec.containers[0].env[*].name}'能看到FELIS_SMTP_PASSWORD,且发一封测试邮件能到达。备注
需要在集群主机上执行,我这边的工具链拿不到写权限,所以挂
help wanted。发信路径有一个已经踩过的坑,值得在验证时留意:Fastmail 在 DATA 结束时才拒绝发件人身份。
MAIL FROM阶段它回 250,一直到w.Close()才报错。所以任何在 DATA 之前就停下的预检(连上了、EHLO 通了、认证过了)都会给出假绿灯。要验证就得真发一封出去。注记(老装机一次性操作,非代码缺陷——保持打开做待办跟踪):
FELIS_SMTP_PASSWORD住在 felis-api Deployment 上,重跑deploy/bootstrap.sh会重渲染 Deployment 的 env(并把 felis-smtp Secret 复制到需要它的命名空间),即自动收敛。已在运行、暂不重跑安装器的机器,走 panel 的 configure email 流程同样会刷新环境(#29 修复后该路径不再被 namespace 冲突吞掉)。收敛路径已落到文档,VM 上实测过。
7c2fa08docs/operations.md新增 "Bringing an older install up to date":重跑装机器 →felis converge→felis converge -user-rcon,并给出三条核对命令。FELIS_SMTP_PASSWORD删掉模拟老安装,重跑bootstrap.sh之后kubectl -n felis get deploy felis-api -o jsonpath='{...env[*].name}'重新列出FELIS_SMTP_PASSWORD;[smtp]段由write_felis_toml()带过去。验收的后半句(真发一封信到达)这次没做:VM 上没有配置 SMTP relay,也不往真实地址发信。env var 这一半已满足,发信验证留给配好 relay 的主机按文档最后一段执行。