1. 前置条件
- 硬件:CPU ≥ 4 核,内存 ≥ 8 GB,硬盘 ≥ 50 GB(根据录像存储需求扩展)
- 操作系统:CentOS 7 / Ubuntu 20.04+(建议最新稳定版)
- 固定公网 IP:本文以
1.1.1.1为例,实际部署请替换 - 安装 Docker:
curl -fsSL https://get.docker.com | bash -s docker systemctl enable --now docker - 安装 b3sum(用于生成 Blake3 哈希):
# Ubuntu / Debian cargo install b3sum # 或使用预编译二进制下载 # 访问 https://github.com/BLAKE3-team/BLAKE3/releases - 准备安装包:将
gb.tar.gz、m.tar、zlm-node、MediaServer上传至服务器(如/root/install/)
2. 统一环境变量配置(.env)
所有 gbhub 服务(mgr、scheduler、sip)共用 /usr/local/gb/.env,systemd 通过 EnvironmentFile 加载。
⚠️ 重要说明(节点上报认证机制):
因此,
zlm-node 启动后会对 NODE_TOKEN 环境变量的值进行 Blake3 哈希,然后将哈希结果通过 X-Node-Token 请求头发送给 gbhub-mgr。因此,
gbhub-mgr 的 .env 中配置的 NODE_REPORT_TOKEN 应当是原始 NODE_TOKEN 的 Blake3 哈希值,而非原始字符串。
💡 如何生成 NODE_REPORT_TOKEN:
使用
使用
b3sum 工具计算原始 NODE_TOKEN 的 Blake3 哈希值:
# 将 your_secret_token_here 替换为实际的 NODE_TOKEN 值
echo -n "your_secret_token_here" | b3sum | awk '{print $1}'
命令拆解说明:
echo -n:去掉末尾换行符,确保哈希结果与代码中的计算方式完全一致。b3sum:计算标准输入内容的 Blake3 哈希值。awk '{print $1}':从输出中提取哈希值部分(去除文件名等额外信息)。
# 假设 NODE_TOKEN="my_secret"
echo -n "my_secret" | b3sum | awk '{print $1}'
# 输出类似:5d3f9e6c8f1a2b4c7d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c
将输出的哈希值填入下方 NODE_REPORT_TOKEN 字段。
mkdir -p /usr/local/gb
cat > /usr/local/gb/.env <<'EOF'
# ============================================================
# 国标视频平台 (gbhub) 环境配置
# ============================================================
# 数据库 (GreptimeDB / PostgreSQL)
DATABASE_URL=postgres://127.0.0.1:4003/public
# Redis 连接池配置
REDIS_URL=redis://127.0.0.1:6379?tcp_keepalive=60
REDIS_POOL_MAX_SIZE=16
REDIS_POOL_TIMEOUT_SECS=5
# SIP 信令监听地址
SERVER_LISTEN_ADDR=0.0.0.0:6060
SERVER_LISTEN_ADDR_TCP=0.0.0.0:6060
# 平台 SIP 标识
SERVER_DEVICE_ID=34020000002000000001
SERVER_REALM=3402000000
SERVER_PASSWORD=QSAe6780
# 公网 IP (用于 SIP/SDP)
PUBLIC_IP=1.1.1.1
# 管理服务器 (mgr-server) 监听地址
MGR_API_LISTEN=0.0.0.0:3002
# 信令服务器 (sip-server) HTTP 监听地址
SIP_API_LISTEN=0.0.0.0:3003
# Webhook 回调端口
HOOK_ENABLE=true
HOOK_PUBLIC_IP=127.0.0.1
HOOK_PORT=3003
# mgr-server 转发 SIP 请求的目标地址
SIP_API_BASE=http://127.0.0.1:3003
# JWT 认证
JWT_SECRET=6n5PVqybFTdWBUbpOPRvwEb6/q1PI1DhTqcmqqhenPo=
JWT_EXPIRE_DAYS=7
ADMIN_INIT_PASSWORD=admin123
# 内部服务通信(gbhub-mgr ↔ gbhub-sip)
INTERNAL_API_TOKEN=q123456778
PLAY_TOKEN=
PUBLISH_TOKEN=
# ============================================================
# 节点上报认证 Token(管理端校验用)
# 此值应为 zlm-node 中 NODE_TOKEN 原始值的 Blake3 哈希结果
# 使用命令生成:echo -n "your_secret_token" | b3sum | awk '{print $1}'
# ============================================================
NODE_REPORT_TOKEN=your_blake3_hash_here
EOF
3. 部署基础服务(Docker 容器)
3.1 导入 MediaServer 镜像
docker load -i m.tar
3.2 启动 Valkey(缓存)
docker run -d --network host --name valkey \
-e VALKEY_EXTRA_FLAGS='--save 60 1 --loglevel warning --rdbcompression no' \
-v /data/valkey:/data \
valkey/valkey
3.3 启动 GreptimeDB(时序数据库)
docker run -d --network host \
-v "/data/greptimedb_data:/greptimedb_data" \
--name greptime \
greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/greptimedb:v1.1.4 \
standalone start \
--http-addr 127.0.0.1:4000 \
--grpc-bind-addr 127.0.0.1:4001 \
--mysql-addr 127.0.0.1:4002 \
--postgres-addr 127.0.0.1:4003
3.4 部署并配置 MediaServer(ZLMediaKit)
先运行生成默认配置,再修改重启
3.4.1 准备目录和二进制
mkdir -p /data/m
mv MediaServer /data/m/
3.4.2 首次启动生成默认配置
docker run -d --network host --name me \
-v /data/m:/app/m \
m /app/m/MediaServer -l 4
sleep 5
docker stop me
3.4.3 修改 /data/m/config.ini
cd /data/m
sed -i 's/mediaServerId=.*/mediaServerId=1/g' config.ini
sed -i 's/port=8000/port=9100/g' config.ini
sed -i 's/tcpPort=8000/tcpPort=9100/g' config.ini
sed -i 's/externIP=.*/externIP=/g' config.ini # 留空自动获取,也可手动指定公网IP
sed -i 's/port=80/port=9080/g' config.ini
sed -i 's/port=443/port=9443/g' config.ini
sed -i 's/secret=.*/secret=935v73f7-bb6b-4889-a715-d9eb2d1936aa/g' config.ini
3.4.4 重启容器
docker start me
3.5 部署 zlm-node(ZLM 节点上报程序)
mkdir -p /usr/local/zlm
mv zlm-node /usr/local/zlm/
chmod +x /usr/local/zlm/zlm-node
4. 部署 GB28181 核心服务
cd /usr/local
tar -xf gb.tar.gz
cd gb
获取机器码并申请授权:
./gbhub-mgr # 打印 Machine ID,将授权文件 license.lic 放入 /usr/local/gb/
授权文件未放入前,服务启动会因 license 无效而退出。
5. 配置 systemd 服务(加载 .env)
5.1 gbhub-mgr(管理服务)
创建 /etc/systemd/system/gbhub-mgr.service:
[Unit]
Description=GB28181 Management Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/usr/local/gb
EnvironmentFile=/usr/local/gb/.env
ExecStart=/usr/local/gb/gbhub-mgr
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=gbhub-mgr
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now gbhub-mgr.service
5.2 gbhub-scheduler(调度服务)
创建 /etc/systemd/system/gbhub-scheduler.service(内容类似,ExecStart 改为 gbhub-scheduler,Environment="RUST_LOG=warn" 可加在 [Service] 段),然后启动。
5.3 gbhub-sip(SIP 信令服务)
创建 /etc/systemd/system/gbhub-sip.service(内容类似,ExecStart 改为 gbhub-sip),然后启动。
5.4 zlm-node(ZLM 节点上报程序)
创建 /etc/systemd/system/zlm-node.service,所有环境变量名均与 Rust 代码中的 Config 结构体字段对应(大写)。
⚠️ 认证机制说明:
程序启动后会读取
因此,请务必保证
程序启动后会读取
NODE_TOKEN 的原始字符串值,计算其 Blake3 哈希,然后将哈希值放入请求头 X-Node-Token 中上报。因此,请务必保证
NODE_TOKEN 的原始值,与 /usr/local/gb/.env 中 NODE_REPORT_TOKEN 的哈希值相匹配。
[Unit]
Description=zlm-node (ZLM Node Reporter)
After=network.target
[Service]
Type=simple
EnvironmentFile=/usr/local/gb/.env
# ---------- 日志级别 ----------
Environment="RUST_LOG=warn"
# ---------- 必填:节点上报原始认证令牌 ----------
# 此值为原始字符串(明文),程序内部会计算 Blake3 哈希后发送
# 务必与 .env 中 NODE_REPORT_TOKEN 的哈希值匹配
Environment="NODE_TOKEN=your_secret_token_here"
# ---------- 节点标识(必须与 MediaServer 的 mediaServerId 一致) ----------
Environment="SERVER_ID=1"
# ---------- ZLM API 地址及密钥 ----------
Environment="API_BASE=http://127.0.0.1:9080"
Environment="SECRET=935v73f7-bb6b-4889-a715-d9eb2d1936aa"
# ---------- 管理端上报接口 ----------
Environment="MGR_URL=http://127.0.0.1:3002/api/zlm/report-status"
# ---------- IP 获取策略(优先级:CUSTOM_IP > INTERFACE > 外网API) ----------
# 1. 手动指定公网 IP(取消注释并填写实际IP)
# Environment="CUSTOM_IP=1.1.1.1"
# 2. 指定网卡名称(如 eth0)
# Environment="INTERFACE=eth0"
# 3. 以上均不设置,则自动通过外网API获取(ip.3322.net / ip.automate.org.cn)
# ---------- 播放地址构造参数 ----------
Environment="ZLM_HTTP_PORT=9080"
Environment="USE_HTTPS=false"
# ---------- 可选:手动指定 http_fmp4_base 或 static_base ----------
# Environment="HTTP_FMP4_BASE=https://custom-domain.com:9443/"
# Environment="STATIC_BASE=http://cdn.example.com/"
# ---------- 上报间隔(秒) ----------
Environment="REPORT_INTERVAL_SECS=30"
# ---------- 是否自动更新 ZLM 的 rtc.externIP(默认 true) ----------
Environment="ENABLE_RTC_EXTERN_IP_UPDATE=true"
# ---------- 是否接受无效 TLS 证书(自签名场景) ----------
# Environment="TLS_ACCEPT_INVALID_CERTS=false"
ExecStart=/usr/local/zlm/zlm-node
Restart=always
PrivateTmp=true
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now zlm-node.service
6. 验证服务状态
systemctl status gbhub-mgr gbhub-scheduler gbhub-sip zlm-node
docker ps | grep -E "valkey|greptime|me"
查看 zlm-node 日志(观察上报及 IP 获取情况):
journalctl -u zlm-node -f
7. 防火墙与端口开放(iptables / nftables)
需开放以下端口(根据实际访问需求调整):
| 服务 | 端口 | 协议 | 说明 |
|---|---|---|---|
| gbhub-sip (SIP) | 6060 | UDP/TCP | SIP 信令 |
| MediaServer (HTTP API) | 9080 | TCP | ZLM HTTP API / Web 页面 |
| MediaServer (HTTPS API) | 9443 | TCP | ZLM HTTPS API / Web 页面 |
| MediaServer (RTP 控制) | 9100 | TCP | RTP 控制端口 |
| MediaServer (RTP 媒体流) | 30000-35000 | UDP/TCP | RTP 媒体传输端口范围 |
| gbhub-mgr API | 3002 | TCP | 管理后台 API |
| gbhub-sip HTTP API | 3003 | TCP | SIP HTTP 接口 / Webhook |
数据库(6379、4000-4003)和 Valkey 端口建议仅监听本地,不对外暴露。
7.1 使用 iptables(CentOS 7 / 传统系统)
# 开放 SIP 信令
iptables -A INPUT -p udp --dport 6060 -j ACCEPT
iptables -A INPUT -p tcp --dport 6060 -j ACCEPT
# 开放 MediaServer API
iptables -A INPUT -p tcp --dport 9080 -j ACCEPT
iptables -A INPUT -p tcp --dport 9443 -j ACCEPT
# 开放 RTP 控制端口
iptables -A INPUT -p tcp --dport 9100 -j ACCEPT
# 开放 RTP 媒体流端口范围(UDP 和 TCP)
iptables -A INPUT -p udp --dport 30000:35000 -j ACCEPT
iptables -A INPUT -p tcp --dport 30000:35000 -j ACCEPT
# 开放管理 API
iptables -A INPUT -p tcp --dport 3002 -j ACCEPT
iptables -A INPUT -p tcp --dport 3003 -j ACCEPT
# 保存规则(CentOS 7)
service iptables save
# 或 iptables-save > /etc/sysconfig/iptables
7.2 使用 nftables(Ubuntu 20.04+ / 现代发行版)
# 添加规则(临时生效)
nft add rule inet filter input udp dport 6060 accept
nft add rule inet filter input tcp dport 6060 accept
nft add rule inet filter input tcp dport 9080 accept
nft add rule inet filter input tcp dport 9443 accept
nft add rule inet filter input tcp dport 9100 accept
nft add rule inet filter input udp dport 30000-35000 accept
nft add rule inet filter input tcp dport 30000-35000 accept
nft add rule inet filter input tcp dport 3002 accept
nft add rule inet filter input tcp dport 3003 accept
# 持久化保存(Ubuntu)
nft list ruleset > /etc/nftables.conf
systemctl enable nftables
若在云平台(如阿里云、腾讯云、AWS)部署,还需在安全组/防火墙策略中放行相应端口。
8. 常见问题及解决
- 授权失败:确认
license.lic已放入/usr/local/gb/,机器码匹配。 - zlm-node 上报 401(认证失败):
1. 检查/usr/local/gb/.env中的NODE_REPORT_TOKEN是否为NODE_TOKEN的 Blake3 哈希值。
2. 确认两边的值完全一致(注意没有换行符等)。
3. 使用命令重新生成哈希值进行比对:echo -n "your_secret_token_here" | b3sum | awk '{print $1}' - b3sum 命令未找到:安装 Rust 后执行
cargo install b3sum,或从 官方 Releases 下载预编译二进制。 - 自动获取公网 IP 失败:手动设置
CUSTOM_IP。 - MediaServer 端口冲突:修改
config.ini中端口,并同步修改 zlm-node 的API_BASE及ZLM_HTTP_PORT。 - rtc.externIP 更新失败:确认
API_BASE和SECRET正确,且ENABLE_RTC_EXTERN_IP_UPDATE=true。 - RTP 媒体流不通:确认防火墙已开放 UDP/TCP 端口范围
30000-35000。
9. 卸载清理
systemctl stop gbhub-mgr gbhub-scheduler gbhub-sip zlm-node
systemctl disable gbhub-mgr gbhub-scheduler gbhub-sip zlm-node
rm -f /etc/systemd/system/gbhub-*.service /etc/systemd/system/zlm-node.service
docker rm -f valkey greptime me
rm -rf /usr/local/gb /usr/local/zlm /data/valkey /data/greptimedb_data /data/m
docker rmi m valkey/valkey greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/greptimedb:v1.1.4
10. 环境变量速查表(zlm-node)
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
NODE_TOKEN | 上报原始令牌(明文,程序内部会计算 Blake3 哈希后发送) | 是 | 无 |
NODE_REPORT_TOKEN | 管理端 .env 中配置的预期哈希值(应为 NODE_TOKEN 的 Blake3 结果) | 是(在 .env 中) | 无 |
SERVER_ID | 节点 ID(与 mediaServerId 一致) | 是 | "1" |
API_BASE | ZLM HTTP API 地址 | 是 | http://127.0.0.1:9080 |
SECRET | ZLM API 密钥 | 是 | 935v73f7-bb6b-4889-a715-d9eb2d1936aa |
MGR_URL | 管理端上报接口 | 是 | http://127.0.0.1:3002/api/zlm/report-status |
CUSTOM_IP | 手动指定公网 IP(最高优先级) | 否 | 自动获取 |
INTERFACE | 指定网卡名称 | 否 | 无 |
ZLM_HTTP_PORT | ZLM HTTP 端口(拼接 URL) | 否 | 9080 |
USE_HTTPS | 是否使用 HTTPS 构造播放地址 | 否 | false |
HTTP_FMP4_BASE | 手动指定 http_fmp4_base | 否 | 自动生成 |
STATIC_BASE | 手动指定静态资源基地址 | 否 | 与 http_fmp4_base 相同 |
REPORT_INTERVAL_SECS | 上报间隔(秒) | 否 | 30 |
ENABLE_RTC_EXTERN_IP_UPDATE | 自动更新 ZLM 的 rtc.externIP | 否 | true |
TLS_ACCEPT_INVALID_CERTS | 接受无效 TLS 证书 | 否 | false |
RUST_LOG | 日志级别(info/warn/debug) | 否 | 程序默认 info |