Snikket stable.20260611.1 常用运维命令与排障详解
Snikket 实例运维手册:版本/状态查证、升级回滚、用户与邀请管理、证书链路维护、prosodyctl check 自检全解、数据备份与 5 个排障实录,基于 stable.20260611.1 实测。
Snikket stable.20260611.1 常用运维命令与排障详解
目标:给已上线的 Snikket 实例一份可照抄的运维手册——版本与状态查证、升级回滚、用户与邀请管理、证书链路维护、日志诊断,以及排障实录(现象→定位→处置)。全部命令与回显来自
stable.20260611.1实例实测(2026-10-30),部署见《Snikket Docker Compose 部署指南》,配置机制见《Snikket stable.20260611.1 配置参数详解》。
一、环境信息
- 操作系统:Ubuntu 22.04 LTS(x86_64);Docker
29.9.2+ Composev5.6.1 - Snikket Server:
stable.20260611.1(四镜像 stable 通道),内置引擎Prosody trunk nightly build 2079 (2026-05-27, fa492a9d1a20) - 实例形态:测试域
snikket.local(自签证书路径),四组件 compose 栈,Web 端口映射 8140→80、8141→443 - 演示账号:管理员
admin@snikket.local,密码q1w2e3r4xy(⚠️ Snikket 密码策略最小长度 10,8 位的q1w2e3r4会被拒绝,实测见 7.4)
二、运维工具全景
动手之前先认清"手上的工具"和"名字的坑"。Snikket 的运维入口有三类:
| 入口 | 载体 | 管什么 |
|---|---|---|
prosodyctl / prosodyctl shell | snikket_server 内置 CLI | XMPP 核心:状态、用户、配置查询、自检 |
create-invite 等 /usr/local/bin 工具 | snikket_server 内置 | 邀请签发、TURN 地址计算 |
docker compose | 部署目录 | 四组件生命周期:启停、日志、升级 |
snikket_server 镜像内 /usr/local/bin 实测清单(docker exec snikket ls /usr/local/bin):
create-invite
smtp-url-to-msmtp
snikket-turn-addresses
create-invite 签发注册邀请(5.2 详解);smtp-url-to-msmtp 是启动脚本内部把 SNIKKET_SMTP_URL 转成 msmtp 配置用的,运维无需直呼;snikket-turn-addresses 计算 TURN 服务对外的地址列表(需传域名参数,直接跑会报 no domain specified),配合防火墙放行 TURN 端口时使用。
服务名与容器名对照(compose 服务名 ≠ 容器名,混用必踩坑):
| compose 服务名 | 容器名 | 典型命令用谁 |
|---|---|---|
snikket_server | snikket | docker compose logs snikket_server;docker exec snikket prosodyctl ... |
snikket_proxy | snikket-proxy | docker compose restart snikket_proxy |
snikket_portal | snikket-portal | docker compose logs snikket_portal |
snikket_certs | snikket-certs | docker compose logs snikket_certs |
实测踩坑:docker compose logs snikket(拿容器名当服务名)直接报错:
no such service: snikket
用 docker compose config --services 拿权威清单:
snikket_certs
snikket_portal
snikket_proxy
snikket_server
规则:docker compose 子命令一律用服务名(带 _server 后缀),docker exec 一律用容器名(连字符/无后缀)。
三、前置条件
- 已按《Snikket Docker Compose 部署指南》完成部署,四组件
Up,且手上有部署目录(官方约定/etc/snikket,本文以/etc/snikket书写); - 具备部署目录的 sudo 权限(compose 命令需能读 docker-compose.yml 与 snikket.conf);
- 正式实例需有真实域名与 DNS 记录——本文多处自检命令在测试域上"报错"属预期(报错本身即诊断素材,见 5.4 解读)。
四、状态查看与版本管理
4.1 版本查证(三种方式)
官方升级文档推荐命令行方式查版本:
docker exec snikket prosodyctl about | head -n1
实测回显:
Prosody trunk nightly build 2079 (2026-05-27, fa492a9d1a20)
注意这是引擎(Prosody)版本;Snikket 发行版版本要用 XMPP 版本查询(XEP-0092)问服务本体——用任一 XMPP 客户端库对 5222 端口发起会话并发版本查询即得。实测本实例的自报(Python slixmpp 客户端登录后 disco#info 携带 XEP-0092 查询的返回):
name: Prosody
version: Snikket release stable.20260611.1
第三种在 Web 界面:管理员登录门户 → 页脚 "Snikket service" → "Software versions"(官方升级文档口径,适合交给非运维同事自查)。
4.2 运行状态与健康检查
组件层状态用 compose 看:
cd /etc/snikket && docker compose ps
实测回显(节选 STATUS/PORTS 列):
NAME IMAGE SERVICE STATUS PORTS
snikket snikket/snikket-server:stable snikket_server Up 6 minutes 0.0.0.0:3478->3478/tcp, 0.0.0.0:5222-5223->5222-5223/tcp, 0.0.0.0:5269->5269/tcp, 0.0.0.0:3478->3478/udp
snikket-certs snikket/snikket-cert-manager:stable snikket_certs Up 10 minutes
snikket-portal snikket/snikket-web-portal:stable snikket_portal Up 10 minutes
snikket-proxy snikket/snikket-web-proxy:stable snikket_proxy Up 10 minutes 0.0.0.0:8140->80/tcp, 0.0.0.0:8141->443/tcp
四个服务全 Up 即正常;官方宿主网络形态下 PORTS 列为空属预期(host 网络不显示映射)。
XMPP 核心进程状态:
docker exec snikket prosodyctl status
Prosody is running with PID 18
门户健康检查端点 /_health(Nginx 已代理到门户):
curl -sk -o /dev/null -w '%{http_code}\n' -H 'Host: snikket.local' https://127.0.0.1:8141/_health
200
⚠️ 实测踩坑:这个 curl 必须带 Host: <你的域名> 头。Nginx 按域名路由,用 IP 直接访问不带 Host 头会落到默认站点返回 404(实测 https://127.0.0.1:8141/_health 不带 Host 头 → 404,带上 → 200);用 http 端口测会得到 301(跳 https)。监控脚本从本机拨测时,用域名作 URL 或显式 -H 'Host: <域名>'。
4.3 升级与回滚
官方升级流程(quick-start 安装方式)就两条命令:
cd /etc/snikket
docker compose pull
docker compose up -d
pull 拉取 :stable 浮动 tag 的最新镜像,up -d 依次重建有变化的组件;数据在 snikket_data 卷里,升级不动数据。升级前留意官方博客/Mastodon 的发布公告,实例自身也会收到更新通知(配置参数 SNIKKET_UPDATE_CHECK 控制,见《Snikket stable.20260611.1 配置参数详解》4.2)。
版本固定与回退:把 compose 里四个 image: 的 :stable 改成历史日期 tag(如 snikket/snikket-server:stable.20260611,Docker Hub 可查),docker compose up -d 即回退。⚠️ 回退跨过大版本可能涉及数据格式变更,先备份(5.5)再动手。
五、日常运维操作详解
5.1 用户管理
Snikket 是邀请制,没有"直接开账号"的常规路径;运维高频操作是查用户与重置密码。
查全部用户:
docker exec snikket prosodyctl shell user list snikket.local
admin@snikket.local
OK: Showing all 1 users
(snikket.local 换成你的 SNIKKET_DOMAIN。)
重置用户密码——prosodyctl shell user password 的参数是 完整 JID + 新密码,不是 user host password 三段式:
# 错误形态:把用户名当主机名解析,实测报错
$ docker exec snikket prosodyctl shell user password admin snikket.local q1w2e3r4xy
Error: No such host: admin
# 正确形态:JID 整体作第一个参数
$ docker exec snikket prosodyctl shell user password admin@snikket.local q1w2e3r4xy
OK: User password changed
⚠️ 新密码同样受 10 位最小长度策略约束(见 7.4)。查询单用户是否存在可用 prosodyctl shell user list 的输出对账,或经门户 "Manage users" 页核对(管理员登录 → Admin → Users)。
5.2 邀请管理
管理员邀请用镜像内置 create-invite(在 snikket_server 里执行)。给新管理员签发邀请:
docker exec snikket create-invite --admin --group default
实测回显:
Your invite link: https://snikket.local/invite/Bbvlmws-jPGYL1qXtfYeT_7N/
要点:
--admin授予管理员权限;--group default把受邀人挂进默认群组(Circle)。给普通用户签发就去掉--admin;- 输出的邀请链接发给受邀人,浏览器打开即走注册流(设置账号名与密码、导入客户端配置),注册成功邀请即失效;
- 邀请默认 28 天有效(模板
invites_bootstrap_ttl默认 28×86400 秒); - ⚠️ 该工具不认识
--help:实测create-invite --help→Error: Unknown parameter: --help。要批量管理邀请(列表/撤销)走门户界面:管理员登录 → Admin → Invitations; - 受邀注册时的密码规则与 5.1 相同(10 位起)。
5.3 证书运维
先懂链路再动手。Snikket 的证书是一条三级流水线(实测各组件行为归纳):
snikket_certs(certbot/anacron,每小时跑一次续期检查)
│ 产出 /snikket/letsencrypt/live/<域>/fullchain.pem + privkey.pem
▼
snikket_server(启动时 wait-for-certs 等证书,出现即 prosodyctl cert import)
│ 导入为 /etc/prosody/certs/<域>.crt/.key,XMPP 各端口启用 TLS
▼
snikket_proxy(cert-monitor 每 10 秒比对证书文件指纹,变了就重渲染 Nginx 并 reload;
另有每日兜底 reload,间隔由 SNIKKET_TWEAK_WEB_PROXY_RELOAD_INTERVAL 控制)
日常维护命令:
# 证书自检(覆盖主域 + groups./share. 两个子域)
docker exec snikket prosodyctl check certs
Checking certificates...
Checking certificate for groups.snikket.local
Certificate: /etc/prosody/certs/snikket.local.crt
Checking certificate for share.snikket.local
Certificate: /etc/prosody/certs/snikket.local.crt
Checking certificate for snikket.local
Certificate: /etc/prosody/certs/snikket.local.crt
All checks passed, congratulations!
# 看有效期( openssl 直接读导入后的证书)
docker exec snikket openssl x509 -enddate -noout -in /etc/prosody/certs/snikket.local.crt
notAfter=Oct 27 14:33:32 2036 GMT
(本实例走自签降级路径,有效期 10 年;正式 LE 证书有效期 90 天,靠每小时续期检查 + proxy 自动 reload 兜底,无需人工介入。)
💡 技术拓展:服务器证书的两种获取方式——
方式 原理 取舍 ACME HTTP-01(Let's Encrypt,正式部署用) cert-manager 经 80 端口完成域名校验后签发 90 天证书,自动续期 公网可信、零维护;要求域名可公网解析且 80 端口可达 自签证书(无公网域名/内网测试) 手工生成自签对并注入证书目录 无外部依赖;客户端必须手动信任或跳过校验,联邦与官方 App 推送受限 Snikket 的 cert-manager 默认走 ACME HTTP-01;无公网域名时 LE 签发必然失败,此时才用自签降级(完整实测与注入方法见《Snikket Docker Compose 部署指南》8.1)。本方案实测环境无公网域名,采用自签 + 客户端跳过校验。
5.4 日志与自检诊断
日志按服务取(注意用服务名,见第二章):
docker compose logs --tail 100 snikket_server # XMPP 核心最近 100 行
docker compose logs -f snikket_proxy # 跟踪代理日志(Ctrl-C 退出)
docker compose logs snikket_certs 2>&1 | grep -i certbot # 证书申请记录
server 日志实测尾部(测试域桥接形态):
snikket | Waiting for certificates to become available...
snikket | WARN: Unable to determine external IP address from DNS
snikket | ERROR: Unable to determine any public IP addresses, required for TURN
snikket | Waiting for certificates to become available...
证书组件日志实测(测试域上 certbot 每日任务签发失败并返回码 1,属自签降级场景的预期噪音;正式实例此处应为签发/续期成功记录):
snikket-certs | /etc/cron.daily/certbot:
snikket-certs | Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
snikket-certs | run-parts: /etc/cron.daily/certbot exited with return code 1
读日志要点:Waiting for certificates to become available... 是首次启动的正常等待(证书流水线就位后消失);TURN 公网 IP 的 WARN/ERROR 在桥接/NAT 形态下会持续出现(coturn 探测不到公网 IP 拒绝启动,处置见 7.2),宿主网络形态不应出现。
prosodyctl check 是比日志更主动的自检工具,五个子命令逐个跑一遍胜过翻半天日志。测试域实例上的真实输出与解读:
# 配置自检:配置文件能否加载、语法是否成立
docker exec snikket prosodyctl check config
Checking config...
The following configuration files have been loaded:
- /etc/prosody/prosody.cfg.lua
Done.
All checks passed, congratulations!
# DNS 自检:三个服务主机名的解析与 SRV 记录
docker exec snikket prosodyctl check dns
Checking DNS for component groups.snikket.local...
Host groups.snikket.local does not seem to resolve to this server (IPv4/IPv6)
Checking DNS for component share.snikket.local...
Problem looking up A record for 'share.snikket.local': ServFail
Problem looking up AAAA record for 'share.snikket.local': ServFail
HTTP service share.snikket.local has no A/AAAA record. Create one or change 'http_external_url' to the correct host.
Host share.snikket.local does not seem to resolve to this server (IPv4/IPv6)
Checking DNS for host snikket.local...
No _xmpps-client SRV record found for snikket.local, but it looks like you need one.
Problem looking up A record for 'snikket.local': ServFail
Problem looking up AAAA record for 'snikket.local': ServFail
File transfer proxy snikket.local has no A/AAAA record. Create one or set 'proxy65_address' to the correct host.
解读:测试域 snikket.local 本无公网 DNS,这批报错是预期现象,恰好完整演示了诊断能力——正式实例上出现同样的行就是真问题:ServFail = 解析失败查 DNS 服务;does not seem to resolve to this server = 记录指向了别的 IP;No _xmpps-client SRV record = 建议补 SRV 记录让客户端自动发现直连 TLS 端口。
# TURN 自检:向内置 TURN 发起真实测试
docker exec snikket prosodyctl check turn
Identified 1 TURN services.
Testing TURN service snikket.local:3478...
Error: Unable to perform TURN test: setpeername: temporary failure in name resolution
Problems found, see above.
测试域解析失败导致测试无法进行(同上属预期);正式实例上这条命令通过即音视频通话的中继链路就绪。
# 联邦连通性自检:经 observe.jabber.network 探测本域可达性
docker exec snikket prosodyctl check connectivity
Checking external connectivity for groups.snikket.local via observe.jabber.network
xmpp-server: Check service failed to establish (secure) connection
Checking external connectivity for snikket.local via observe.jabber.network
xmpp-client: Check service failed to establish (secure) connection
xmpps-client: Check service failed to establish (secure) connection
xmpp-server: Check service failed to establish (secure) connection
Note: The connectivity check only checks the reachability of the domain.
Note: It does not ensure that the check actually reaches this specific prosody instance.
Problems found, see above.
解读同上:测试域无公网记录必然全失败;正式实例全绿的前提是 5222/5223/5269 对公网放行且 DNS 正确(末尾两行 Note 提醒:该检查验证的是"域能被连到",不是"连到的就是你这台")。
5.5 数据备份与恢复要点
所有状态都在 snikket_data 卷(挂载点 /snikket)里,构成与备份要点:
/snikket/prosody/:用户账号、消息存档、群组、OAuth2/TURN 密钥、按域目录(snikket%2e<域>形式)——核心备份对象;/snikket/letsencrypt/:证书与续期状态(正式实例需备份,丢了可重签,但会触发重新验证);- 备份动作:停写窗口内整卷打包,实测(测试实例数据量小,产物仅 8KB;正式实例随消息/文件量增长):
docker run --rm -v snikket-20260611-stack_snikket_data:/data -v /tmp/snk_backup:/backup ubuntu \
tar czf /backup/snikket-data.tgz -C / data
tar: data/prosody/prosody.sock: socket ignored
ls -la /tmp/snk_backup/
-rw-r--r-- 1 root root 5995 Oct 30 23:13 snikket-data.tgz
(卷名 snikket-20260611-stack_snikket_data 为 compose 项目名 + 卷名拼接,docker volume ls | grep snikket 可查;socket ignored 是 unix socket 不入包的正常提示。)
- 恢复:新栈把卷填回
/snikket后docker compose up -d,server 会按目录属主自动修正 UID/GID,证书导入与端口激活自动完成; - 配置另存一份
snikket.conf+docker-compose.yml(几十行文本,跟着备份走)。
验证备份可用性的最低标准:恢复后 prosodyctl shell user list <域> 用户齐全 + curl 健康检查 200(4.2 的命令)。
六、注意事项
- restart ≠ up -d:
docker compose restart不重读 snikket.conf(环境变量是创建时注入的);改配置后必须up -d(实测闭环见《Snikket stable.20260611.1 配置参数详解》3.4)。 - 服务名/容器名别混用:
docker compose用服务名(snikket_server),docker exec用容器名(snikket),对照表见第二章。 - 拨测脚本带 Host 头:本机
curl健康检查必须-H 'Host: <域名>',否则 404(4.2 实测)。 - TWEAK 参数谨慎:生产实例不要随手加
TWEAK_变量做实验,逐项风险评估见《Snikket stable.20260611.1 配置参数详解》4.6。 - 升级前看公告、跨版本先备份:
:stable浮动 tag 自动跟进安全修复,跨大版本回退涉及数据格式(4.3、5.5)。 - create-invite 产出的链接即凭据:邀请链接在有效期内任何人可注册(管理员邀请获得管理员权限),走可信渠道传递,用完即过期。
七、常见问题(排障实录)
7.1 门户 502 Bad Gateway(重启某组件后出现)
- 现象:重启 portal(或宿主机网络变动)后访问门户 502;
docker compose logs snikket_proxy可见 upstream 连接拒绝。 - 定位:实测过程——桥接形态下 portal 容器重建拿到新 IP(如 10.89.60.4:5765),而 proxy 内 Nginx 的 upstream 缓存了旧容器 IP,
proxy_pass http://snikket_portal:5765解析结果过期,报Connection refused。 - 处置:
cd /etc/snikket && docker compose restart snikket_proxy
Nginx 重新解析服务名后恢复。宿主网络形态无此问题(同一网络栈,无 IP 缓存)。本坑只在"桥接 + 重建个别组件"组合下出现,遇到 502 先重启 proxy 再查别的。
7.2 coturn 报 "Unable to determine any public IP addresses, required for TURN"
- 现象:server 日志持续刷
ERROR: Unable to determine any public IP addresses, required for TURN,音视频通话中继不可用。 - 定位:coturn 启动时经公网 DNS 探测自身公网 IP;桥接/NAT 环境探测不到即拒绝启动(实测日志见 5.4)。
- 处置:正式部署用官方宿主网络形态(公网 IP 直绑,探测天然成功);确需 NAT 后部署时,按官方参数
SNIKKET_TWEAK_TURNSERVER_INTERNAL_IP指定内网 IP 且保证 NAT 保端口号映射(参数细节见《Snikket stable.20260611.1 配置参数详解》5.6)。测试/内网环境若不需要通话中继,可接受该 ERROR 常驻(不影响文字聊天)。
7.3 首次启动 proxy/portal 报 "host not found in upstream"
- 现象:全新启动后
docker compose logs snikket_proxy刷host not found in upstream "localhost:5765"类错误。 - 定位:Nginx 启动渲染配置时上游主机名尚未可解析(各组件启动无强顺序依赖,proxy 先于 portal 就绪时必然出现)。
- 处置:无需干预。各组件自带重试/重渲染逻辑,全栈就绪后自愈;实测方法:稍候重跑
curl -H 'Host: <域名>' https://127.0.0.1:<https端口>/_health至 200。持续不恢复才按 7.1 重启 proxy。
7.4 注册/改密提示密码强度不足
- 现象:邀请注册或重置密码设置 8 位密码(如
q1w2e3r4)被拒。 - 定位:内置密码策略最小长度 10(配置模板
password_policy = { length = 10 },运行时可用prosodyctl shell config get <域> password_policy查证)。 - 处置:用 ≥10 位密码(本文演示用
q1w2e3r4xy)。策略由镜像模板固化,snikket.conf 未暴露调整参数,别尝试从配置侧放宽。
7.5 日志里的噪音辨别
首次启动与测试环境常见三类"看着吓人实则无害"的日志:Waiting for certificates to become available...(证书流水线就位前的正常等待);桥接形态的 TURN 公网 IP WARN/ERROR(7.2,环境使然);WARN: Unable to determine external IP address from DNS(同 TURN 探测)。辨别原则:对照 5.4 的自检命令结果说话——check config/check certs 全绿、健康检查 200、客户端能登录收发消息,日志里的 WARN/ERROR 就按环境差异归类,不必逐条消灭。
八、参考链接
- 官方升级指南(4.3 流程来源):https://docs.snikket.org/setup/upgrading/
- 官方排障指南:https://docs.snikket.org/setup/troubleshooting/
- 官方防火墙端口说明(TURN 端口段):https://docs.snikket.org/advanced/firewall/
- prosodyctl 文档(check/shell 能力总览):https://prosody.im/doc/prosodyctl
- 站内关联文档:《Snikket 介绍与选型指南》、《Snikket Docker Compose 部署指南》、《Snikket stable.20260611.1 配置参数详解》