Docker Compose 部署 ejabberd 指南

ejabberd 26.09 官方 ecs 镜像 Compose 从零部署实战:镜像选型、端口规划、数据持久化、管理员注册、WebAdmin 验证与 CTL_ON_CREATE 踩坑实录,Ubuntu 22.04 逐命令实测。

ejabberd即时通信ejabberd2026/10/21

Docker Compose 部署 ejabberd 指南

目标:在一台 Ubuntu 22.04 服务器上,用 Docker Compose 从零部署 ejabberd 26.09 XMPP 即时通信服务器,覆盖镜像选型、端口规划、数据持久化、管理员账号开通、WebAdmin 验证与日常运维命令,全程命令均在 Ubuntu 22.04.4 LTS + Docker 29.8.1 环境实测通过。

一、环境信息

本章记录部署实测所用的真实环境,所有命令与回显均在此环境逐条执行验证。

  • 操作系统:Ubuntu 22.04.4 LTS(x86_64);
  • Docker:29.8.1;Docker Compose:v5.5.1(docker compose v2 语法);
  • ejabberd 版本:26.09(镜像 ejabberd/ecs:26.09,ProcessOne 官方维护,2026-10-21 时官方最新稳定版);
  • 服务端口规划:5222(XMPP 客户端)、5269(服务器联邦)直通宿主;WebAdmin HTTP 映射 8143→5280、TLS 综合口 8144→5443(5280/5443 若无冲突也可直通);
  • 数据目录:/srv/ejabberd/(compose 项目目录,含 conf/database/logs/upload 四个子目录);
  • 管理员账号:admin@localhost / q1w2e3r4(示例演示口令,生产环境务必更换为强口令)。

二、镜像选型说明

本章说明为什么选这个镜像、它与其他获取途径的差异,选型错误会直接影响后续配置路径。

ProcessOne 官方维护两个 ejabberd 服务端镜像,均随官方部署文档(CONTAINER.md)发布:

镜像构建仓库架构配置路径特点
ejabberd/ecs(Docker Hub)processone/docker-ejabberdx64/home/ejabberd/conf/(与 /opt/ejabberd/conf/ 同一文件)Community Server 版,默认配置已预置 admin 账号的 ACL,开箱即用
ghcr.io/process-one/ejabberd(GitHub Packages)processone/ejabberd 主仓库 .github/containerx64 + arm64/opt/ejabberd/conf/稳定版与 master 双通道,环境变量宏机制(EJABBERD_MACRO_*)更完整

本篇实测采用 ejabberd/ecs:26.09,理由有三:

  1. 官方同源:ejabberd/ecs 由 ProcessOne 官方 docker-ejabberd 仓库构建发布,与 ghcr 版同属官方两条产品线,且 ecs 的默认配置文件对新手更友好(内置宏定义与完整模块清单,官方 Compose 文档主线即以此形态演示);
  2. 拉取可达:实测环境直接 docker pull Docker Hub 官方源成功;ghcr.io 通道在部分网络下会遇到 registry 拒绝(实测出现过 denied,见第七章排障记录);
  3. 版本一致:Docker Hub 的 ecs 仓库与主仓库同步发布 26.09 tag,版本号与源码 Release 一一对应。

⚠️ 注意:两个镜像的目录布局存在差异——ecs 用 /home/ejabberd/(家目录)与 /opt/ejabberd/ 双路径(指向同一份文件,实测 inode 相同);ghcr 版文档只写 /opt/ejabberd/。挂载卷时务必与你所选镜像的文档路径一致,混用会挂错位置导致配置不生效。

💡 说明:ejabberd 的版本认定双源依据、架构与同类横向对比见 《ejabberd 26.09 介绍与选型指南》。

💡 技术拓展:拉取官方镜像时常见的三个 tag 策略对比——

tag 形态含义适用
26.09(精确版本)锁定到具体 release生产部署,升级可控
latest跟随最新稳定版实验/试用,升级不可预期
master跟随开发主干功能验证,禁用于生产

本文实际采用 26.09 精确版本 tag,便于版本回溯与升级对比。

三、前置条件

部署前需确认服务器具备以下条件,逐项验证避免中途卡壳。

  1. Docker 与 Compose 已安装且版本可用:
docker --version && docker compose version

实测回显:

Docker version 29.8.1, build 4a63305
Docker Compose version v5.5.1
  1. 端口未被占用:5222/5269 直通,8143/8144 作为 WebAdmin 映射口,先检查:
ss -ltn | grep -E ':(5222|5269|8143|8144)\b' || echo 'ports free'

实测回显(部署前):

ports free

若 5222/5269 已被占用(比如宿主已跑其他 XMPP 服务),把映射改为 5223:5222 这类高位端口并在客户端相应调整;若 8143/8144 被占,从 8145 顺延取空闲端口即可。

  1. 数据目录已规划:本文使用 /srv/ejabberd/ 存放 compose 项目与全部持久化数据:
mkdir -p /srv/ejabberd/{conf,database,logs,upload}

⚠️ 注意:database/logs/upload 三个目录会被容器内 ejabberd 账号(UID:GID = 9000:9000)读写,bind mount 场景必须预先修正属主,否则启动时报权限拒绝:

chown -R 9000:9000 /srv/ejabberd/database /srv/ejabberd/logs /srv/ejabberd/upload
  1. 镜像已拉取:
docker pull ejabberd/ecs:26.09

实测回显(末行):

Status: Downloaded newer image for ejabberd/ecs:26.09

四、部署步骤

本章按「准备配置 → 编写 compose 文件 → 启动 → 注册管理员 → 验证」的顺序完成从零到可用,每一步都给出实测回显。

4.1 导出默认配置文件

ecs 镜像内置一份带完整注释的默认 ejabberd.yml(含宏定义、监听端口、模块清单),把它导出到宿主机再挂载回去,后续改配置不需要进容器:

cd /srv/ejabberd
docker run --rm --entrypoint sh ejabberd/ecs:26.09 -c 'cat /home/ejabberd/conf/ejabberd.yml' > conf/ejabberd.yml
chown 9000:9000 conf/ejabberd.yml
wc -l conf/ejabberd.yml

实测回显:

339 conf/ejabberd.yml

默认配置的核心结构(节选,完整内容见文件本体):

define_macro:
  HOST: localhost
  ADMIN: "admin@localhost"
  PORT_C2S: 5222
  PORT_C2S_TLS: 5223
  PORT_S2S: 5269
  PORT_HTTP_TLS: 5443
  PORT_HTTP: 5280

hosts:
  - HOST

acl:
  local:
    user_regexp: ""
  loopback:
    ip:
      - 127.0.0.0/8
      - ::1/128
  admin:
    user:
      - ADMIN

逐项说明:define_macro 定义宏变量,配置其余位置用 HOST、PORT_C2S 等宏名引用,改域名只需改宏值;hosts 声明本服务器服务的 XMPP 域;acl 的 admin 组引用 ADMIN 宏(即 admin@localhost),注册同名账号即自动获得管理权限。

4.2 编写 docker-compose.yml

在 /srv/ejabberd/ 下创建 docker-compose.yml。必须显式设置项目名 name: ejabberd-26.09-stack,防止同机其他 ejabberd 编排同名项目互相干扰;网络子网显式指定避免与既有网络冲突:

name: ejabberd-26.09-stack

services:
  ejabberd:
    image: ejabberd/ecs:26.09
    container_name: ejabberd-26.09-main
    hostname: ejabberd-server
    environment:
      - CTL_ON_CREATE=register admin localhost q1w2e3r4
      - CTL_ON_START=registered_users localhost ; status
    ports:
      - "5222:5222"
      - "5269:5269"
      - "8143:5280"
      - "8144:5443"
    volumes:
      - ./conf/ejabberd.yml:/opt/ejabberd/conf/ejabberd.yml:ro
      - ./database:/opt/ejabberd/database
      - ./logs:/opt/ejabberd/logs
      - ./upload:/opt/ejabberd/upload
    restart: unless-stopped

逐项说明:

  • CTL_ON_CREATE:仅首次启动时执行的 ejabberdctl 命令,这里注册管理员账号;多条命令用 ; 分隔;
  • CTL_ON_START:每次启动都执行的命令,这里列出已注册账号并打印状态,便于在日志中确认启动结果;
  • ports:5222(客户端)、5269(联邦)直通;5280(WebAdmin HTTP)与 5443(TLS 综合口)映射到宿主 8143/8144,避免与宿主已有 5280 冲突;
  • volumes:配置文件以只读方式挂入;database(Mnesia 数据)、logs(日志)、upload(HTTP 上传文件)三个目录持久化到宿主;
  • restart: unless-stopped:服务器重启后服务自动拉起。

⚠️ 实测踩坑:官方文档对挂载路径写的是 /opt/ejabberd/conf、/opt/ejabberd/database,而 ecs 镜像内配置实际存放在 /home/ejabberd/conf/。两个路径指向同一份文件(实测 inode 一致),按文档写 /opt/ejabberd/ 即可正常生效;若改用 ghcr 版镜像,路径以 /opt/ejabberd/ 为准。

4.3 启动服务

cd /srv/ejabberd
docker compose up -d

实测回显:

 Container ejabberd-26.09-main Created
 Container ejabberd-26.09-main Starting
 Container ejabberd-26.09-main Started

等待约 10 秒让 Mnesia 完成初始化,确认运行状态:

docker compose ps

实测回显(输出节选,PORTS 列有截断):

NAME                   IMAGE                 COMMAND                  SERVICE    CREATED          STATUS          PORTS
ejabberd-26.09-main    ejabberd/ecs:26.09    "/home/ejabberd/bin/…"   ejabberd   12 seconds ago   Up 12 seconds   0.0.0.0:5222->5222/tcp, [::]:5222->5222/tcp, 0.0.0.0:5269->5269/tcp, ...

查看启动日志确认 ejabberd 内核已就绪:

docker compose logs ejabberd | grep -E 'started in the node|accepting TCP'

实测回显(节选):

2026-10-21 08:47:20.535 [info] ejabberd 26.9.0 is started in the node :ejabberd@localhost in 0.80s
2026-10-21 08:47:20.562 [info] Start accepting TCP connections at [::]:1880 for :ejabberd_http

4.4 注册管理员账号并验证

⚠️ 实测踩坑(重要):compose 里虽然配置了 CTL_ON_CREATE=register admin localhost q1w2e3r4,但因为部署前已按第三章预创建了 database 目录并 chown,ejabberdctl 的首次启动判定(脚本中 [ -d "$SPOOL_DIR" ] || FIRST_RUN=true,即数据库目录不存在才视为首次运行)不会触发,CTL_ON_CREATE 被静默跳过。bind mount 方式下 database 目录必须提前存在,因此首次部署后请手动执行一次注册命令,并把它当作固定步骤:

docker exec ejabberd-26.09-main ejabberdctl register admin localhost q1w2e3r4

实测回显:

User admin@localhost successfully registered

验证账号与密码:

docker exec ejabberd-26.09-main ejabberdctl registered_users localhost
docker exec ejabberd-26.09-main ejabberdctl check_password admin localhost q1w2e3r4 && echo 'password OK'

实测回显:

admin
password OK

4.5 服务状态与端口验证

docker exec ejabberd-26.09-main ejabberdctl status

实测回显:

The node ejabberd@localhost is started with status: started
ejabberd 26.9.0 is running in that node

宿主侧确认端口监听:

ss -ltn | grep -E ':(5222|5269|8143|8144)\b'

实测回显:

LISTEN 0      4096         0.0.0.0:8143       0.0.0.0:*
LISTEN 0      4096         0.0.0.0:8144       0.0.0.0:*
LISTEN 0      4096         0.0.0.0:5222       0.0.0.0:*
LISTEN 0      4096         0.0.0.0:5269       0.0.0.0:*

4.6 WebAdmin 管理台验证

浏览器访问 http://<服务器IP>:8143/admin/,弹出 HTTP Basic 认证,用户名填 admin@localhost(完整 JID)、密码填 q1w2e3r4。命令行验证(HTTP 401 表示需要认证,带凭据返回管理台首页):

curl -s -o /dev/null -w '%{http_code}\n' --max-time 10 http://127.0.0.1:8143/admin/
curl -s -u 'admin@localhost:q1w2e3r4' --max-time 10 http://127.0.0.1:8143/admin/ | grep -oE '<title>[^<]*</title>'

实测回显:

401
<title>ejabberd Web Admin</title>

WebAdmin 首页可查看节点状态、已注册账号(Nodes → localhost → Accounts)、群聊、会话等,此处不再展开截图式描述。另外 8144(容器内 5443)是 TLS 综合口,同时承载 HTTPS 版 WebAdmin(https://<服务器IP>:8144/admin/)、REST API(/api)、WebSocket(/websocket)与 BOSH(/bosh)。

💡 说明:WebAdmin 的登录账号能登录的前提是 acl.admin 覆盖该账号——默认配置的 ADMIN 宏即 admin@localhost,故注册同名账号即可;若你改了 HOST 宏(换域名),管理员 JID 与注册命令都要同步改为 admin@<新域名>。

4.7 数据持久化验证

重启服务后账号与配置应原样保留(数据落在 Mnesia 磁盘表):

docker compose restart ejabberd
sleep 8
docker exec ejabberd-26.09-main ejabberdctl registered_users localhost

实测回显:

 Container ejabberd-26.09-main Started
admin

重启后 CTL_ON_START 仍会执行(每次启动都跑),日志可见:

:> ejabberdctl registered_users localhost
:> ejabberdctl status

数据目录落盘情况(宿主侧查看):

ls /srv/ejabberd/database/ | head -5

实测回显(节选):

archive_msg.DCD
archive_msg.DCL
last_activity.DCD
passwd.DCD
roster.DAT

五、环境变量表

ecs 镜像通过环境变量注入启动行为,下表为实测验证过的关键变量(全部来自官方部署文档并在本环境复核):

变量作用实测取值示例
CTL_ON_CREATE首次启动执行的 ejabberdctl 命令(数据库目录已存在时不触发,见 4.4 排障)register admin localhost q1w2e3r4
CTL_ON_START每次启动执行的命令,多条用 ; 分隔,命令前加 ! 可忽略失败registered_users localhost ; status
ERLANG_NODE_ARG覆盖 Erlang 节点名(集群用)ejabberd@main
ERLANG_COOKIEErlang 节点互联 cookie(集群各节点必须一致)dummycookie123
EJABBERD_BYPASS_WARNINGS置 true 时忽略配置警告(live 模式常用)true

💡 说明:ghcr 版镜像额外支持 EJABBERD_MACRO_* 环境变量(24.12 起),可把 ejabberd.yml 里的同名宏值用环境变量覆盖,例如 EJABBERD_MACRO_HOST=example.com 覆盖 HOST 宏;REGISTER_ADMIN_PASSWORD 配合 EJABBERD_MACRO_ADMIN 自动注册管理员。ecs 镜像以「挂配置文件 + CTL_ON_* 命令」为主要定制手段。

六、配置文件挂载与参数速改

日常改配置的最短路径:编辑宿主 /srv/ejabberd/conf/ejabberd.yml → 重启服务(配置文件以只读挂载,热重载也可用 ejabberdctl reload_config,但 ecs 只读挂载下更稳妥的是重启):

vim /srv/ejabberd/conf/ejabberd.yml
docker compose restart ejabberd

三个最高频的改动点:

  1. 改 XMPP 域名:把宏 HOST: localhost 改为你的域名(如 HOST: chat.example.com),同时 ADMIN 宏改为 admin@chat.example.com,再重新注册对应管理员账号;
  2. 开注册:默认 mod_register 的 ip_access: trusted_network 只允许回环网段自助注册(防滥用),生产若要开放自助注册需调整 trusted_network 的 ACL;
  3. 日志级别:顶层 loglevel: info 可改为 warning 降噪或 debug 排障。

配置文件的逐段详解(hosts/listeners/auth/数据库/ACL/modules 等每一节的参数含义与实测改法)见 《ejabberd 26.09 配置参数详解》。

七、等价 docker run 命令

不使用 compose 时,下面一条 docker run 等价于本文的 compose 部署(多行只为阅读方便):

mkdir -p /srv/ejabberd/{conf,database,logs,upload}
chown -R 9000:9000 /srv/ejabberd/database /srv/ejabberd/logs /srv/ejabberd/upload

docker run -d --name ejabberd-26.09-main \
  -p 5222:5222 -p 5269:5269 -p 8143:5280 -p 8144:5443 \
  -v /srv/ejabberd/conf/ejabberd.yml:/opt/ejabberd/conf/ejabberd.yml:ro \
  -v /srv/ejabberd/database:/opt/ejabberd/database \
  -v /srv/ejabberd/logs:/opt/ejabberd/logs \
  -v /srv/ejabberd/upload:/opt/ejabberd/upload \
  -e CTL_ON_START="registered_users localhost ; status" \
  ejabberd/ecs:26.09

生产建议统一用 compose 管理(版本声明、网络规划、一键升降级),docker run 仅用于临时验证。

八、常用运维命令

以下命令均在部署目录 /srv/ejabberd/ 下实测:

docker compose ps                      # 查看服务状态
docker compose logs -f ejabberd        # 跟踪日志
docker compose restart ejabberd        # 重启服务
docker compose stop                    # 停止服务(保留数据)
docker compose start                   # 再启动
docker compose down                    # 停止并移除服务(数据目录保留)
docker compose up -d                   # 重新拉起

进容器执行 ejabberdctl 的两种形态:

# 每条命令显式 exec(本文主线用法)
docker exec ejabberd-26.09-main ejabberdctl status

# 交互式进入后直接执行
docker exec -it ejabberd-26.09-main sh
ejabberdctl status

连接真实 XMPP 客户端做端到端验证:手机/电脑装任意 XMPP 客户端(如 Conversations、Gajim、Pidgin),账号填 admin@localhost、密码 q1w2e3r4、服务器地址填本机 IP、端口 5222,登录后在线人数即 +1:

docker exec ejabberd-26.09-main ejabberdctl stats onlineusers
docker exec ejabberd-26.09-main ejabberdctl connected_users

⚠️ 注意:localhost 域仅供同机/内网验证;要让外部客户端连上,需把 HOST 宏改为真实域名、配置 TLS 证书(官方支持 ACME 自动申请)并开放防火墙 5222 端口。

九、常见问题(FAQ)

Q1:拉取 ghcr.io/process-one/ejabberd:26.09 报 denied?

实测现象:docker pull ghcr.io/process-one/ejabberd:26.09 返回 Error response from daemon: error from registry: denied。定位:ghcr.io 匿名拉取在部分网络出口会被拒。解决:改用 Docker Hub 官方同步发布的 ejabberd/ecs:26.09(同为 ProcessOne 官方构建,本文主线即用它),或配置可访问 ghcr.io 的代理后重试。

Q2:CTL_ON_CREATE 配置的注册命令没有生效?

实测现象:compose 里配了 CTL_ON_CREATE=register admin localhost q1w2e3r4,启动后 registered_users localhost 仍为空。定位:ecs 入口脚本以「数据库 spool 目录是否存在」判定首次运行([ -d "$SPOOL_DIR" ] || FIRST_RUN=true),bind mount 部署必须预创建 database 目录,于是永远不满足首次运行条件,CTL_ON_CREATE 被跳过。解决:首次部署后手动执行一次 docker exec ejabberd-26.09-main ejabberdctl register admin localhost q1w2e3r4;CTL_ON_START(每次启动都执行)不受此影响,可留作启动自检。

Q3:启动失败,日志报 Mnesia/目录权限错误?

定位:bind mount 的 database/logs/upload 目录属主不是容器内 ejabberd 账号(9000:9000)。解决:宿主执行 chown -R 9000:9000 /srv/ejabberd/{database,logs,upload} 后 docker compose up -d 重启。

Q4:WebAdmin 打开一直 401?

正常现象——WebAdmin 就是 HTTP Basic 认证。用户名必须填完整 JID admin@localhost(只填 admin 会认证失败);若密码遗忘,用 ejabberdctl change_password admin localhost 新密码 重置后重试。

Q5:外部客户端连不上 5222?

按顺序排查:ss -ltn | grep 5222 确认宿主监听 → 防火墙放行 5222/TCP → 客户端服务器地址填宿主 IP 而非 localhost → 域名非 localhost 的部署要确认客户端 JID 域与 hosts 配置一致。

十、卸载与清理

cd /srv/ejabberd
docker compose down        # 停止并移除服务与网络,数据目录保留

确认不再需要数据后删除持久化目录:

rm -rf /srv/ejabberd

如需彻底清理镜像:

docker rmi ejabberd/ecs:26.09

十一、参考链接

  1. 官方部署文档 CONTAINER.md(镜像、端口、环境变量、Compose 示例):https://github.com/processone/ejabberd/blob/master/CONTAINER.md
  2. 官方 ecs 镜像仓库:https://hub.docker.com/r/ejabberd/ecs/
  3. 官方 Compose 编排仓库 docker-ejabberd:https://github.com/processone/docker-ejabberd
  4. ejabberd 26.09 Release(版本来源):https://github.com/processone/ejabberd/releases.atom
  5. ejabberd 官方文档站:https://docs.ejabberd.im/
  6. 官方文档防火墙与安全端口表:https://docs.ejabberd.im/admin/guide/security/#firewall-settings
  7. 同系列配置详解篇:《ejabberd 26.09 配置参数详解》
  8. 同系列命令详解篇:《ejabberd 常用 CLI 命令详解》