BigBlueButton 3.0.39 Docker Compose 部署指南
BigBlueButton 3.0.39 Compose 部署:bigbluebutton/docker 社区编排 17 服务栈一键部署、.env 与自签/正式证书两种形态、Greenlight 管理员创建、Blocked hosts 与 ChecksumError 排障、API 全链路验证与数据持久化实测(2026-10-27 实测)。
BigBlueButton 3.0.39 Docker Compose 部署指南
目标:用官方社区编排项目 bigbluebutton/docker 一键部署 BigBlueButton 3.0.39 全家桶(核心服务 + FreeSWITCH + webrtc-sfu + Greenlight 前端 + coturn 等 17 个服务),完成 .env 配置、编排文件生成、启动、Greenlight 管理员创建、BBB HTTP API 全链路验证(getMeetings/create/join/end)与数据持久化实测,并给出镜像选型、服务清单、资源占用、等价 docker run 与常见问题排障。全部命令与回显均在 Docker 29.9.2 + Compose v5.6.1 环境实测采集(2026-10-27),组件背景见《BigBlueButton 4.0.0 介绍与选型指南》。
一、环境信息
本文所有命令在以下环境实测:
- 服务器系统:Ubuntu 24.04(x86_64,内核 7.0.0-38-generic)
- Docker:29.9.2(
docker --version→Docker version 29.9.2, build 7c95437) - Docker Compose:v5.6.1(
docker compose version→Docker Compose version v5.6.1) - 编排项目:https://github.com/bigbluebutton/docker (master 分支,2026-10-27 克隆;README 自述「Docker version of BigBlueButton 3.0」「version: 3.0.39」,并注明「currently missing: livekit」——即该编排形态当前覆盖 3.0.39,尚未覆盖 4.0 的 LiveKit 媒体栈)
- 部署目录:
/opt/bbb-docker/(Compose 项目名bbb-3-0-39-stack) - 服务器 IP:10.89.58.3(EXTERNAL_IPv4 配置值,部署于独立隔离网段 10.89.58.0/24)
- Web 端口:80/443(haproxy 统一入口);内部端口 48081/48082/48083/48087 由 nginx 承载、8090 由 bbb-web 承载、5060/8021 由 FreeSWITCH 承载、3478 由 coturn 承载
⚠️ 版本说明:BigBlueButton 官方主推裸机一键安装(4.0.0 对应 Ubuntu 24.04 + bbb-install-4.0.sh),bigbluebutton/docker 是官方 GitHub 组织下的社区编排项目,其 README 明确自述为「not official supported way」(非官方支持形态)。本文选择 Compose 形态的原因与 4.0 容器化边界(LiveKit 组件未覆盖)见《BigBlueButton 4.0.0 介绍与选型指南》第七章。
二、镜像选型说明
bigbluebutton/docker 不是「单镜像」项目,而是把 BBB 裸机安装拆成一组官方自建镜像的编排(全部镜像来自 Docker Hub alangecker/ 命名空间,与仓库内各服务目录的 Dockerfile 对应,版本由仓库 repos/tags 缓存文件钉住):
| 服务 | 镜像/构建方式 | 说明 |
|---|---|---|
| bbb-web | alangecker/bbb-docker-bbb-web(TAG_BBB=v3.0.39) | BBB 核心(Grails API、会议管理) |
| freeswitch / webrtc-sfu | alangecker/bbb-docker-freeswitch、bbb-docker-webrtc-sfu | 语音混音与音视频转发(mediasoup) |
| nginx / haproxy | alangecker/bbb-docker-nginx、alangecker/bbb-docker-haproxy | nginx 只在内网监听(48081/48082 走 proxy_protocol),TLS 终结由 haproxy 承担 |
| greenlight | bigbluebutton/greenlight:v3 | 官方前端面板镜像 |
| postgres / redis | postgres:16、redis:6.2-alpine | Greenlight 元数据 / BBB 消息与状态 |
| etherpad 系列 | bbb-pads、bbb-export-annotations、bbb-shared-notes-server | 协作笔记与批注导出 |
| coturn | alangecker/bbb-docker-coturn | TURN/STUN 中继 |
| periodic | alangecker/bbb-docker-periodic | 定时清理任务 |
镜像 tag 钉版机制(实测):仓库克隆后执行 ./scripts/generate-compose,脚本读取 repos/tags(实测内容为 bigbluebutton v3.0.39)与 .env,把 docker-compose.tmpl.yml 模板渲染为 docker-compose.yml。因此版本切换 = 修改 repos/tags 或检出对应分支后重新生成,不手动改 compose 文件。
三、前置条件
- Ubuntu 22.04/24.04 服务器,root 权限,4 核 / 8 GB 内存以上(实测栈整机常驻内存约 2.5 GB,见 5.4 节);
- Docker 24+ 与 Compose v2 插件;
- 一个解析到服务器 IP 的域名(用于 HTTPS 证书与 Greenlight 房间链接);没有域名也可以按本文 4.3 节以「自签证书 + 关闭 Host 校验」的实验形态跑通;
- 端口放行:TCP 80/443(Web 入口)、TCP/UDP 3478 与 UDP 49152-65535(coturn 中继)、UDP 16384-32768(WebRTC 媒体);
- 服务器防火墙/安全组不得占用上述端口(haproxy 绑定 0.0.0.0:80/443)。
四、部署步骤
4.1 安装 Docker 并克隆编排仓库
# 安装 Docker(Ubuntu 24.04 实测回显)
apt-get update && apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
docker --version
实测回显:
Docker version 29.9.2, build 7c95437
git clone --depth 1 https://github.com/bigbluebutton/docker.git /opt/bbb-docker
cd /opt/bbb-docker
git log -1 --format="%H %cs"
实测回显:
e7571f4b3ed6e07c5cf6d7a0dea32f448432c94b 2026-10-18
4.2 编写 .env 并生成编排文件
从模板创建 .env(sample.env → .env),实测采用的核心内容如下(自签实验形态,SECRET 为实测生成的真实值):
ENABLE_HTTPS_PROXY=true
LETSENCRYPT_EMAIL=admin@example.com
ENABLE_GREENLIGHT=true
ENABLE_COLLABORA=false
ENABLE_COTURN=true
ENABLE_RECORDING=false
IGNORE_TLS_CERT_ERRORS=true
SHARED_SECRET=dQlqhNULhRDTwaPdKi2hXet1bihGeLqH0RDEXPOfEI
ETHERPAD_API_KEY=kE2mYvP8QrT4nW6bZ1xCj9Hs5aF0gLuD
RAILS_SECRET=Rt7Wq2ZkB9Xm4Nc6Vj1Pd8Hs3Fa0gLu5YeTr2Ow9Qk4
POSTGRESQL_SECRET=Pg9Xw4Rk2Zb8Nc5Vj1Md7Hs3Fa6gLu0
FSESL_PASSWORD=Fs8Xw3Rk6Zb9Nc4Vj2Pd7Hs5Fa1gLu
TURN_SECRET=Tn6Xw3Rk9Zb4Nc8Vj1Pd5Hs7Fa2gLu0
DOMAIN=bbb.example.com
EXTERNAL_IPv4=10.89.58.3
EXTERNAL_IPv6=
STUN_IP=216.93.246.18
STUN_PORT=3478
SIP_IP_ALLOWLIST=
DEFAULT_PRESENTATION=./mod/nginx/default.pdf
SOUNDS_LANGUAGE=en-us-callie
DISABLE_SOUND_MUTED=false
DISABLE_SOUND_ALONE=false
ENABLE_LEARNING_DASHBOARD=true
COMPOSE_PROJECT_NAME=bbb-3-0-39-stack
生成编排文件并启动:
cd /opt/bbb-docker
./scripts/generate-compose
docker compose up -d
实测要点:
generate-compose借助临时辅助镜像把模板渲染为docker-compose.yml(实测 455 行),.env 中COMPOSE_PROJECT_NAME=bbb-3-0-39-stack决定项目名——注意 Compose 项目名不允许点号,所以版本号 3.0.39 写作 3-0-39;- 首次
up -d拉取镜像约需数分钟(全部镜像合计约 3 GB)。
4.3 确认服务状态(17 服务全 Up)
docker compose ps --format "{{.Name}} {{.Status}}"
实测回显(按名称排序):
bbb-3-0-39-stack-apps-akka-1 Up 8 minutes
bbb-3-0-39-stack-bbb-export-annotations-1 Up 8 minutes
bbb-3-0-39-stack-bbb-graphql-actions-1 Up 8 minutes
bbb-3-0-39-stack-bbb-graphql-middleware-1 Up 8 minutes
bbb-3-0-39-stack-bbb-graphql-server-1 Up 8 minutes
bbb-3-0-39-stack-bbb-shared-notes-server-1 Up 7 minutes
bbb-3-0-39-stack-bbb-web-1 Up 8 minutes
bbb-3-0-39-stack-bbb-freeswitch-1 Up 8 minutes
bbb-3-0-39-stack-coturn-1 Up 8 minutes
bbb-3-0-39-stack-fsesl-akka-1 Up 8 minutes
bbb-3-0-39-stack-greenlight-1 Up 2 minutes
bbb-3-0-39-stack-haproxy-1 Up 8 minutes
bbb-3-0-39-stack-nginx-1 Up 8 minutes
bbb-3-0-39-stack-periodic-1 Up 8 minutes
bbb-3-0-39-stack-postgres-1 Up 8 minutes
bbb-3-0-39-stack-redis-1 Up 8 minutes
bbb-3-0-39-stack-webrtc-sfu-1 Up 8 minutes
⚠️ 实测踩坑:
bbb-shared-notes-server在首启时因 PostgreSQL 就绪竞态Exited(2),等栈稳定后单独执行docker compose up -d bbb-shared-notes-server即恢复 Up,这是编排健康检查的已知竞态,不是故障。
4.4 创建 Greenlight 管理员
Greenlight v3 提供 rake 任务直接建管理员(无 SMTP 时的标准做法):
cd /opt/bbb-docker
docker compose exec -T greenlight bin/rake admin:create[root,root@example.com,q1w2E3r4!]
实测回显:
Name: root
Email: root@example.com
Password: q1w2E3r4!
Role: Administrator
(另以 admin:create[admin,admin@example.com,q1w2E3r4!] 同法创建了演示管理员 admin@example.com。)
⚠️ 实测踩坑:Greenlight 密码策略要求至少 8 位且同时包含大小写字母、数字与特殊字符,纯数字弱口令(如
q1w2e3r4)会被拒绝(报错Password is invalid)。本文统一使用q1w2E3r4!。
4.5 Web 入口验证(含 Blocked hosts 排障)
curl -sk -o /dev/null -w "%{http_code}\n" -H "Host: bbb.example.com" https://127.0.0.1/
首次实测返回 403,Greenlight 日志显示 Rails 的 HostAuthorization 拦截(实测日志行):
Blocked hosts: 127.0.0.1 AND bbb.example.com
原因与处置:IGNORE_TLS_CERT_ERRORS=true 的自签形态下,Greenlight 以内部 HTTP 端点(http://10.7.7.34:48083/bigbluebutton/api)访问 API,而其 Host 白名单来自 URL_HOST=https://bbb.example.com,自签实验形态下两种 Host 均不在白名单。Greenlight 官方预留了 BYPASS_HOST 环境变量,新增 docker-compose.override.yml 关闭 Host 校验(生产形态使用真实域名 + Let's Encrypt 证书时无需此步):
services:
greenlight:
environment:
BYPASS_HOST: "true"
重建并复测:
docker compose up -d greenlight bbb-shared-notes-server
sleep 20
curl -sk -o /dev/null -w "greenlight -> %{http_code}\n" -H "Host: bbb.example.com" https://127.0.0.1/
curl -sk https://127.0.0.1/ -H "Host: bbb.example.com" | grep -oE "<title>[^<]+</title>"
实测回显:
greenlight -> 200
<title>BigBlueButton</title>
五、部署后验证
5.1 API 探活与校验和算法(重要)
BBB 3.0 起 HTTP API 的 checksum 拼接口径与 2.x 不同:新版为 sha256(action + queryString + sharedSecret),queryString 不含 checksum 参数本身。用 2.x 老口径(sha1(action + secret + queryString))调用带参数的 API 会返回 ChecksumError: checksum match error——但无参数的 getMeetings 恰好两种口径等价,容易误判。本专栏实测过程即被此坑误导(服务端日志打印的 SHA1 值与本地计算不一致,穷举比对后确认为拼接顺序变化)。
正确口径的 API 探活实测:
S=dQlqhNULhRDTwaPdKi2hXet1bihGeLqH0RDEXPOfEI
B=https://127.0.0.1/bigbluebutton/api
C=$(printf %s "getMeetings${S}" | sha256sum | cut -d" " -f1)
curl -sk "$B/getMeetings?checksum=$C"
实测回显:
<response>
<returncode>SUCCESS</returncode>
<meetings/>
<messageKey>noMeetings</messageKey>
<message>no meetings were found on this server</message>
</response>
5.2 create / getMeetingInfo / join / end 全链路实测
S=dQlqhNULhRDTwaPdKi2hXet1bihGeLqH0RDEXPOfEI
B=https://127.0.0.1/bigbluebutton/api
api(){ local a=$1 q=$2; local c=$(printf %s "${a}${q}${S}" | sha256sum | cut -d" " -f1); curl -sk --max-time 15 "${B}/${a}?${q}&checksum=${c}"; }
# create(显式指定两个会议密码)
Q="attendeePW=q1w2e3r4Att&meetingID=doc-test-002&moderatorPW=q1w2e3r4Mod&name=%E5%AE%9E%E6%B5%8B%E4%BC%9A%E8%AE%AE%E5%AE%A4&welcome=Welcome+to+doc-test"
api create "$Q" | grep -E "returncode|meetingID>|moderatorPW|attendeePW|createDateTime"
# getMeetingInfo
api getMeetingInfo "meetingID=doc-test-002" | grep -E "returncode|meetingName|moderatorPW|running"
# join(curl 跟随 302 前先看跳转)
J="fullName=%E6%B5%8B%E8%AF%95%E7%94%A8%E6%88%B7&meetingID=doc-test-002&password=q1w2e3r4Mod&redirect=true"
c=$(printf %s "join${J}${S}" | sha256sum | cut -d" " -f1)
curl -sk -o /dev/null -w "join -> HTTP %{http_code} Location=%{redirect_url}\n" "${B}/join?${J}&checksum=${c}"
# end
api end "meetingID=doc-test-002&password=q1w2e3r4Mod" | grep -E "returncode|sentEnd"
实测回显:
<response>
<returncode>SUCCESS</returncode>
<meetingID>doc-test-002</meetingID>
<internalMeetingID>5f363f9ed2ef17e9216b7adb9630e1780cd678f5-1793066362694</internalMeetingID>
<parentMeetingID>bbb-none</parentMeetingID>
<attendeePW>q1w2e3r4Att</attendeePW>
<moderatorPW>q1w2e3r4Mod</moderatorPW>
<createTime>1793066362694</createTime>
<voiceBridge>450178364</voiceBridge>
<dialNumber>613-555-1234</dialNumber>
<createDate>Tue Oct 27 01:59:22 UTC 2026</createDate>
<hasUserJoined>false</hasUserJoined>
<duration>0</duration>
<hasBeenForciblyEnded>false</hasBeenForciblyEnded>
<messageKey></messageKey>
<message></message>
</response>
getMeetingInfo 与 join、end 的实测回显:
<returncode>SUCCESS</returncode>
<meetingName>实测会议室</meetingName>
<moderatorPW>q1w2e3r4Mod</moderatorPW>
<running>false</running>
join -> HTTP 302 Location=https://bbb.example.com/html5client/?sessionToken=takeairlvrgibxkq
<returncode>SUCCESS</returncode>
<messageKey>sentEndMeetingRequest</messageKey>
join 返回 302 跳转至 html5client 会话页(sessionToken 为实测真实值),说明会议与客户端会话签发链路正常;把该 URL 在浏览器中打开即为入会页面。浏览器端音视频的实际体验(拾音/摄像/屏幕共享)依赖 TURN 与本地设备权限,无法以 curl 完成自动化验证,本文如实标注此边界。
5.3 getMeetings 复查(end 后会议移除)
api getMeetings "" | grep -E "returncode|messageKey|message" | head -3
实测回显:
<returncode>SUCCESS</returncode>
<messageKey>noMeetings</messageKey>
<message>no meetings were found on this server</message>
5.4 资源占用实测
docker stats --no-stream --format "{{.Name}}\t{{.MemUsage}}" | sort
实测回显(核心项):
bbb-3-0-39-stack-bbb-web-1 753.9MiB
bbb-3-0-39-stack-apps-akka-1 389.1MiB
bbb-3-0-39-stack-fsesl-akka-1 306.5MiB
bbb-3-0-39-stack-webrtc-sfu-1 306MiB
bbb-3-0-39-stack-greenlight-1 142.3MiB
bbb-3-0-39-stack-bbb-graphql-server-1 213.4MiB
bbb-3-0-39-stack-freeswitch 50.68MiB
bbb-3-0-39-stack-postgres-1 75.1MiB
17 个服务常驻内存合计约 2.4 GB(不含媒体转发峰值),8 GB 服务器即可承载轻量使用。
六、数据持久化说明
- 持久化方式:bbb-docker 全部状态落在编排目录的
data/子目录(bind mount),实测du -sh data/为92M,包含bigbluebutton/(会议状态)、postgres/(Greenlight 数据)、greenlight/、redis/、freeswitch-meetings/、coturn/、haproxy/(证书)、mediasoup/八个子目录; - 重建保数据实测:
docker compose down && docker compose up -d全栈销毁重建后,查询 Greenlight 用户表:
docker compose exec -T postgres psql -U postgres -d greenlight -t -c "select email from users;"
实测回显(down 前后各执行一次,结果一致):
admin@example.com
即管理员账号与房间数据随 data/postgres/ 持久化,栈重建不丢失。注意:进行中的会议不跨重建保留(会议状态属运行时数据),end 后的录制产物路径与备份边界见《BigBlueButton 4.0.0 配置参数详解》第六章。
七、配置参数说明
- .env 是唯一配置入口:生成编排后修改参数应改 .env 并重新执行
./scripts/generate-compose+docker compose up -d(核心参数逐项解说与属性文件对照见《BigBlueButton 4.0.0 配置参数详解》); - 自签与正式证书:
IGNORE_TLS_CERT_ERRORS=true时 haproxy 启动脚本自签证书(实测证书 CN 为 DOMAIN 值);正式环境设为false并配置可达公网的DOMAIN与LETSENCRYPT_EMAIL,由 haproxy 自动向 Let's Encrypt 申请; - BBB 共享密钥:
.env的SHARED_SECRET即 API checksum 密钥,与裸机形态的bbb-conf --secret输出同源(裸机形态解说见 CLI 命令篇)。
八、配置文件挂载
| 挂载 | 说明 |
|---|---|
./data/ | 全部持久化数据(postgres/redis/greenlight/haproxy 证书/会议状态) |
./mod/nginx/default.pdf | 默认演示文稿(DEFAULT_PRESENTATION 指定) |
./docker-compose.override.yml | 本文 4.5 节的 Greenlight 环境变量补充(BYPASS_HOST) |
九、等价 docker run
BigBlueButton 是 17 个强耦合服务的编排栈(服务间通过固定编排网段 10.7.7.0/24 与宿主网络混合通信:bbb-web/freeswitch/webrtc-sfu 等使用 host 网络,nginx/greenlight 等使用编排网络固定 IP),逐服务手写等价 docker run 无实际运维价值,也极易错配环境注入。本文仅给出栈中结构最简单的 redis 服务的等价单命令(参数取自生成的 docker-compose.yml,仅作编排原理说明):
docker run -d --name redis \
--network bbb-3-0-39-stack_bbb-net --ip 10.7.7.11 \
-v /opt/bbb-docker/data/redis:/data \
redis:6.2-alpine
⚠️ 该命令仅用于理解编排结构,请勿与
docker compose up -d混用(同名网络/IP 冲突)。
十、常用运维命令
cd /opt/bbb-docker
docker compose ps # 服务状态
docker compose logs -f bbb-web # 跟看 BBB 核心日志
docker compose restart bbb-web # 重启单个服务(改完 .env 后)
docker compose down && docker compose up -d # 全栈重建(数据在 data/ 持久化)
docker compose exec -T postgres psql -U postgres -d greenlight -t -c "select email from users;" # Greenlight 用户查询
十一、常见问题(FAQ)
Q1:API 调用报 ChecksumError: checksum match error?
BBB 3.0 起校验和为 sha256(action + queryString + sharedSecret),不是 2.x 的 sha1(action + secret + queryString);无参数的 getMeetings 两者等价,带参数接口必须用新口径(见 5.1 节实测过程)。
Q2:Greenlight 页面 403,日志出现 Blocked hosts?
Rails HostAuthorization 拦截了请求 Host。生产形态用真实域名 + Let's Encrypt 证书(IGNORE_TLS_CERT_ERRORS=false)即可匹配 URL_HOST;无域名的实验形态按 4.5 节加 BYPASS_HOST: "true"。
Q3:bbb-shared-notes-server 启动即退出?
PostgreSQL 就绪竞态,docker compose up -d bbb-shared-notes-server 单独拉起即可(4.3 节实测)。
Q4:admin:create 报 Password is invalid?
密码需同时包含大小写字母、数字、特殊字符且 ≥8 位(4.4 节实测)。
Q5:能部署 BigBlueButton 4.0.0 吗? 截至 2026-10-27,bigbluebutton/docker 主线覆盖 3.0.39,4.0 的 LiveKit 媒体栈未纳入编排(README 自述 currently missing: livekit);4.0 请用官方裸机一键脚本(Ubuntu 24.04),见选型指南第七章。
Q6:TURN 中继通了吗? 本文实测范围内 coturn 服务 Up、TURN_SECRET 已注入并随栈启动;跨运营商/对称 NAT 场景下的外网中继连通性依赖公网安全组与证书,超出本文实测边界,如实标注未验证。
十二、k8s 形态简介
本专栏本批次以 Compose 形态实测交付;BigBlueButton 在 Kubernetes 上的部署形态现状如下(2026-10-27 官方文档实查,本篇未做 k8s 实测):
- 官方未提供 k8s 编排:官方安装文档主线是裸机一键脚本,「Other installation options」章节列出的是社区维护的安装方式(Ansible 角色、含 Scalelite 的大规模 HA 方案等),未见官方 Helm chart 或官方 k8s 清单;
- 官方规模化路径:多台裸机 BBB 服务器 + Scalelite 负载均衡器调度(官方另有 Cluster Proxy 集群代理方案文档),k8s 并非官方推荐的承载形态;
- 社区 chart:第三方仓库存在以 Helm chart/清单形式编排 BBB 的尝试,成熟度与维护状态参差,采用前需自行评估(本文不列出未经实测验证的具体仓库);
- 后续实测计划:k8s 形态(含社区 chart 可用性)由本专栏 K1 批次另行实测交付,本篇不实测 k8s。
十三、参考链接
- bigbluebutton/docker 编排仓库(README 含 .env 参数全集):https://github.com/bigbluebutton/docker
- sample.env 参数模板:https://github.com/bigbluebutton/docker/blob/master/sample.env
- BigBlueButton 官方文档(裸机安装对照):https://docs.bigbluebutton.org
- Greenlight 文档:https://docs.bigbluebutton.org/greenlight/overview
- 本专栏配套篇目:《BigBlueButton 4.0.0 介绍与选型指南》、《BigBlueButton 4.0.0 配置参数详解》、《BigBlueButton 4.0.0 常用 CLI 命令与工具详解》