Movim 0.35.4 Docker Compose 部署指南
用官方镜像 ghcr.io/movim/movim(v0.35.4)通过 Docker Compose 部署完整 Movim 栈:PostgreSQL 15 + 自建 Prosody 13.0.1 XMPP + Movim 三服务编排,覆盖编排逐项说明、自签证书 CA 注入、管理员设置、登录链路端到端验证与 12 条实测排障记录;Ubuntu 24.04.5 / Docker 29.9.2 全量实测。
Movim 0.35.4 Docker Compose 部署指南
目标:用官方镜像
ghcr.io/movim/movim(内含 VERSION=v0.35.4)通过 Docker Compose 从零部署一套完整可用的 Movim——PostgreSQL 15 数据库 + Prosody 13.0.1 XMPP 服务器 + Movim 应用三服务编排,完成数据库迁移、管理员设置与登录链路端到端验证,并沉淀 12 条实测排障记录。已在 Ubuntu 24.04.5 LTS 服务器(Docker 29.9.2 / Docker Compose v5.6.1)上全量实测通过。定位与选型见 《Movim 0.35.4 介绍与选型指南》。
一、环境信息
本文所有命令与输出均在以下环境实测采集:
- 操作系统:Ubuntu 24.04.5 LTS(x86_64)
- Docker:29.9.2;Docker Compose:v5.6.1(
docker compose version实测) - Movim:v0.35.4(官方镜像
ghcr.io/movim/movim:latest,镜像内VERSION文件 = v0.35.4,构建于 2026-11-01,amd64,基于 serversideup/php:8.4-fpm-nginx-alpine3.21,PHP 8.4.15) - 数据库:PostgreSQL 15(官方镜像
postgres:15;官方 podman-compose 用 18.3-trixie,本地取已有 15 复用,功能一致) - XMPP 服务器:Prosody 13.0.1(
prosodyctl --version实测回显Prosody 13.0.1;Debian 13 发行版 apt 包自建镜像) - 端口映射:宿主
8148→ Movim 容器8443(HTTPS,自签证书);daemon WebSocket 容器内 8083;XMPP c2s 5222(仅内部网络) - Docker 网络:
movim-net(bridge,子网 10.89.72.0/24),XMPP 服务挂网络别名movim.local - 部署目录:
/opt/movim-stack/deploy(Compose 项目名取目录名deploy,故容器为deploy-db-1/deploy-xmpp-1/deploy-movim-1) - 演示口令:数据库与管理员演示密码统一
q1w2e3r4(生产务必更换)
二、镜像选型说明
Movim 官方镜像已迁移到 GitHub Container Registry,选型要点(均 2026-11-02 实测):
| 镜像 | 状态 | 说明 |
|---|---|---|
ghcr.io/movim/movim:latest | ✅ 官方现行发布渠道 | README 明示;镜像内 VERSION=v0.35.4;内含 nginx+fpm+daemon 全套 s6 服务 |
Docker Hub movim/movim | ❌ 已弃用 | 仓库存在但 无任何 tag(registry API 实测 tags=[],latest/master/0.35.4 等候选全 404;pull_count 110825、last_updated 2025-09-23) |
movim/xmpp-broker、movim/bridge | ❌ 不存在 | API 返回 object not found;旧架构(≤0.20)组件,现行版本无需 |
XMPP 侧 prosody/prosody(Docker Hub) | ⚠️ 本文自建替代 | 官方镜像存在,但本实验宿主 registry 白名单拒拉,改用 debian:13 + apt 自建(见 4.3) |
两种编排来源对比(本文选方案 B):
- 方案 A:官方 podman-compose.yml——仓库根自带(db=
postgres:18.3-trixie+ movim 本地 build,端口 8443),README 明示「仅测试用、缓存禁用」,且面向 podman; - 方案 B:自写 docker-compose.yml + 预构建镜像(本文采用)——直接引用
ghcr.io/movim/movim:latest,数据目录挂宿主卷,补一个 XMPP 服务组成完整闭环。
⚠️ 注意(国内/受限网络实测):本宿主配置了 registry-mirrors 白名单(daocloud/1ms.run/hub.rat.dev),非白名单镜像一律被拒。实际拉取
ghcr.io/movim/movim:latest走的是「skopeo copy --proxy经代理拉 docker-archive →docker load」的降级路径;prosody 官方镜像经代理直连 registry 仍报access denied,才改自建。正常网络环境直接docker pull即可,无需这些绕行。
💡 技术拓展:XMPP 服务器不止 Prosody 一种,Movim 可对接的常见选择——
服务器 语言 特点 适用 Prosody Lua 轻量、模块全、配置简洁,Debian/Ubuntu apt 直装 个人/小团队自建(本文采用) ejabberd Erlang 高并发、企业级、MAM/推送支持完善 中大规模部署 Openfire Java 管理后台完善、插件市场 已有 Java 运维体系 Movim 官方镜像内置? — 否,Movim 不内置 XMPP 服务器,必须外部提供 — 本文选 Prosody:apt 一个包 + 一个配置文件即可跑通,与 Movim 官方文档示例一致。
三、前置条件
- Docker 与 Compose:宿主机 Docker 24+(实测 29.9.2)与
docker composev2+ 插件(docker compose version→Docker Compose version v5.6.1); - 网络可达:能访问 ghcr.io 与 Docker Hub(受限网络见第二章 ⚠️ 降级实录);
- 端口规划:宿主 8148 空闲——
ss -ltn | grep 8148无输出即空闲; - 域名/别名规划:Movim 守护进程按 JID 域名(本文
movim.local)连接 XMPP 服务器,需保证应用侧能解析该域名(本文用 Docker 网络别名实现,见 4.4); - 证书准备:XMPP 服务器 TLS 证书(自签可用,但 CA 必须注入 Movim 信任链,见 4.5);
- 资源:建议至少 2 核 4GB(daemon + 3 worker + PG 常驻),磁盘预留 5GB;
- 数据库选择:强烈建议 PostgreSQL——部分特性仅 PG 可用;MariaDB 需 10.2+ 且 utf8mb4/utf8mb4_bin;MySQL 不支持。
四、部署步骤
4.1 建立部署目录与证书
mkdir -p /opt/movim-stack/deploy/xmpp/certs /opt/movim-stack/deploy/data/{pg,cache,log,public-cache}
cd /opt/movim-stack/deploy
生成 XMPP 域自签证书(供 Prosody 使用):
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout xmpp/certs/movim.local.key -out xmpp/certs/movim.local.crt \
-days 365 -subj "/CN=movim.local" -addext "subjectAltName=DNS:movim.local"
验证证书主体与 SAN(实测回显):
openssl x509 -in xmpp/certs/movim.local.crt -noout -subject -ext subjectAltName
# subject=CN = movim.local
# X509v3 Subject Alternative Name:
# DNS:movim.local
⚠️ 注意:目录一旦建错,Compose 挂载会踩「Docker 自动创建空目录」的坑(把挂载点当目录建),详见第十一章 Q1。
4.2 编写 Prosody 配置文件
xmpp/prosody.cfg.lua(完整内容,逐项说明见第七章 7.2):
-- Movim 演示用 Prosody XMPP 服务器配置
daemonize = false
plugin_paths = {}
folders = {
data = "/var/lib/prosody";
}
modules_enabled = {
"roster";
"s2s";
"tls";
"dialback";
"disco";
"private";
"vcard";
"carbons";
"pep";
"smacks";
"mam";
"bookmarks";
"lastactivity";
"register";
"admin_adhoc";
}
allow_registration = true
-- Movim 守护进程以普通 XMPP 客户端身份连接,证书由自定义 CA 签发并已注入信任链
c2s_require_encryption = false
authentication = "internal_plain"
log = "/var/log/prosody/prosody.log"
ssl = {
key = "/etc/prosody/certs/movim.local.key";
certificate = "/etc/prosody/certs/movim.local.crt";
}
VirtualHost "movim.local"
Component "conference.movim.local" "muc"
admins = { "admin@movim.local" }
4.3 构建 XMPP 服务镜像
xmpp/Dockerfile:
FROM debian:13
RUN apt-get update \
&& apt-get install -y --no-install-recommends prosody lua-unbound openssl \
&& rm -rf /var/lib/apt/lists/*
COPY prosody.cfg.lua /etc/prosody/prosody.cfg.lua
COPY certs/movim.local.key certs/movim.local.crt /etc/prosody/certs/
RUN chown prosody:prosody /etc/prosody/certs/movim.local.key /etc/prosody/certs/movim.local.crt
EXPOSE 5222
CMD ["/usr/bin/prosody", "--no-daemonize"]
逐项说明:lua-unbound 供 Prosody 做 DNS SRV 查询(缺了会报 Prosody was unable to find lua-unbound,见 Q6);user: prosody 在 Compose 侧声明(Prosody 拒绝 root 启动,见 Q2);启动参数必须用 --no-daemonize(写成 --daemonize=off 会被解析成「开启后台化」导致容器秒退,见 Q4)。
4.4 编写编排文件
docker-compose.yml(完整内容):
services:
db:
image: postgres:15
environment:
POSTGRES_USER: movim
POSTGRES_PASSWORD: q1w2e3r4
POSTGRES_DB: movim
volumes:
- ./data/pg:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U movim -d movim"]
interval: 2s
timeout: 5s
retries: 30
networks:
- movim-net
restart: unless-stopped
xmpp:
build:
context: ./xmpp
image: movim-demo-xmpp:1.0
user: prosody
networks:
movim-net:
aliases:
- movim.local
restart: unless-stopped
movim:
image: ghcr.io/movim/movim:latest
depends_on:
db:
condition: service_healthy
xmpp:
condition: service_started
environment:
DB_DRIVER: pgsql
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: movim
DB_USERNAME: movim
DB_PASSWORD: q1w2e3r4
DAEMON_URL: https://127.0.0.1:8148/
DAEMON_DEBUG: "true"
DAEMON_VERBOSE: "true"
volumes:
- ./xmpp/certs/ca-bundle.crt:/etc/ssl/certs/ca-certificates.crt:ro
- ./data/cache:/var/www/html/cache
- ./data/log:/var/www/html/log
- ./data/public-cache:/var/www/html/public/cache
ports:
- "8148:8443"
networks:
- movim-net
restart: unless-stopped
networks:
movim-net:
driver: bridge
ipam:
config:
- subnet: 10.89.72.0/24
关键设计逐条说明:
xmpp服务的网络别名movim.local:Movim 容器内 Docker DNS 只认服务名,而守护进程按 JID 域名movim.local发起 SRV/A 查询——加别名后容器内getent hosts movim.local解析到 10.89.72.4、TCP 5222 连通(不加别名则连接失败,见 Q7);depends_on+ PG healthcheck:pg_isready就绪后才拉起 movim,避免迁移连不上库;DAEMON_URL:必须是用户浏览器实际访问的公网 URL(本文https://127.0.0.1:8148/)。不配它 daemon 直接拒绝启动,实测报错Please configure DAEMON_URL in .env;ca-bundle.crt只读覆盖挂载:把自签 XMPP 证书的 CA 注入 Movim 信任链(制作过程见 4.5);- 端口
8148:8443:镜像内 nginx 监听 8443(SSL_MODE=full自签 HTTPS),宿主端口按本机资源规划取 8148。
4.5 制作 Movim 侧 CA 信任包
Movim 镜像(Alpine)的 TLS 校验默认 allow_self_signed=false,Prosody 用自签证书时 daemon 的 STARTTLS 校验会失败。解法:以镜像自带 CA 文件为底,拼接自签证书生成新 bundle:
docker run --rm --entrypoint cat ghcr.io/movim/movim:latest \
/etc/ssl/certs/ca-certificates.crt > xmpp/certs/ca-bundle-base.crt
cat xmpp/certs/ca-bundle-base.crt xmpp/certs/movim.local.crt > xmpp/certs/ca-bundle.crt
grep -c "BEGIN CERTIFICATE" xmpp/certs/ca-bundle.crt
# 147(基础 146 张系统 CA + 1 张 movim.local 自签证书)
compose 已把该文件只读覆盖挂载回 /etc/ssl/certs/ca-certificates.crt(见 4.4),重建 movim 服务后生效。
4.6 启动与验证服务状态
docker compose up -d --build
docker compose ps
实测回显:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
deploy-db-1 postgres:15 "docker-entrypoint.s…" db 42 minutes ago Up 42 minutes (healthy) 5432/tcp
deploy-movim-1 ghcr.io/movim/movim:latest "docker-php-serversi…" movim 42 minutes ago Up 15 minutes (healthy) 8080/tcp, 9000/tcp, 0.0.0.0:8148->8443/tcp, [::]:8148->8443/tcp
deploy-xmpp-1 movim-demo-xmpp:1.0 "/usr/bin/prosody --…" xmpp 21 minutes ago Up 21 minutes 5222/tcp
三个服务 Up(db 与 movim 均 healthy)即编排成功。镜像内 s6 服务链会自动完成首启初始化:movim-migrations(oneshot,执行 composer movim:migrate)→ movim-daemon(longrun,php daemon.php start)→ tail-log。daemon 启动横幅实测(docker compose logs movim 节选):
Please set at least one user as an admin once its account is logged in
To set an existing user admin
Movim daemon launched
Base URL: https://127.0.0.1:8148/
😋 Avatar Handler Worker launched
🌍 Resolver Worker launched
🔔 Pusher Worker launched
Templates cache cleared
po files compiled
Files compiled in Opcache
Stickers compiled
Connect to tcp://movim.local:5222, peer_name: movim.local
XMPP socket launched
💡 说明:
Connect to tcp://movim.local:5222一行证明守护进程已按「无 SRV → 回退 5222」逻辑发起 XMPP 连接;首启时还没有用户,横幅提示先设置管理员(见 4.7)。
4.7 设置管理员
docker compose exec -u www-data movim php daemon.php setAdmin movim@movim.local
# User movim@movim.local is now admin
数据库侧验证(psql -U movim -d movim):users 表主键列名是 id(存 JID,不是叫 jid 的列),该行 admin=t:
select id, admin from users;
-- id | admin
-- ----------------+-------
-- movim@movim.local | t
4.8 端到端访问验证
Web 层(实测回显):
curl -sk -o /dev/null -w '%{http_code}' https://127.0.0.1:8148/
# 302
curl -skL https://127.0.0.1:8148/ | grep -o '<title>.*</title>'
# <title>Login</title>
nginx 访问日志同步印证:"GET /login HTTP/2.0" 200 15670。
登录链路(无浏览器环境用 curl + Python WebSocket 脚本复现):Movim 登录是「页面 WebSocket → daemon → XMPP」三段式,手工复现必须凑齐三个要素——
- WebSocket 握手必须携带
Cookie: MOVIM_SESSION_ID=<32位hex>、Origin、Sec-Fetch-Site: same-origin三个头(缺头时 daemon 报Core.php:397 Undefined array key 0;sessionId 非 hex 会被validateCookie拒绝并报Invalid password format); - 收到
{"func":"started","sid":"..."}帧后,必须先发注册帧{"func":"register","host":"movim.local"}(浏览器端由 login.js 取输入框@后的域名发出,见movim_websocket.js)——daemon 收到它才会发起 XMPP 连接; - 再发
ajaxLogin提交账号密码。
实测成功证据链:
HANDSHAKE 101
{"func":"started","sid":"75598950..."}
→ Toast "已连接到服务器" → {"func":"registered"} → Login.setQuick
daemon 日志:Connect to tcp://movim.local:5222, peer_name: movim.local → XMPP socket launched → Handler Firing Payload\STARTTLS;客户端收到 presence from movim@movim.local/movimvYMlbRDWR2xjexzL(资源绑定成功);Prosody 日志印证:
Nov 02 07:38:22 c2s59decaa62e30 info Client connected
至此登录闭环全通。日常运维命令见第十章,配置项逐项解释见 《Movim 0.35.4 配置参数详解》,CLI 命令全集见 《Movim 0.35.4 常用 CLI 命令与工具详解》。
五、数据持久化说明
本文把全部状态挂到宿主 ./data/ 下(Compose 绑定挂载,非命名卷),重建服务不丢数据:
| 宿主路径 | 容器路径 | 内容 | 备份建议 |
|---|---|---|---|
./data/pg | /var/lib/postgresql/data | PostgreSQL 全部业务数据(users/configuration/phinxlog 等) | 核心,定期 pg_dump |
./data/cache | /var/www/html/cache | 模板/语言/图片缓存 | 可再生,可不备 |
./data/log | /var/www/html/log | Movim 运行日志(loglevel=2 时落盘) | 按合规要求保留 |
./data/public-cache | /var/www/html/public/cache | 头像/图片等对外缓存 | 可再生(重新从 XMPP 网络拉取) |
持久化实测:docker compose restart movim 后,users 表管理员行与 configuration 表 CLI 写入值均保留(psql 复查通过);Prosody 侧账号数据在其容器 /var/lib/prosody(本文未外挂,生产部署应补一条 - ./data/prosody:/var/lib/prosody 挂载)。
六、环境变量表
Movim 服务通过环境变量注入配置(三级来源:.env 文件 → 同名环境变量覆盖 → config/*.php 默认值;逐项详解见 《Movim 0.35.4 配置参数详解》)。本文用到的键:
| 变量 | 本文取值 | 默认值 | 说明 |
|---|---|---|---|
DB_DRIVER | pgsql | pgsql | 数据库驱动,pgsql/mysql 二选一(MySQL 实际不支持) |
DB_HOST | db | localhost | 数据库主机(Compose 服务名) |
DB_PORT | 5432 | 5432 | 数据库端口 |
DB_DATABASE | movim | movim | 库名 |
DB_USERNAME / DB_PASSWORD | movim / q1w2e3r4 | movim | 账号口令(演示值,生产更换) |
DAEMON_URL | https://127.0.0.1:8148/ | null | 必填,公网访问 URL;未配置 daemon 拒绝启动 |
DAEMON_PORT | (未设,镜像内 8083) | 8080(config 默认)/8083(镜像改) | WebSocket 监听端口 |
DAEMON_INTERFACE | (未设) | 127.0.0.1 | 监听地址,容器内对外需放开 |
DAEMON_DEBUG / DAEMON_VERBOSE | "true" / "true" | false | 调试与详细输出 |
GALENER_XMPP_IP / GALENER_XMPP_PORT | (未设) | 127.0.0.1 / 5347 | Galener 音视频组件对接参数 |
SSL_MODE | (镜像默认 full) | full | 镜像运行时 HTTPS 模式(自签) |
七、配置参数说明
7.1 Movim 镜像内部服务形态
官方镜像用 s6 编排三件套:movim-migrations(oneshot,composer movim:migrate)→ movim-daemon(longrun,php daemon.php start)→ tail-log;nginx 通过 server-opts.d/movim-websocket.conf 反代 WebSocket 到 daemon(容器内 8083)。SSL_MODE=full 时以镜像自签证书(/etc/ssl/private/self-signed-web.crt)提供 8443 HTTPS——生产应在反代层终结 TLS 或替换证书文件。
7.2 prosody.cfg.lua 关键项
daemonize = false+ CMD--no-daemonize:双保险禁止后台化(容器内后台化=主进程退出=秒退循环,见 Q4);modules_enabled:Movim 依赖的核心模块集(roster/pep/mam/carbons/smacks/vcard/bookmarks 等)。注意 Prosody 13 中groupchat已改名muc,且muc只能以 Component 形式加载——全局启用会报MUC should be loaded as a component(见 Q5);authentication = "internal_plain":明文存储于内部库,供 daemon 以普通客户端身份注册/登录(Movim 需要拿到账号密码走 SASL);log = "/var/log/prosody/prosody.log":字符串形式——表格式日志配置在 Prosody 13.0.1 会被静默忽略(源码 loggingmanagerapply_sink_rules只认[level]=filename、数组 sink 表或字符串文件名,见 Q3);c2s_require_encryption = false:放宽 c2s 强制加密(本文 CA 信任已注入,生产可收紧);Component "conference.movim.local" "muc":群组聊天服务。
八、配置文件挂载
| 挂载 | 形态 | 说明 |
|---|---|---|
./xmpp/certs/ca-bundle.crt → /etc/ssl/certs/ca-certificates.crt:ro | 只读覆盖 | 注入自签 XMPP 证书 CA(4.5 制作);:ro 防应用写回 |
./data/cache、./data/log、./data/public-cache | 读写绑定挂载 | 应用缓存/日志持久化(第五章) |
./data/pg | 读写绑定挂载 | 数据库数据目录 |
prosody.cfg.lua / 证书 | 打进镜像(Dockerfile COPY) | 也可改为挂载覆盖 /etc/prosody/prosody.cfg.lua,改配置后 docker compose restart xmpp 生效 |
⚠️ 注意:绑定挂载路径必须真实存在且类型正确(文件对文件、目录对目录)。路径写错时 Docker 会自动创建同名空目录顶在挂载点位置,导致后续报
not a directory——本次实测踩过两次(../xmpp/certs、../data相对路径写错),统一改为./xmpp/certs与./data后解决(见 Q1)。
九、等价 docker run
Compose 编排等价的手动单容器命令(供不使用 Compose 的环境参考;本文实测载体为 Compose):
docker network create --subnet 10.89.72.0/24 movim-net
docker run -d --name movim-db --network movim-net \
-e POSTGRES_USER=movim -e POSTGRES_PASSWORD=q1w2e3r4 -e POSTGRES_DB=movim \
-v $(pwd)/data/pg:/var/lib/postgresql/data \
postgres:15
docker run -d --name movim-xmpp --network movim-net --network-alias movim.local \
-u prosody \
movim-demo-xmpp:1.0
docker run -d --name movim --network movim-net -p 8148:8443 \
-e DB_DRIVER=pgsql -e DB_HOST=movim-db -e DB_PORT=5432 \
-e DB_DATABASE=movim -e DB_USERNAME=movim -e DB_PASSWORD=q1w2e3r4 \
-e DAEMON_URL=https://127.0.0.1:8148/ -e DAEMON_DEBUG=true -e DAEMON_VERBOSE=true \
-v $(pwd)/xmpp/certs/ca-bundle.crt:/etc/ssl/certs/ca-certificates.crt:ro \
-v $(pwd)/data/cache:/var/www/html/cache \
-v $(pwd)/data/log:/var/www/html/log \
-v $(pwd)/data/public-cache:/var/www/html/public/cache \
ghcr.io/movim/movim:latest
差异说明:手动形态无 depends_on 健康门控,需自行确认 movim-db healthy 后再起 movim;--network-alias 仅默认网络生效,与 Compose 的 services.xmpp.networks.movim-net.aliases 等价。
十、常用运维命令
docker compose ps # 服务状态(回显见 4.6)
docker compose logs -f movim # 跟踪 daemon/迁移日志
docker compose logs xmpp # Prosody 日志(或读 ./data 外挂路径)
docker compose exec -u www-data movim php daemon.php sessionsTree
sessionsTree 有活跃会话时实测回显:
⚙️ Movim Daemon 🔧 1 👤 1
╰─ 🔧 moUbKF2sctYINewz (1)
╰─ 👤 🟠 75598950ab73ae0d7d5cc6a4f80cc88e movim@movim.local (0)
(图例:🔴 Launched / 🟠 XMPP Socket connected / 🟢 XMPP Session started;无会话时为 ⚙️ Movim Daemon 🔧 0 👤 0。)
docker compose restart movim # 改配置/换 CA 后重启应用(数据保留,见第五章)
docker compose down # 停止并删除容器(保留 ./data 数据)
docker compose down -v --rmi local && rm -rf ./data # 彻底清理实验环境
CLI 命令(daemon.php 12 个子命令)的完整参数与回显,见 《Movim 0.35.4 常用 CLI 命令与工具详解》。
十一、常见问题(排障实录)
以下 12 条全部来自本次部署的真实踩坑过程,按出现顺序编号。
Q1:挂载报 not a directory?
现象:容器起不来,日志提示挂载点类型错误。定位:docker-compose.yml 里把证书与数据路径写成 ../xmpp/certs、../data(相对部署目录之外),Docker 在容器侧自动创建了空目录顶掉预期挂载点。解决:统一改为 ./xmpp/certs、./data(宿主机真实存在对应目录/文件)。教训:绑定挂载前先 ls 确认路径存在且类型正确。
Q2:Prosody 启动即退出,日志 Danger, Will Robinson!?
原因:Prosody 拒绝以 root 运行。解决:Compose 的 xmpp 服务加 user: prosody(Dockerfile 内 apt 安装已创建 prosody 用户)。
Q3:Prosody 日志文件不生成?
实测三阶段:log = { levels = { ... }, to = "file" } 报 io_open nil;log = { file = { ... } } 表格式在 Prosody 13.0.1 被静默忽略(不报错也不写文件);读 loggingmanager 源码确认 apply_sink_rules 只认 [level]=filename、数组 sink 表、字符串文件名三种形态。解决:log = "/var/log/prosody/prosody.log" 字符串形式,立即生效(4.8 的 c2s 日志即从此文件读出)。
Q4:xmpp 容器秒退、无限重启?
原因:启动命令写成 prosody --daemonize=off——该语法非法,被解析为「开启后台化」,Prosody 转后台后容器主进程退出。解决:prosodyctl/prosody --help 实测确认正确参数是 -F / --no-daemonize,配置文件同时保留 daemonize = false。
Q5:Prosody 报模块错误 MUC should be loaded as a component?
原因:沿用旧配置把 groupchat 写进 modules_enabled。Prosody 13 中该模块已改名 muc,且只能由 Component "conference.<域名>" "muc" 形式加载(本文即 Component "conference.movim.local" "muc");另外 blocking 模块在 Debian 13 发行版缺失,也要从 modules_enabled 移除。解决:按 4.2 配置——muc 走 Component,删掉 blocking。
Q6:Prosody 启动报 Prosody was unable to find lua-unbound?
原因:DNS SRV 查询依赖 lua-unbound 绑定,最小化镜像未带。解决:apt 加装 lua-unbound(已并入 4.3 Dockerfile)。
Q7:daemon 连不上 XMPP(域名解析失败)?
现象:daemon 反复报无法连接 movim.local。定位:容器内 Docker DNS 只解析服务名,不认 JID 域名。解决:xmpp 服务在网络下声明别名 aliases: [movim.local](4.4),容器内 getent hosts movim.local → 10.89.72.4,nc -z 5222 通。
Q8:STARTTLS 证书校验失败?
现象:连接建立但 TLS 握手被拒。原因:Movim Linker.php 默认 allow_self_signed=false、peer_name=JID 域名,自签证书不在镜像 CA 内。解决:4.5 制作 ca-bundle(镜像原 CA + 自签证书拼接),只读覆盖挂载 /etc/ssl/certs/ca-certificates.crt,重启后 Handler Firing Payload\STARTTLS 通过。
Q9:手工 WebSocket 握手成功但 daemon 报 Core.php:397 Undefined array key 0?
原因:握手缺 Sec-Fetch-Site: same-origin(及 Origin、MOVIM_SESSION_ID Cookie)头,daemon 解析请求上下文取不到值。解决:补齐三个头;MOVIM_SESSION_ID 必须是 32 位 hex,否则 validateCookie 报 Invalid password format。
Q10:发了登录请求但 daemon 不发起 XMPP 连接?
原因:漏了 register 帧。浏览器在 login.js 里用输入框 @ 后域名发 {"func":"register","host":"movim.local"}(源码 movim_websocket.js:12),daemon 收到后才建 XMPP 连接;手工脚本必须在 started 帧后、ajaxLogin 前补发。
Q11:GHCR 镜像拉不下来?
本宿主 registry-mirrors 白名单拒绝非白名单镜像。降级路径(实测有效):skopeo copy --proxy 192.168.1.72:7897 docker://ghcr.io/movim/movim:latest docker-archive:movim-ghcr-latest.tar → docker load -i。prosody 官方镜像同法仍报 access denied,最终改 debian:13 + apt 自建(4.3)。正常网络直接 pull 即可。
Q12:daemon 启动横幅提示 Please configure DAEMON_URL in .env 后退出?
DAEMON_URL 是启动硬检查项(源码 DaemonCommand.php 检查链:迁移状态 → PHP 扩展 → DAEMON_URL → 目录可写 → admin)。按 4.4 配置后,URL 缺 scheme 时 daemon 会自动补 https:// 再校验。
十二、参考链接
- Movim 仓库与镜像:https://github.com/movim/movim (ghcr.io/movim/movim)
- 官方安装指南:仓库根
INSTALL.md;快速测试参考podman-compose.yml - Prosody 文档:https://prosody.im/doc (loggingmanager、MUC、模块列表)
- PostgreSQL 镜像:https://hub.docker.com/_/postgres
- Galener(音视频):https://github.com/movim/galener
- 本专栏姊妹篇:《Movim 0.35.4 介绍与选型指南》、《Movim 0.35.4 配置参数详解》、《Movim 0.35.4 常用 CLI 命令与工具详解》