mysamimi/rtmp-http-tunnel
GitHub: mysamimi/rtmp-http-tunnel
该工具通过将本地 RTMP 流拆分为混淆的 HLS 分段并经 HTTPS 并发上传至远程服务器进行缓冲重构,来解决受限网络下直播推流遭遇限速、丢包和封锁的问题。
Stars: 0 | Forks: 0
# rtmp-http-tunnel
`rtmp-http-tunnel` 是一个使用 Go 语言编写的轻量级、高弹性的开源流媒体中继工具。它旨在绕过在向 YouTube、Twitch 或 Aparat 等平台进行直播推流时遇到的网络限速、深度包检测 (DPI) 以及高抖动网络环境(例如受限的网络连接)。
## 问题所在
标准的 RTMP 推流通过单一且持久的 TCP 连接(通常是 1935 端口)进行。在不稳定或受到严格审查的网络中,这种单一连接很容易被限速、遭受丢包(导致推流断开)或完全被防火墙阻止。此外,网络绑定(结合多个 WAN 连接)也无法轻易地动态分发单一的原始 RTMP 流。
## 解决方案
`rtmp-http-tunnel` 通过将您的本地 RTMP 流拆分为小型的、经过混淆的 HLS 分段(通常每个 2 秒),并使用工作池通过安全的 HTTPS(443 端口)并发上传它们,从而解决了这个问题。
远程服务器对这些分段进行缓冲(例如 60 秒)以吸收丢包和网络抖动,然后按顺序重构它们,最后通过管道将其作为连续的 RTMP 流重新导向 YouTube/Twitch。
```
+----------+ +-------------------------+ +-------------------------+ +-----------------+
| OBS / | RTMP | Local Client | HTTPS | Remote Server | RTMP | YouTube/Twitch |
| Encoder | -------> | (RTMP Ingest -> Chunks) | =======> | (Jitter Buffer -> RTMP) | -------> | Ingest Server |
+----------+ (Port +-------------------------+ POSTs +-------------------------+ (Port +-----------------+
1935) (Port 1935)
443)
```
## 功能
- **多流支持(多客户端与多服务器):** 通过将多个独立的流路由到动态路径 endpoint(例如 `/s/stream_abc/upload`),可以在同一服务器端口上同时进行中继。
- **智能过期策略:** 客户端会查询服务器的 `/health` endpoint 以动态发现缓冲持续时间配置。如果本地分块超过了服务器窗口期,客户端会在本地将其丢弃(并避免上传),从而节省带宽。
- **后台非活跃会话清理:** 服务器运行一个后台例程,安全地终止非活跃的流媒体会话进程,释放端口、docker 容器,并清理临时磁盘资产。
- **Docker 化的 FFmpeg 集成:** 在轻量级容器内运行视频处理。如果 Docker 可用,则无需在客户端或服务器上安装和配置本地 FFmpeg 构建版本。
- **并发分块上传:** 利用工作池并行上传分段,自然地利用多连接负载均衡器或软件网络绑定。
- **防 DPI 的 XOR 混淆:** 在应用层使用简单密钥对分块字节进行加扰,以绕过针对视频头的深度包检测 (DPI)。
- **MPEG-TS 完整性验证:** 在抵达时自动验证解密的数据包,如果存在 `obfuscation_key` 不匹配的情况,会立即向您发出警告。
- **抗弹性抖动缓冲:** 在将分块馈送至接收平台之前,服务器会缓冲一个可配置的滑动窗口(例如 60 秒),能够吸收长达 60 秒的完全客户端断开连接,且不会中断目标推流。
- **优雅关闭:** 实现了适当的 OS 信号捕获。通过 `Ctrl+C` 关闭客户端或服务器会立即停止子进程,关闭 HTTP 监听器,释放端口,并干净地终止 Docker 容器。
## 环境要求
- **Go**(1.20 或更高版本)
- **选项 A(推荐):** 在客户端和服务器机器上均运行 **Docker**(应用程序将自动管理 `linuxserver/ffmpeg` 容器)。
- **选项 B(原生):** 在两台机器上均已安装 **FFmpeg** 并添加到 PATH 中。注意:在客户端,您的 FFmpeg 构建版本必须支持 RTMP 监听(`-listen 1`)。启用了 `librtmp` 的 FFmpeg 构建可能无法监听;建议使用标准的 Homebrew 或 Linux 软件包管理器构建版本。
## 配置
将 `config.json.example` 复制为 `config.json` 并调整参数:
```
{
"mode": "client",
"client": {
"server_url": "https://your-server-ip:8443",
"auth_token": "a-strong-random-shared-secret-token",
"obfuscation_key": "some-secret-xor-obfuscation-key",
"concurrency": 4,
"chunk_duration": 2,
"use_docker": true,
"docker_image": "linuxserver/ffmpeg",
"max_upload_retries": 5,
"streams": [
{
"stream_path": "stream_abc123",
"input_url": "rtmp://0.0.0.0:1935",
"temp_dir": "./tmp_client/stream_abc123"
},
{
"stream_path": "stream_xyz456",
"input_url": "srt://0.0.0.0:9000",
"temp_dir": "./tmp_client/stream_xyz456"
}
]
},
"server": {
"listen_addr": ":8443",
"auth_token": "a-strong-random-shared-secret-token",
"obfuscation_key": "some-secret-xor-obfuscation-key",
"buffer_duration": 60,
"rebuffer_duration": 4,
"chunk_duration": 2,
"inactive_session_timeout": 120,
"tls_cert_file": "/etc/letsencrypt/live/your-server-ip/fullchain.pem",
"tls_key_file": "/etc/letsencrypt/live/your-server-ip/privkey.pem",
"use_docker": true,
"docker_image": "linuxserver/ffmpeg",
"streams": [
{
"path": "stream_abc123",
"target_rtmp_url": "rtmp://a.rtmp.youtube.com/live2/key-for-stream-1",
"temp_dir": "./tmp_server/stream_abc123"
},
{
"path": "stream_xyz456",
"target_rtmp_url": "rtmp://a.rtmp.youtube.com/live2/key-for-stream-2",
"temp_dir": "./tmp_server/stream_xyz456"
}
]
}
}
```
### 关键参数:
- `"concurrency"`:每个客户端流的并发 HTTP 上传工作线程数。
- `"max_upload_retries"`:客户端在跳过/丢弃某个分块前尝试上传的次数。
- `"inactive_session_timeout"`:服务器端非活动超时时间(秒)。如果在此持续时间内未收到某个流的上传分块,服务器将终止其流媒体进程并进行清理。
- `"auth_token"`:必需的共享 bearer token。客户端和服务器端的值必须匹配。
- `"obfuscation_key"`:必需的共享 XOR 密钥。客户端和服务器端的值必须匹配。
- `"buffer_duration"` 和 `"chunk_duration"`:在服务器上,`buffer_duration` 必须大于 `chunk_duration`;否则服务器将拒绝启动。
- `"rebuffer_duration"`:在流已经启动一次后的可选快速恢复缓冲区。省略时默认约为两个分块。将其设置为较小的值(如 `4`)可以在客户端重启后快速恢复,同时保持较大的初始 `buffer_duration`。
- `"streams"`(客户端):本地流处理 pipeline 数组,定义:
- `"stream_path"`:服务器路由标识符(`/s/{stream_path}/upload`)。
- `"input_url"`:通用输入 URL。支持的格式:
- RTMP(监听器):`rtmp://0.0.0.0:1935`(零 IP 主机绑定监听器)
- RTMP(拉取/连接):`rtmp://192.168.1.100:1935/live/app`
- SRT(监听器):`srt://0.0.0.0:9000`(自动追加 `?mode=listener`)
- SRT(呼叫者/拉取):`srt://192.168.1.100:9000`(自动追加 `?mode=caller`)
- UDP(监听器):`udp://0.0.0.0:1234`(自动追加 `?listen`)
- UDP(多播拉取):`udp://239.1.1.1:1234`
- HTTP/HLS:`http://example.com/stream.m3u8`
- `"temp_dir"`:本地化分块资产的路径。
- `"streams"`(服务器):静态注册路径定义的数组。
- `"path"`:预期的 URL 路由标识符。
- `"target_rtmp_url"`:出站 RTMP 接收服务器(例如 YouTube RTMP URL + 密钥)。
- `"temp_dir"`:本地化服务器缓冲分块的路径。
### 启动验证
应用程序需要有效的配置文件。如果 `config.json` 缺失或无效,启动将会失败,而不会回退到不安全的默认设置。
验证检查包括:
- `mode` 必须是 `client` 或 `server`(或使用 `-mode` 覆盖)。
- 客户端的 `server_url` 必须是 `http` 或 `https`。
- `auth_token`、`obfuscation_key`、流路径、输入 URL、目标 URL 和临时目录必须存在。
- 流路径只能包含字母、数字、`.`、`_` 和 `-`;不允许使用斜杠,因为路径会用于 `/s/{stream_path}/...` 路由。
- 流路径在所选的客户端或服务器配置中必须唯一。
- TLS 证书和密钥路径必须成对配置。
## 使用方法
### 1. 运行服务器(VPS / 数据中心)
确保您的防火墙允许监听端口(例如 `8443`)上的流量。运行:
```
go run main.go -mode server -config config.json
```
### 2. 运行客户端(本地机器)
运行客户端程序:
```
go run main.go -mode client -config config.json
```
### 3. 开始推流
将您的编码器(例如 OBS)配置为推流到它们各自的端口。
例如,对于第一个流:
- **服务器:** `rtmp://127.0.0.1:1935/live/app`
- **推流密钥:** (可留空或填入任意虚拟密钥)
对于第二个流:
- **服务器:** `rtmp://127.0.0.1:1936/live/app`
- **推流密钥:** (可留空或填入任意虚拟密钥)
OBS 开始推流后,客户端会将流进行分段、混淆,并将分块中继到 `/s/{stream_path}/upload`。服务器将它们隔离缓冲,并将重构后的流转发到匹配的 `target_rtmp_url`。
## 安全限制
- 上传请求限制每个分块最大 50 MB。过大的分块将被拒绝并返回 HTTP `413`,以确保不会静默接受损坏/被截断的媒体。
- 客户端会丢弃对服务器缓冲窗口而言过于陈旧的分块。如果服务器健康 endpoint 无法访问,客户端将使用保守的回退窗口。
- 建议在实际部署中使用 HTTPS。目前,客户端接受自签名的 TLS 证书以简化 VPS 设置,因此请确保 `auth_token` 足够强且保密。
## 故障排除
### 配置缺失或无效
如果启动失败并提示 `Invalid configuration`,请修复日志中指出的字段。应用程序不会使用占位符默认值运行。
### 解密警告
如果服务器记录了以下内容:
`[Receiver] WARNING: Decrypted chunk does not start with MPEG-TS sync byte (0x47, 'G')...`
这意味着服务器无法解密传入的分块。请仔细检查客户端和服务器配置中的 `"obfuscation_key"` 是否完全一致。
### 端口冲突
如果您收到 `port is already allocated` 或 `bind: address already in use` 错误:
- 在服务器上:停止后台运行的任何现有服务器进程:
killall rtmp-http-tunnel
- 在客户端(Docker)上:清理任何仍然占用该端口的孤立容器:
docker rm -f $(docker ps -a -q --filter name=rtmp-http-tunnel-client-)
标签:EVTX分析, Go语言, 抗丢包, 日志审计, 流媒体中继, 流量伪装, 程序破解, 网络穿透, 网络通信, 请求拦截