Snikket Docker Compose 部署指南
Snikket 官方四组件 Compose 部署:DNS/端口规划、启动初始化、邀请创建管理员、桥接形态改造、持久化与常见故障排障,基于 stable.20260611.1 实测。
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.
端口占用规划(官方形态宿主网络直绑,实测桥接形态为映射):
| 端口 | 协议 | 用途 | 官方形态 | 实测桥接形态 |
|---|---|---|---|---|
| 80 | TCP | ACME HTTP-01 验证 + HTTP 跳转 | 直绑宿主 | 映射 8140 |
| 443 | TCP | Web 门户 + XMPP Over HTTPS | 直绑宿主 | 映射 8141 |
| 5222 | TCP | 客户端连接 C2S(STARTTLS) | 直绑宿主 | 映射 5222 |
| 5223 | TCP | 客户端直连 TLS | 直绑宿主 | 映射 5223 |
| 5269 | TCP | 服务器联邦 S2S | 直绑宿主 | 映射 5269 |
| 3478 | TCP+UDP | STUN/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_challenges | cert-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 常用运维命令与排障详解》。
十、参考链接
- 官方快速开始(Quick-start):https://docs.snikket.org/setup/quickstart/
- 官方稳定版 compose 下载源:https://snikket.org/service/resources/docker-compose.yml
- snikket-selfhosted(配套脚本与 conf 样例):https://github.com/snikket-im/snikket-selfhosted
- 防火墙端口说明:https://docs.snikket.org/advanced/firewall/
- 已有网站同机部署(反向代理改造):https://docs.snikket.org/advanced/reverse_proxy/
- 站内关联文档:《Snikket 介绍与选型指南》、《Snikket stable.20260611.1 配置参数详解》、《Snikket stable.20260611.1 常用运维命令与排障详解》