Snikket Docker Compose 部署指南

Snikket 官方四组件 Compose 部署:DNS/端口规划、启动初始化、邀请创建管理员、桥接形态改造、持久化与常见故障排障,基于 stable.20260611.1 实测。

SnikketSnikketDocker ComposeXMPP2026/10/30

Snikket Docker Compose 部署指南

目标:从零把一套 Snikket 私有聊天服务跑起来——官方四组件 Compose 编排、首次初始化、管理员邀请注册、数据持久化与常见启动故障处理。全流程已在 Ubuntu 22.04 服务器实测通过(Snikket Server stable.20260611.1,测试域 snikket.local,含无公网域名时的自签证书降级路径)。

一、环境信息

  • 操作系统:Ubuntu 22.04 LTS(x86_64)
  • Docker:Docker version 29.9.2, build a82e528;Compose:Docker Compose version v5.6.1(实测回显)
  • Snikket Server:snikket/snikket-server:stable(部署后 XEP-0092 实测自报 Snikket release stable.20260611.1;内置引擎 Prosody trunk nightly build 2079 (2026-05-27))
  • 四组件镜像(均为官方 stable 通道,2026-10-30 拉取):
    • snikket/snikket-server:stable(XMPP 核心 + coturn,57.5MB 压缩层)
    • snikket/snikket-web-proxy:stable(Nginx 入口代理,36MB)
    • snikket/snikket-web-portal:stable(Web 管理门户,61.6MB)
    • snikket/snikket-cert-manager:stable(Let's Encrypt 证书管理,49.7MB)
  • 测试域:snikket.local(无公网 DNS,走自签证书降级路径,见"八、常见问题"8.1);正式部署请用真实域名
  • 实测网络形态:自定义桥接网络 10.89.60.0/24,Web 端口映射 8140→80、8141→443(同机 80/443 已被占用时的替代形态);官方默认形态为宿主网络直绑 80/443,两者差异见 3.3

二、镜像选型说明

Snikket 官方只提供一种部署形态:四镜像 Compose 栈。镜像通道(tag)分三档:

通道tag说明适用
stable:stable官方稳定通道,对应 GitHub 仓库 stable.YYYYMMDD[.N] 日期 tag(当前最新 stable.20260611.1)生产/日常自用,本文采用
beta:beta预发布通道(snikket-selfhosted 仓库 compose.base 默认引用)愿意帮官方测新功能
dev:dev开发通道(官方仓库源码 compose 默认引用)参与开发

snikket/snikket-server:stable 镜像内部是 s6-supervised 多服务进程树(实测 ps -ef 节选):prosody -F(XMPP 主进程)、anacron(证书定时任务外壳)、coturn(STUN/TURN,等待证书后拉起)。Web 代理、门户、证书申请分属另外三个镜像,彼此通过共享数据卷 /snikket 协作。不要找"单镜像全家桶"tag——官方没有提供,四个镜像一起用才是受支持的形态。

选型建议:跟随 :stable 浮动 tag 即可;升级时 docker compose pull 拉新镜像后 up -d 重建,数据卷向后兼容。若要固定版本,可把 tag 写成明确的日期 tag(Docker Hub 上存在 stable.20260611 等历史 tag),代价是安全修复不再自动跟进。

三、前置条件

3.1 硬件与系统

  • 1 台 Linux 服务器(官方推荐 VPS 或树莓派皆可),1 核 1GB 内存起步即可稳定跑单实例(实测环境为共享宿主机,四组件合计常驻内存约 300MB);
  • 磁盘预留:消息存档与文件上传随用量增长,建议 10GB 起,并在 snikket.conf 限定上传总量(见《Snikket stable.20260611.1 配置参数详解》)。

3.2 DNS 与端口

正式部署需要一个可自主加子域记录的公网域名(官方 quickstart 要求):

# 域名                      TTL   类型    指向
chat.example.com.           300   A      203.0.113.123
groups.chat.example.com.    300   CNAME  chat.example.com.
share.chat.example.com.     300   CNAME  chat.example.com.

端口占用规划(官方形态宿主网络直绑,实测桥接形态为映射):

端口协议用途官方形态实测桥接形态
80TCPACME HTTP-01 验证 + HTTP 跳转直绑宿主映射 8140
443TCPWeb 门户 + XMPP Over HTTPS直绑宿主映射 8141
5222TCP客户端连接 C2S(STARTTLS)直绑宿主映射 5222
5223TCP客户端直连 TLS直绑宿主映射 5223
5269TCP服务器联邦 S2S直绑宿主映射 5269
3478TCP+UDPSTUN/TURN直绑宿主映射 3478(见 8.2 限制)

3.3 网络形态选择

💡 技术拓展:容器发布的两种网络形态——| 形态 | 原理 | 取舍 | |---|---|---| | host 网络直绑 | 容器直接使用宿主网络栈,端口=宿主端口,无需 NAT | SNAT 无损、TURN 等公网 IP 检测正常;代价是 80/443 必须独占、端口无隔离 | | bridge 桥接映射 | 容器独享内网,端口经 docker-proxy 映射 | 端口可规划、多实例共存;代价是镜像内"绑定 127.0.0.1 的服务间调用"会断(必须改监听地址与服务名互指)、TURN 公网 IP 检测失败、跳转 URL 带真实端口需额外处理 |

Snikket 官方 compose 采用 host 网络直绑(这正是它敢把"127.0.0.1:5280/5765"写死为默认值的原因);本文实测环境因 80/443 已被同机其他服务占用,改用桥接形态并补齐互指变量,两形态的完整配置都在下文给出。

四、部署步骤

4.1 准备部署目录与配置

# 创建部署目录(/etc/snikket 为官方约定路径)
mkdir -p /etc/snikket && cd /etc/snikket

# 下载官方稳定版 compose 编排
curl -o docker-compose.yml https://snikket.org/service/resources/docker-compose.yml

创建 snikket.conf(官方 compose 通过 env_file 给四个服务注入同一份配置):

cat > snikket.conf <<'EOF'
# Snikket 实例主域(一旦确定不可再改,所有组件共用)
SNIKKET_DOMAIN=snikket.local
# 管理员联系邮箱(同时是 Let's Encrypt 账户注册邮箱)
SNIKKET_ADMIN_EMAIL=admin@snikket.local
EOF

配置只有两个必填项:SNIKKET_DOMAIN 是实例身份(XMPP 地址后缀、证书签发对象),确定后不可更改;SNIKKET_ADMIN_EMAIL 用于 LE 账户注册与新用户可见的管理员联系方式。更多可选变量(留存天数、上传配额、TLS 档位等)见《Snikket stable.20260611.1 配置参数详解》。

4.2 官方宿主网络形态(推荐,真实域名场景)

官方 https://snikket.org/service/resources/docker-compose.yml 原文结构如下(四个服务全部 network_mode: host):

version: "3.3"

services:
  snikket_proxy:
    container_name: snikket-proxy
    image: snikket/snikket-web-proxy:stable
    env_file: snikket.conf
    network_mode: host
    volumes:
      - snikket_data:/snikket
      - acme_challenges:/var/www/html/.well-known/acme-challenge
    restart: "unless-stopped"
  snikket_certs:
    container_name: snikket-certs
    image: snikket/snikket-cert-manager:stable
    network_mode: host
    env_file: snikket.conf
    volumes:
      - snikket_data:/snikket
      - acme_challenges:/var/www/.well-known/acme-challenge
    restart: "unless-stopped"
  snikket_portal:
    container_name: snikket-portal
    image: snikket/snikket-web-portal:stable
    network_mode: host
    env_file: snikket.conf
    restart: "unless-stopped"
  snikket_server:
    container_name: snikket
    image: snikket/snikket-server:stable
    network_mode: host
    volumes:
      - snikket_data:/snikket
    env_file: snikket.conf
    restart: "unless-stopped"

volumes:
  acme_challenges:
  snikket_data:

真实域名 + 宿主网络场景下,此文件无需任何修改,直接进入 4.3 启动。

4.3 启动栈

docker compose up -d

实测回显(首次启动会依次拉起四个容器):

 Container snikket-proxy Started
 Container snikket-certs Started
 Container snikket-portal Started
 Container snikket Started

验证四容器状态:

docker compose ps --format 'table {{.Name}}\t{{.Status}}'
NAME             STATUS
snikket          Up 12 seconds
snikket-certs    Up 12 seconds
snikket-portal   Up 12 seconds
snikket-proxy    Up 12 seconds

确认 XMPP 核心端口激活(docker logs snikket 节选):

portmanager               info	Activated service 'c2s' on [*]:5222, [::]:5222
portmanager               info	Activated service 'c2s_direct_tls' on [*]:5223, [::]:5223
portmanager               info	Activated service 's2s' on [*]:5269, [::]:5269
portmanager               info	Activated service 'http' on [0.0.0.0]:5280

证书申请由 snikket-certs 服务完成(certbot,每日 anacron 触发、每小时巡检),签发成功后证书落盘共享卷 /snikket/letsencrypt/live/<域名>/;Prosody 启动前有 wait-for-certs 守门脚本,会循环执行 prosodyctl cert import /snikket/letsencrypt/live 等待证书就绪。证书就绪后,Web 代理内的 cert-monitor 服务(10 秒轮询)自动把 Nginx 从"等待页"切换为完整 HTTPS 配置并 reload。真实域名场景此时访问 http://<域名>/ 应 301 跳转 HTTPS 并出现登录页。

4.4 桥接网络形态(同机端口冲突/无真实域名时的实测形态)

桥接形态需要解决三个"官方默认值失效"问题:代理上游 localhost 不再互通、Prosody/门户只绑 127.0.0.1、TURN 公网 IP 检测。实测可用的完整 compose(放于部署目录替代官方文件):

name: snikket-20260611-stack

services:
  snikket_server:
    image: snikket/snikket-server:stable
    container_name: snikket
    env_file: snikket.conf
    environment:
      # Prosody 内部 HTTP API 绑定所有网卡(桥接下代理/门户要跨容器访问)
      SNIKKET_TWEAK_INTERNAL_HTTP_INTERFACE: 0.0.0.0
    volumes:
      - snikket_data:/snikket
    ports:
      - "5222:5222"
      - "5223:5223"
      - "5269:5269"
      - "3478:3478/udp"
      - "3478:3478/tcp"
    networks: [snikket_net]
    restart: "unless-stopped"

  snikket_portal:
    image: snikket/snikket-web-portal:stable
    container_name: snikket-portal
    env_file: snikket.conf
    environment:
      # 门户连 Prosody 管理 API:host 网络下镜像默认 http://127.0.0.1:5280/,
      # 桥接下必须改为服务名(这是桥接部署最关键的一处改动)
      SNIKKET_WEB_PROSODY_ENDPOINT: http://snikket_server:5280/
      SNIKKET_TWEAK_PORTAL_INTERNAL_HTTP_INTERFACE: 0.0.0.0
    networks: [snikket_net]
    restart: "unless-stopped"

  snikket_proxy:
    image: snikket/snikket-web-proxy:stable
    container_name: snikket-proxy
    env_file: snikket.conf
    environment:
      # Nginx 两个上游由 localhost 改为服务名
      SNIKKET_TWEAK_INTERNAL_HTTP_HOST: snikket_server
      SNIKKET_TWEAK_PORTAL_INTERNAL_HTTP_HOST: snikket_portal
    ports:
      - "8140:80"
      - "8141:443"
    volumes:
      - snikket_data:/snikket
      - acme_challenges:/var/www/html/.well-known/acme-challenge
    networks: [snikket_net]
    restart: "unless-stopped"

  snikket_certs:
    image: snikket/snikket-cert-manager:stable
    container_name: snikket-certs
    env_file: snikket.conf
    volumes:
      - snikket_data:/snikket
      - acme_challenges:/var/www/.well-known/acme-challenge
    networks: [snikket_net]
    restart: "unless-stopped"

networks:
  snikket_net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.60.0/24

volumes:
  acme_challenges:
  snikket_data:

改动逐项说明:SNIKKET_TWEAK_INTERNAL_HTTP_HOST/INTERFACE 控制 Nginx→Prosody 上游(官方默认 localhost:5280,Prosody 默认绑 127.0.0.1);SNIKKET_TWEAK_PORTAL_INTERNAL_HTTP_HOST/INTERFACE 控制 Nginx→门户上游(默认 localhost:5765,门户默认绑 127.0.0.1);SNIKKET_WEB_PROSODY_ENDPOINT 是门户镜像内置的 Prosody 管理端点(镜像默认值 http://127.0.0.1:5280/)。桥接网络子网先确认空闲再定(实测环境 10.89.56.0/24、10.89.58.0/24 已被其他栈占用,故取 10.89.60.0/24)。

启动后逐项验证(实测命令与回显,--resolve 用于把测试域指向本机,正式域名场景不需要):

# 健康检查:门户与 XMPP 各一个端点
curl -sk --resolve snikket.local:8141:127.0.0.1 "https://snikket.local:8141/_health/portal" -w ' [%{http_code}]\n'
curl -sk --resolve snikket.local:8141:127.0.0.1 "https://snikket.local:8141/_health/xmpp" -w ' [%{http_code}]\n'
STATUS OK [200]
STATUS OK
 [200]
# HTTP 入口 301 跳 HTTPS
curl -sik --resolve snikket.local:8140:127.0.0.1 "http://snikket.local:8140/" --max-time 10 | grep -i '^location'
Location: https://snikket.local:443/
# 管理 API 未授权访问应被拒绝(返回 401 而非 404/502,说明代理→Prosody 链路通)
curl -sk --resolve snikket.local:8141:127.0.0.1 "https://snikket.local:8141/admin_api/users" -o /dev/null -w '%{http_code}\n'
401

4.5 创建管理员账号(邀请制注册)

Snikket 没有"首次访问网页自动建管理员"的流程,管理员账号也走邀请制。在服务器上生成管理员邀请链接:

docker exec snikket create-invite --admin --group default
Your invite link: https://snikket.local/invite/MhuhpaBQrLc-lD2p_hiTLH7f/

浏览器打开该链接 → 点击网页上的 "Continue on this device / 注册" 入口(路径 /invite/<token>/register)→ 设定用户名与密码(密码最少 10 位,实测 8 位密码会被服务端密码策略拒绝)→ 提交后进入注册成功页,页面明确展示分配的 XMPP 地址:

<title>Successfully registered on snikket.local | Snikket</title>
<h1>Successfully registered on snikket.local</h1>
Your address
admin@snikket.local

随后访问 https://<域名>/(桥接形态 https://snikket.local:8141/),用 admin@snikket.local 与注册时密码登录。实测登录请求 POST /login 返回 302 并落地 /user/ 用户首页,访问 /admin/users 返回 200 管理页:

POST login: HTTP 302 -> https://snikket.local:8141/user/
GET /admin/users: HTTP 200
<h1>Manage users</h1>

门户登录页(GET /login 返回 200)包含 address、password、csrf_token、login 四个表单字段,CSRF 防护开启——若用脚本模拟登录需先取登录页拿 csrf_token 与会话 Cookie。

4.6 XMPP 客户端连通验证

用任意 XMPP 客户端或脚本连 5222 端口验证 C2S 登录(实测采用 Python slixmpp 1.17.0,STARTTLS + 自签证书跳过校验):

import asyncio, ssl, slixmpp

class Tester(slixmpp.ClientXMPP):
    def __init__(self):
        super().__init__(jid="admin@snikket.local", password="你的注册密码")
        self.register_plugin("xep_0030")
        self.register_plugin("xep_0092")
        self.add_event_handler("session_start", self.on_start)

    async def on_start(self, event):
        self.send_presence()
        info = await self["xep_0030"].get_info(jid="snikket.local", timeout=10)
        print("[disco#info]", info["disco_info"]["identities"])
        ver = await self["xep_0092"].get_version(jid="snikket.local", timeout=10)
        print("[version]", ver["software_version"]["name"], ver["software_version"]["version"])
        self.disconnect()

async def main():
    xmpp = Tester()
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    xmpp.ssl_context = ctx
    xmpp.connect(host="127.0.0.1", port=5222)
    await asyncio.wait_for(xmpp.disconnected, timeout=40)

asyncio.run(main())

实测回显(登录、服务发现、版本查询全部成功):

[disco#info] {('server', 'im', None, 'Prosody'), ('proxy', 'bytestreams', None, 'SOCKS5 Bytestreams Service')}
[version] Snikket Snikket release stable.20260611.1

版本应答 Snikket release stable.20260611.1 同时也是核对镜像版本的最直接手段。

五、数据持久化说明

数据落点说明
Prosody 全部业务数据(账号/角色/存档/MUC/上传缓存/ TURN 密钥)具名卷 snikket_data → 容器 /snikket/prosody/账号与角色存储为 internal 文件库(/snikket/prosody/<域>/),默认 files 后端
TLS 证书与私钥具名卷 snikket_data → /snikket/letsencrypt/live/<域名>/cert-manager 写入,Prosody 由 prosodyctl cert import 同步到 /etc/prosody/certs/
ACME 验证文件具名卷 acme_challengescert-manager 与 Web 代理共享 HTTP-01 challenge 目录
门户会话密钥portal 容器内 /etc/snikket-web-portal/secret_key首次启动自动生成(日志显示 SNIKKET_WEB_SECRET_KEY persisted to /etc/snikket-web-portal/secret_key);该文件不在共享卷内,docker compose down 后重建 portal 容器会重新生成,已登录会话全部失效(重启容器不丢,实测验证)

重启持久化实测:docker compose restart snikket_server snikket_portal 后 Prosody 正常拉起(prosodyctl status 回显 Prosody is running with PID 18),重新登录仍用原账号密码成功(POST /login: HTTP 302),证明账号/角色数据完整落盘于共享卷。

⚠️ 注意:桥接形态下重启 portal 容器后,Web 代理会因 Nginx upstream 缓存了旧容器 IP 而对门户路径报 502(实测 connect() failed (111: Connection refused) ... upstream "http://10.89.60.4:5765/"),需一并 docker compose restart snikket_proxy 让其重新解析服务名;宿主网络形态上游固定 127.0.0.1,无此问题。

六、环境变量表

snikket.conf 两个必填项:

变量必填说明
SNIKKET_DOMAIN是实例主域。XMPP 地址后缀、证书签发对象、子域(groups./share.)生成基准。首次启动后不可更改
SNIKKET_ADMIN_EMAIL是管理员邮箱,Let's Encrypt 账户注册邮箱 + 全站公开的管理员联系方式

可选:SNIKKET_LETSENCRYPT_TOS_AGREE=Y(snikket-selfhosted 配置样例中出现,表示同意 LE 服务条款)。其余留存、配额、TLS 档位、TWEAK 级变量全量解析见《Snikket stable.20260611.1 配置参数详解》。

七、配置文件挂载与等价 docker run

7.1 挂载关系

官方 compose 只挂载具名卷,不挂宿主目录。若想把数据落宿主磁盘(便于备份),可把 snikket_data:/snikket 替换为 ./snikket_data:/snikket 类 bind mount,容器内路径不变;替换前先备份并 chown 对齐(server 启动脚本会按 /snikket 目录属主自动修正 UID/GID)。自签证书注入的挂载玩法见 8.1。

7.2 等价 docker run

不用 Compose 时,四条命令等价复现官方形态(宿主网络版;桥接版在此之上追加 --network/-p/-e 参数,变量与 4.4 相同):

# 1. 数据卷
docker volume create snikket_data
docker volume create acme_challenges

# 2. XMPP 核心(Prosody + coturn)
docker run -d --name snikket --network host \
  --env-file /etc/snikket/snikket.conf \
  -v snikket_data:/snikket \
  --restart unless-stopped \
  snikket/snikket-server:stable

# 3. Web 代理(Nginx 入口)
docker run -d --name snikket-proxy --network host \
  --env-file /etc/snikket/snikket.conf \
  -v snikket_data:/snikket \
  -v acme_challenges:/var/www/html/.well-known/acme-challenge \
  --restart unless-stopped \
  snikket/snikket-web-proxy:stable

# 4. Web 管理门户
docker run -d --name snikket-portal --network host \
  --env-file /etc/snikket/snikket.conf \
  --restart unless-stopped \
  snikket/snikket-web-portal:stable

# 5. 证书管理器(Let's Encrypt)
docker run -d --name snikket-certs --network host \
  --env-file /etc/snikket/snikket.conf \
  -v snikket_data:/snikket \
  -v acme_challenges:/var/www/.well-known/acme-challenge \
  --restart unless-stopped \
  snikket/snikket-cert-manager:stable

启动顺序无强依赖(各组件自带等待/重试逻辑),但建议按 server → proxy → portal → certs 顺序起,日志更干净。

八、常见问题

8.1 无公网域名/测试环境:Let's Encrypt 证书失败,走自签证书降级

现象:snikket-certs 日志反复出现(实测回显):

/etc/cron.daily/certbot:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Unable to register an account with ACME server. The ACME server believes admin@snikket.local is an invalid email address.

定位:Let's Encrypt 需要公网域名 + 公网可达的 80 端口做 HTTP-01 验证;.local 测试域既过不了 ACME 账户邮箱校验,也没有可路由的验证入口。Prosody 侧则表现为 wait-for-certs 循环打印 Waiting for certificates to become available...(等待超时后退出)。

解决(实测路径):手工签发自签证书,放进共享卷的证书目录。三个子域(主域/groups/share)都要进 SAN:

# 1. 签发含三域名 SAN 的自签证书(CN=主域)
openssl req -x509 -newkey rsa:2048 -keyout snikket-local.key -out snikket-local.crt \
  -days 3650 -nodes -subj "/CN=snikket.local" \
  -addext "subjectAltName=DNS:snikket.local,DNS:groups.snikket.local,DNS:share.snikket.local"

# 2. 按官方证书目录约定放入共享卷(fullchain.pem/privkey.pem 固定命名)
docker run --rm -v snikket-20260611-stack_snikket_data:/snikket -v "$PWD":/seed alpine sh -c \
  'mkdir -p /snikket/letsencrypt/live/snikket.local && \
   cp /seed/snikket-local.crt /snikket/letsencrypt/live/snikket.local/fullchain.pem && \
   cp /seed/snikket-local.key /snikket/letsencrypt/live/snikket.local/privkey.pem'

验证:重启 snikket_server 后,日志出现证书导入回显,Prosody/Web 代理全部就绪:

Job `cron.daily' started
Imported certificate and key for hosts snikket.local, snikket.local, share.snikket.local, groups.snikket.local

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!

客户端(浏览器/XMPP 客户端)会提示证书不受信任,属自签预期行为:浏览器手工信任后继续访问;XMPP 客户端在测试脚本中跳过校验(生产环境严禁)。自签只是开发/测试降级路径,正式部署务必用真实域名让 cert-manager 自动走完 Let's Encrypt 流程。

8.2 桥接/NAT 环境 coturn 起不来

现象:docker logs snikket 反复出现(实测回显):

WARN: Unable to determine external IP address from DNS
ERROR: Unable to determine any public IP addresses, required for TURN

定位:内置 coturn 启动时需要探测服务器公网 IP 用于语音中继通告;桥接网络/NAT 内网环境探测不到。影响面仅为音视频通话中继(STUN/TURN),文字聊天、MUC、文件上传不受影响。

解决:① 官方宿主网络形态 + 服务器带公网 IP 时不出现,首选;② 桥接环境若不需要语音通话,在 snikket.conf 加 SNIKKET_TWEAK_TURNSERVER=0 关闭;③ 有固定公网 IP 但机器在内网 NAT 后,设 SNIKKET_TWEAK_TURNSERVER_INTERNAL_IP=<内网 IP> 并在路由器上做端口映射(要求保端口号)。改完 docker compose up -d 重建生效。

8.3 首次启动门户/代理报 "host not found in upstream"

现象:docker logs snikket-proxy:

[emerg] 15#15: host not found in upstream "snikket_portal" in /etc/nginx/snippets/snikket-common.conf:47

定位:桥接形态下四个容器同时启动,代理渲染 Nginx 配置时门户容器 DNS 名尚未注册。约 10 秒后 cert-monitor 轮询(证书已存在时)会重渲染配置并 reload,实测日志随后出现 signal process started 自愈。若仍未恢复,docker compose restart snikket_proxy 一次即可。

8.4 8 位密码注册被拒

现象:邀请注册页提交后报密码不符合要求。定位:Snikket 内置密码策略 length = 10(Prosody 配置模板实测值)。解决:使用至少 10 位的密码。

8.5 日志中的无害告警

  • sendmail: cannot connect to localhost, port 1025: Connection refused:未配置 SMTP 时 anacron 尝试给 root 发通知邮件失败,不影响任何业务功能;要消除可在 snikket.conf 配置 SNIKKET_SMTP_URL(如 smtp://mail.example.com:587/)。
  • Unable to load module 'track_muc_joins':官方 stable 包未随附该模块,实测群聊(MUC 创建/发言/成员管理)功能正常,属可忽略告警。

九、常用运维命令

docker compose ps                       # 四容器状态一览
docker compose logs -f snikket_server    # 跟踪 XMPP 核心日志(服务名,容器名是 snikket)
docker compose logs --tail 100 snikket_proxy   # 代理最近 100 行
docker compose restart snikket_proxy    # 重启单个组件
docker compose up -d                    # 修改 snikket.conf 后应用(重建有变化的容器)
docker compose pull && docker compose up -d    # 升级到最新 stable
docker compose down                     # 停止并移除容器(保留数据卷)
docker exec snikket prosodyctl status   # XMPP 核心状态
docker exec snikket create-invite --admin --group default   # 生成管理员邀请

更多用户管理、证书续期、日志排障命令见《Snikket stable.20260611.1 常用运维命令与排障详解》。

十、参考链接