plugNmeet 2.5.3 Docker Compose 部署指南

用 Docker Compose 在单台服务器编排 plugNmeet 2.5.3 官方镜像与 LiveKit、NATS、Redis、MariaDB 依赖服务:NKey 生成、配置对位、一键拉起、数据持久化与运维命令,全部实测验证。

plugNmeetWebRTC视频会议2026/10/26

plugNmeet 2.5.3 Docker Compose 部署指南

目标:用 Docker Compose 在单台服务器上编排 plugNmeet 2.5.3 官方镜像与 LiveKit、NATS、Redis、MariaDB 四个依赖服务,一次性拉起可用的视频会议栈,实测登录页与健康检查接口正常响应,并给出数据持久化、配置挂载与日常运维命令。

一、环境信息

本文全部命令与回显在下列环境实测取得:

  • 操作系统:Ubuntu 24.04 LTS(x86_64),Docker 28.x + Docker Compose v2
  • plugNmeet 服务端镜像:mynaparrot/plugnmeet-server:latest(内含 v2.5.3)
  • 依赖镜像:livekit/livekit-server:latest(1.13.x)、nats:2.15-alpine、redis:8-alpine、mariadb:12.3
  • Compose 项目名:plugnmeet-2-5-3-stack(文件顶部 name: 显式声明)
  • 自定义网络:plugnmeet-net(bridge,子网 10.89.64.0/24)
  • 端口:8145(Web/API)、8146/8147(LiveKit)、50000-60000/UDP(RTC)、4222/8222(NATS)、3306/6379(仅绑定 127.0.0.1)
  • 数据目录:./data/{mariadb,nats,upload,log,artifacts,recordings}(bind mount 持久化)

🔗 组件定位与裸机安装路径见 《plugNmeet 2.5.3 介绍与选型指南》、《Ubuntu 24.04 安装 plugNmeet 2.5.3 指南》。

二、镜像选型说明

服务镜像体积选型理由
plugnmeetmynaparrot/plugnmeet-server1.68GB官方唯一镜像,内置客户端静态资源、字体与 FFmpeg 等转换依赖,无需另装
livekitlivekit/livekit-server132MB官方 SFU,plugNmeet 硬依赖,媒体转发全靠它
natsnats:2.15-alpine42.2MBplugNmeet v2.x 起用 NATS 承载消息总线与客户端 WebSocket,alpine 变体最小
redisredis:8-alpine161MB房间实时状态存储(带 24h TTL 语义),官方默认搭配
mariadbmariadb:12.3464MB历史数据(房间、录制、分析),官方脚本同版本

版本对应关系(2026-10-26 实查):服务端 v2.5.3 对应官方编排模板中的 nats:2.15-alpine 与 mariadb:12.3;livekit-server 与 plugnmeet-server 均用 latest 跟随上游,生产环境建议固定到具体 tag。

⚠️ 官方仓已从 plugnmeet/plugnmeet 迁移到 mynaparrot/plugNmeet-server,旧镜像名在 Docker Hub 已不存在,写编排文件时勿用旧名。

三、前置条件

  1. 已安装 Docker Engine 与 Compose v2 插件(docker compose version 可用)。
  2. 端口空闲:8145、8146、8147 未被占用;UDP 50000-60000 防火墙放行。
  3. 子网规划:compose 自建 bridge 网络需要一段空闲地址。本文选 10.89.64.0/24;多项目共存的宿主机上,10.89.56.0/24 起 20 个段常被并行项目占用,遇到 Pool overlaps with other one on this address space 报错就换一段(见第十一节)。
  4. 目录准备(本文统一放在 plugnmeet-lab/ 下):
$ mkdir -p plugnmeet-lab/data/{mariadb,nats,upload,log,artifacts,recordings} plugnmeet-lab/client
$ cd plugnmeet-lab

四、部署步骤

4.1 生成 NATS 密钥(NKey + Curve)

plugNmeet 与 NATS 之间用 auth_callout 鉴权,需要一对用户 NKey、一对账号 NKey(作 issuer)和一对 Curve xkey。用官方 natsio/nats-box 镜像生成(natsio/nats-box:latest 需先 pull):

$ docker run --rm natsio/nats-box:latest nsc generate nkey --user
SUAMHIWAFFCLN3DBPDPWBUMAHBGVPUF6ZIEZ3JKBJAHH6HZYORHDD76EP4
UCQYR5JHAAMHLAO36T7QXCDZOUWBNN2CFN6G5R4JPGAMJFR7VZT325VU
$ docker run --rm natsio/nats-box:latest nsc generate nkey --account
SAAJWLJT6OUHNIZAXI3HT4WQ2TLHTTBXSGV3IZA76N2J6WL4P5FA73ZZTM
ADDCGJ3LS3XP3XJHLIFZP6Q3ASIL64L7DTSQJVBWCDQFWEDZGW3TUZEU
$ docker run --rm natsio/nats-box:latest nsc generate nkey --curve
SXAAJKICFNMG3APQVW23KMOLSO6CPOO7WBLNMQGY7GGT6ZCNLKY4OTPOLA
XBVII36MTEP7BMTG6OFCYWWBAFMLX6CWQOUTD7YKEDJT6JJPI4PVSG44

前缀规则是配对的关键(填反服务必挂,见第十一节第 1 条):

类型私钥种子(给 plugnmeet 配置)公钥(给 nats-server.conf)
用户 NKeySU 开头U 开头
账号 NKeySA 开头A 开头
Curve xkeySX 开头X 开头

本文按上述规则使用一对实测生成的密钥(与你复现时生成的不一致是正常的,全程保持同一对即可):

  • 用户:seed SUAMBUHCVL6ISLATV5RLBIZ5N4TSH5BCJ2XHCHD636PTAOCMXXAR7HLRNY ↔ public UB6MDZLJHLS4YXJMKES6QWWCXCMTDSEZHO5GMYJAUQ3PJDHCTKZ6PGGD
  • 账号:seed SAAN4R7SHHPQ7ZSKJWBHACDMSYUGQ2L5QWDVUDCATOHKMSMC2E57KFGQIA ↔ public AC2DMAEHMXUQHIMIUOSRJI7FUN6GKKG55HAMWYO7O2OFWY7GLHXPUWJX
  • Curve:seed SXAOPXSEKADPNY7JTT3CNSIRZARFJGFFFXTPRJDXISS4I3GFOFE4B6GFPM ↔ public XCFAO7BHHJUGNY56CYQSCPXA32DASMHOX6WTAGT5RIPGVBZJAZEUJCE6

4.2 四份配置文件

nats-server.conf(公钥填这里):

websocket {
    port: 8222
    no_tls: true
}

jetstream: {
    store_dir: /data/jetstream
}

accounts {
    SYS: {
        exports: [
            {
                stream: "$SYS.ACCOUNT.PNM.>",
                accounts: [PNM]
            }
        ]
    }
    PNM: {
        jetstream: enabled
        imports: [
            {
                stream: {
                    account: SYS, subject: "$SYS.ACCOUNT.PNM.>"
                }
            }
        ]
        users: [
            {
                nkey: UB6MDZLJHLS4YXJMKES6QWWCXCMTDSEZHO5GMYJAUQ3PJDHCTKZ6PGGD
            }
        ]
    }
}

system_account: SYS

authorization {
    timeout: 5
    auth_callout {
        issuer: AC2DMAEHMXUQHIMIUOSRJI7FUN6GKKG55HAMWYO7O2OFWY7GLHXPUWJX
        auth_users: [ UB6MDZLJHLS4YXJMKES6QWWCXCMTDSEZHO5GMYJAUQ3PJDHCTKZ6PGGD ]
        account: PNM
        xkey: XCFAO7BHHJUGNY56CYQSCPXA32DASMHOX6WTAGT5RIPGVBZJAZEUJCE6
    }
}

config.yaml(plugNmeet 主配置,私钥种子填在 nats_info):

client:
  port: 8145
  debug: false
  path: "./client/dist"
  api_key: APIkey1234567
  secret: q1w2e3r4plugnmeetsecret0123456789abcd
  token_validity: 10m
  webhook_conf:
    enable: false
    url: ""
    enable_for_per_meeting: false
  prometheus:
    enable: true
    metrics_path: "/metrics"
    username: ""
    password: ""
  copyright_conf:
    allow_override: false
    text: 'Powered by <a href="https://www.plugnmeet.org" target="_blank">plugNmeet</a>'
  bbb_join_host: "http://127.0.0.1:8145"

room_default_settings:
  max_duration: 0
  max_participants: 0
  max_num_breakout_rooms: 6
  max_preloaded_wb_file_size: 5mb

log_settings:
  log_file: "./log/plugNmeet.log"
  maxsize: 20
  maxbackups: 4
  maxage: 2
  log_level: "info"

livekit_info:
  host: "http://127.0.0.1:8146"
  api_key: APIlivekit1234
  secret: q1w2e3r4livekitsecret012345678901234

livekit_sip_info:
  enabled: false
  trunk_name: "pnm-inbound-trunk"
  phone_numbers: []

redis_info:
  host: localhost:6379
  username: ""
  password: ""
  db: 0
  default_ttl: 24h

database_info:
  driver_name: mysql
  host: localhost
  port: 3306
  username: plugnmeet
  password: q1w2e3r4
  db: plugnmeet
  prefix: pnm_
  charset: "utf8mb4"
  loc: "UTC"
  conn_max_lifetime: 4m
  max_open_conns: 10

nats_info:
  nats_urls:
    - "nats://127.0.0.1:4222"
  nats_ws_urls:
    - "ws://127.0.0.1:8222"
  account: PNM
  nkey: SUAMBUHCVL6ISLATV5RLBIZ5N4TSH5BCJ2XHCHD636PTAOCMXXAR7HLRNY
  auth_callout_issuer_private: SAAN4R7SHHPQ7ZSKJWBHACDMSYUGQ2L5QWDVUDCATOHKMSMC2E57KFGQIA
  auth_callout_xkey_private: SXAOPXSEKADPNY7JTT3CNSIRZARFJGFFFXTPRJDXISS4I3GFOFE4B6GFPM
  num_replicas: 1
  room_stream_name: "pnm-room-stream"
  default_ttl: 24h
  subjects:
    system_api_worker: "sysApiWorker"
    system_js_worker: "sysJsWorker"
    system_core_worker: "sysCoreWorker"
    system_public: "sysPublic"
    system_private: "sysPrivate"
    chat: "chat"
    whiteboard: "whiteboard"
    data_channel: "dataChannel"
  recorder:
    recorder_channel: "recorderChannel"
    recorder_info_kv: "pnm-recorderInfo"
    transcoding_jobs_subject: "pnm-RecorderTranscoderJobs"

upload_file_settings:
  path: "./upload"
  max_size: 50
  max_size_whiteboard_file: 30
  keep_forever: false
  allowed_types: ["jpg","png","jpeg","svg","pdf","docx","txt","xlsx","pptx","zip","mp4","webm","mp3"]

recorder_info:
  recording_files_path: "./recording_files"
  token_validity: 30m
  ping_timeout: 8s
  enable_del_recording_backup: true
  del_recording_backup_path: "./recording_files/del_backup"
  del_recording_backup_duration: 72h

analytics_settings:
  enabled: true

artifacts_settings:
  storage_path: "./artifacts"
  token_validity: 10m
  enable_del_artifacts_backup: true
  del_artifacts_backup_path: "./artifacts/trash"
  del_artifacts_backup_duration: 72h

insights:
  enabled: false

路径解释:livekit_info.host 指向 8146、redis_info.host 指向 6379、database_info.host 指向 3306,均用 localhost——因为 plugnmeet 服务用 network_mode: host(见 4.4 编排文件),与 LiveKit/Redis/MariaDB 共享宿主机网络栈,直接回环互通,无需服务名 DNS。

全部配置项逐条释义见专栏《plugNmeet 2.5.3 配置参数详解》。

livekit.yaml(keys 与上面 livekit_info 严格一致):

port: 8146
rtc:
  port_range_start: 50000
  port_range_end: 60000
  tcp_port: 8147
  use_external_ip: false
  allow_tcp_fallback: true
redis:
  address: localhost:6379
  username: ""
  password: ""
  db: 0
room:
  auto_create: true
  enabled_codecs:
    - mime: audio/opus
    - mime: audio/red
    - mime: video/h264
    - mime: video/vp8
    - mime: video/vp9
    - mime: video/av1
logging:
  level: info
keys:
  APIlivekit1234: q1w2e3r4livekitsecret012345678901234
webhook:
  api_key: APIlivekit1234
  urls:
    - "http://127.0.0.1:8145/webhook"

install.sql:从服务端源码仓库 sql_dump/ 下载(https://raw.githubusercontent.com/mynaparrot/plugNmeet-server/v2.5.3/sql_dump/install.sql),放到编排目录,由 MariaDB 首次初始化自动执行建库建表。

4.3 编排文件 docker-compose.yaml

name: plugnmeet-2-5-3-stack

services:
  mariadb:
    image: mariadb:12.3
    container_name: plugnmeet-v2-5-3-mariadb
    restart: unless-stopped
    environment:
      MARIADB_ROOT_PASSWORD: q1w2e3r4
      MARIADB_DATABASE: plugnmeet
      MARIADB_USER: plugnmeet
      MARIADB_PASSWORD: q1w2e3r4
    volumes:
      - ./data/mariadb:/var/lib/mysql
      - ./install.sql:/docker-entrypoint-initdb.d/install.sql:ro
    networks: [pnm]
    ports:
      - "127.0.0.1:3306:3306"

  redis:
    image: redis:8-alpine
    container_name: plugnmeet-v2-5-3-redis
    restart: unless-stopped
    networks: [pnm]
    ports:
      - "127.0.0.1:6379:6379"

  nats:
    image: nats:2.15-alpine
    container_name: plugnmeet-v2-5-3-nats
    restart: unless-stopped
    command: ["-config", "/nats-server.conf"]
    volumes:
      - ./nats-server.conf:/nats-server.conf
      - ./data/nats:/data/jetstream
    networks: [pnm]
    ports:
      - "127.0.0.1:4222:4222"
      - "127.0.0.1:8222:8222"

  livekit:
    image: livekit/livekit-server:latest
    container_name: plugnmeet-v2-5-3-livekit
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./livekit.yaml:/app/livekit.yaml:ro
    command: ["--config", "/app/livekit.yaml", "--node-ip", "127.0.0.1"]
    depends_on:
      - redis

  plugnmeet:
    image: mynaparrot/plugnmeet-server:latest
    container_name: plugnmeet-v2-5-3-app
    restart: unless-stopped
    network_mode: host
    depends_on:
      - nats
      - livekit
      - mariadb
      - redis
    volumes:
      - ./config.yaml:/app/config.yaml
      - ./client:/app/client
      - ./data/upload:/app/upload
      - ./data/log:/app/log
      - ./data/artifacts:/app/artifacts
      - ./data/recordings:/app/recording_files

networks:
  pnm:
    name: plugnmeet-net
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.64.0/24

编排要点:

  • 两个网络模式并存:mariadb/redis/nats 走 bridge 隔离、端口只绑 127.0.0.1 不暴露公网;livekit/plugnmeet 走 network_mode: host——plugNmeet 官方镜像就是 host 网络口径(Web 直挂 8145、UDP 媒体段直收发),这也是官方编排模板的写法。
  • name: plugnmeet-2-5-3-stack 显式声明项目名,docker compose -p 不再需要;版本号进名字便于多套并存。
  • 网络名固定为 plugnmeet-net 并显式声明子网,避免重启后网段漂移。

4.4 启动与首次初始化

$ docker compose up -d
 Network plugnmeet-net Creating
 Network plugnmeet-net Created
 Container plugnmeet-v2-5-3-mariadb Creating
 Container plugnmeet-v2-5-3-nats Creating
 Container plugnmeet-v2-5-3-redis Creating
 Container plugnmeet-v2-5-3-nats Created
 Container plugnmeet-v2-5-3-mariadb Created
 Container plugnmeet-v2-5-3-redis Created
 Container plugnmeet-v2-5-3-livekit Creating
 Container plugnmeet-v2-5-3-livekit Created
 Container plugnmeet-v2-5-3-app Creating
 Container plugnmeet-v2-5-3-app Created
 Container plugnmeet-v2-5-3-nats Starting
 Container plugnmeet-v2-5-3-mariadb Starting
 Container plugnmeet-v2-5-3-redis Starting
 Container plugnmeet-v2-5-3-nats Started
 Container plugnmeet-v2-5-3-mariadb Started
 Container plugnmeet-v2-5-3-redis Started
 Container plugnmeet-v2-5-3-livekit Starting
 Container plugnmeet-v2-5-3-livekit Started
 Container plugnmeet-v2-5-3-app Starting
 Container plugnmeet-v2-5-3-app Started

首次启动 MariaDB 会执行 install.sql 建库建表(几秒);plugNmeet 启动时自动向 NATS 注册 auth_callout、建 JetStream 流。

4.5 部署验证

$ docker compose ps --format 'table {{.Name}}\t{{.Image}}\t{{.Status}}'
NAME                       IMAGE                                STATUS
plugnmeet-v2-5-3-app       mynaparrot/plugnmeet-server:latest   Up 33 minutes
plugnmeet-v2-5-3-livekit   livekit/livekit-server:latest        Up 37 minutes
plugnmeet-v2-5-3-mariadb   mariadb:12.3                         Up 37 minutes
plugnmeet-v2-5-3-nats      nats:2.15-alpine                     Up 33 minutes
plugnmeet-v2-5-3-redis     redis:8-alpine                       Up 37 minutes
$ curl -s -o /dev/null -w 'healthCheck HTTP %{http_code} ' http://127.0.0.1:8145/healthCheck
healthCheck HTTP 200 Healthy
$ docker logs plugnmeet-v2-5-3-app 2>&1 | grep -o 'version: 2.5.3' | head -1
version: 2.5.3

浏览器打开 http://<服务器IP>:8145/(参会入口)与 http://<服务器IP>:8145/login(管理入口,输入 config.yaml 的 api_key/secret)。

五、数据持久化说明

宿主机目录容器内路径内容重要性
./data/mariadb/var/lib/mysql房间历史、录制索引、分析记录高(删了历史全没)
./data/nats/data/jetstreamJetStream 流(房间实时状态中转)中(重建可自动恢复结构)
./data/upload/app/upload会议中上传的文件高
./data/log/app/log服务日志(20MB×4 轮转)低
./data/artifacts/app/artifacts会后 AI 摘要等产物中
./data/recordings/app/recording_files录制文件高

全部 bind mount 落宿主机目录,docker compose down 不丢数据;只有 down -v 或手动删目录才会清空。

六、环境变量表

本编排只有 MariaDB 一个服务消费环境变量(其余服务全部走挂载的配置文件),见 4.3 节:

变量示例值作用
MARIADB_ROOT_PASSWORDq1w2e3r4root 口令(仅本地排障用)
MARIADB_DATABASEplugnmeet首次启动自动建库
MARIADB_USER / MARIADB_PASSWORDplugnmeet / q1w2e3r4业务账号,需与 config.yaml 的 database_info 一致

plugNmeet 服务端本身不读环境变量——所有配置集中在 config.yaml,改配置 = 改文件 + docker compose restart plugnmeet。

七、配置参数说明

三份配置的互信对位关系(错一个服务就起不来,全部实测验证):

plugNmeet config.yaml对端文件必须一致的字段
client.api_key / client.secret登录页输入 / REST API 双头管理凭证
livekit_info.api_key / .secretlivekit.yaml 的 keys:LiveKit 互信
nats_info.nkey 等(SU/SA/SX 私钥种子)nats-server.conf 的 U/A/X 公钥NATS 鉴权
database_info.*MariaDB 环境变量与库名数据库连接

client.port 与容器内监听端口一致(host 网络下即宿主机端口);nats_ws_urls 是浏览器直连 NATS 的 WebSocket 地址(生产环境换 wss://域名/ws 并在反代终结 TLS)。

八、配置文件挂载一览

./config.yaml      → /app/config.yaml        (plugNmeet 主配置,可写挂载便于热替换)
./client           → /app/client             (客户端静态资源;官方镜像已内置,可省略)
./livekit.yaml     → /app/livekit.yaml:ro    (LiveKit 配置)
./nats-server.conf → /nats-server.conf       (NATS 配置)
./install.sql      → /docker-entrypoint-initdb.d/install.sql:ro(MariaDB 首次建表)
./data/*           → 各数据路径              (持久化,见第五节)

注意 client 挂载是可选的:官方镜像内自带客户端资源,只有需要替换自制前端时才挂载;且挂载目录内必须是 dist/ 布局(index.html 所在层)。

九、等价 docker run

以 plugNmeet 主服务为例,编排文件等价于:

$ docker network create --driver bridge --subnet 10.89.64.0/24 plugnmeet-net
$ docker run -d --name plugnmeet-v2-5-3-app \
  --network host \
  --restart unless-stopped \
  -v ./config.yaml:/app/config.yaml \
  -v ./client:/app/client \
  -v ./data/upload:/app/upload \
  -v ./data/log:/app/log \
  -v ./data/artifacts:/app/artifacts \
  -v ./data/recordings:/app/recording_files \
  mynaparrot/plugnmeet-server:latest

其余四个服务同思路(mariadb/redis/nats 加 --network plugnmeet-net 与端口映射,livekit 亦为 host 网络)。多服务编排仍建议始终用 compose 管理。

十、常用运维命令

$ docker compose ps                      # 五服务状态一览
$ docker compose logs -f plugnmeet       # 跟踪主服务日志
$ docker compose restart plugnmeet       # 改完 config.yaml 后重启生效
$ docker compose stop                    # 全栈停机(保留数据)
$ docker compose up -d                   # 全栈拉起
$ docker compose down                    # 停机并移除容器与网络(数据目录保留)
$ docker compose pull && docker compose up -d   # 升级镜像(升级前备份 ./data)

十一、常见问题

  1. plugNmeet 反复重启,日志报 failed to create nkey option: nkeys: invalid seed,NATS 报 Not a valid public nkey for a user:NKey 公私填反了——config.yaml 的 nats_info 必须填 SU/SA/SX 开头的私钥种子,nats-server.conf 必须填对应 U/A/X 开头的公钥(本文实测踩坑,见 4.1 前缀规则表)。
  2. up -d 报 Pool overlaps with other one on this address space:声明的子网已被其他 compose 项目占用。把 networks.pnm.ipam.config.subnet 换一段空闲地址即可(本文从 10.89.62 → 10.89.64 段实测换过两次)。
  3. bind: address already in use:8145/8146/8147 或 3306/6379/4222/8222 有占用者。特别注意上次异常退出残留的端口代理进程,ss -tlnp | grep <端口> 找到 PID 后处理再 up -d。
  4. NATS 日志 Expected callout user to be a valid public account nkey:auth_callout.issuer 必须是 A 开头的账号公钥而不是 SA 私钥种子;auth_users 里的用户 NKey 同理用 U 公钥。
  5. 健康检查 502/拒绝连接:depends_on 只保证启动顺序不保证就绪,MariaDB 初始化期间(首启几秒)plugNmeet 可能连库失败自动重启一轮,等 30 秒再看;持续失败查 docker compose logs mariadb 确认 install.sql 执行无误。
  6. 浏览器打不开页面:host 网络下 8145 直接监听在宿主机,检查防火墙;云服务器还需放行安全组。

十二、参考链接