一个完整的直播平台:Rust 后端 + MediaMTX + SRT 推流中继 + WHEP 播放 + 观众登录 + 主题化管理端与观众端。
- 观众端为首页(
/),支持 WHEP/HLS 播放与实时弹幕。 - 管理端(
/admin.html)用于推流配置、链路监控、SMTP 等管理操作。 - MediaMTX 鉴权代理(推流/播放 Token)。
- 内置 SRT 监听/转发,方便本地推流测试。
- Rust 服务端支持 Linux、Windows、macOS 构建与发行。
- 观众账号系统 + 邮箱验证码。
- Turnstile 人机验证。
- 观众邮箱防盗刷(一次性注册令牌 + 频率限制)。
- 可选 Cloudflare Access 管理端二次鉴权。
- 创建 MySQL 数据库
live_streaming。 - 复制
.env.example→.env并填写。 - 启动后端:
cd server-rust
cargo run- 启动前端:
npm run dev- 访问:
- 观众端:
http://localhost:5173/ - 管理端:
http://localhost:5173/admin.html
服务端可在 Linux、Windows、macOS 上运行。以下为通用部署流程,平台细节见 docs/server-platforms.md。
- 安装依赖:
- Rust(stable,源码构建时需要)
- MySQL
- MediaMTX
- FFmpeg(使用直播封面或剪辑功能时需要)
- 创建数据库:
- 数据库名:
live_streaming
- 数据库名:
- 配置环境变量:
- 复制
.env.example→.env - 根据实际域名/端口修改(重点:
PORT、BIND_HOST、MEDIAMTX_*、TURNSTILE_SECRET)
- 复制
- 构建后端:
cd server-rust
cargo build --release- 启动(示例):
./target/release/server-rustWindows PowerShell:
.\target\release\server-rust.exe-
反向代理(可选,但推荐):
/api与/ws反代到后端PORT/live/stream/whep、/live/stream等播放路径可按需反代至 MediaMTX- 需透传
X-Forwarded-Proto,后端会根据它生成 HTTPS 播放地址
-
MediaMTX 鉴权:
- 在
mediamtx.yml中将鉴权回调指向POST /api/mediamtx/auth
- 在
-
端口建议:
- 后端:
5174 - MediaMTX WHEP:
8889 - MediaMTX HLS:
8888 - MediaMTX SRT:
8890
- 后端:
相对路径(如 CLIP_DIR、LIVE_DIR)均相对于服务端进程的工作目录。作为系统服务运行时建议使用绝对路径。
如需 systemd 启动服务,可将 server-rust 可执行文件放入固定路径,并在 service 中读取 .env。
假设后端部署在 /opt/meow-live:
[Unit]
Description=Meow Live Streaming Backend
After=network.target
[Service]
WorkingDirectory=/opt/meow-live/server-rust
ExecStart=/opt/meow-live/server-rust/target/release/server-rust
Restart=on-failure
RestartSec=3
EnvironmentFile=/opt/meow-live/.env
# 安全建议
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
[Install]
WantedBy=multi-user.target启用方式:
sudo systemctl daemon-reload
sudo systemctl enable meow-live
sudo systemctl start meow-live
sudo systemctl status meow-live假设 MediaMTX 放在 /opt/mediamtx,配置文件为 /opt/mediamtx/mediamtx.yml:
[Unit]
Description=MediaMTX Streaming Server
After=network.target
[Service]
WorkingDirectory=/opt/mediamtx
ExecStart=/opt/mediamtx/mediamtx
Restart=on-failure
RestartSec=3
# 如需指定配置文件:
# ExecStart=/opt/mediamtx/mediamtx /opt/mediamtx/mediamtx.yml
# 安全建议
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
[Install]
WantedBy=multi-user.target启用方式:
sudo systemctl daemon-reload
sudo systemctl enable mediamtx
sudo systemctl start mediamtx
sudo systemctl status mediamtxMYSQL_HOST,MYSQL_PORT,MYSQL_USER,MYSQL_PASSWORD,MYSQL_DATABASEADMIN_USER,ADMIN_PASSPORT(默认5174),BIND_HOST(默认0.0.0.0)WS_PATH(默认/ws)TOKEN_TTL_HOURSADMIN_TOKEN_MIN,ADMIN_REFRESH_DAYS(管理端刷新令牌有效期,分钟/天)ADMIN_LOGIN_WINDOW_SEC,ADMIN_LOGIN_IP_MAX,ADMIN_LOGIN_USER_MAX(管理端登录风控)VIEWER_TOKEN_DAYSTURNSTILE_SECRETPUBLIC_BASE_URL(用于通知里拼接直播地址 / 生成公开 URL)TELEGRAM_BOT_TOKENCHAT_FILTER_WORDSEMAIL_CODE_TTL_MIN,EMAIL_ECHOLIVE_COUNT_FALLBACK_SECS(直播开始时间缺失时的排行榜回退范围,秒)VIEWER_VERIFY_EMAIL_RATE_LIMIT_WINDOW_SECVIEWER_VERIFY_EMAIL_RATE_LIMIT_MAXVIEWER_VERIFY_EMAIL_RATE_LIMIT_EMAIL_MAXVIEWER_VERIFY_EMAIL_COOLDOWN_SECVIEWER_BLOCK_DISPOSABLE_EMAILVIEWER_BLOCK_EDU_GOV_EMAILVIEWER_REGISTER_TOKEN_TTL_SECSMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASS,SMTP_FROM,SMTP_REPLY_TO,SMTP_STARTTLSMEDIAMTX_API,MEDIAMTX_METRICS,MEDIAMTX_WEBRTC,MEDIAMTX_HLS,MEDIAMTX_PATH,MEDIAMTX_POLL_MSHLS_SEGMENT_DURATION_SECS,HLS_SEGMENT_COUNT,REPLAY_MAX_SECONDSCLIP_MIN_SECS,CLIP_MAX_SECS,CLIP_TTL_SECS,CLIP_DIR,CLIP_TMP_DIR,LIVE_DIR,FFMPEG_BINTHUMBNAIL_ENABLED,THUMBNAIL_INTERVAL_SECS,THUMBNAIL_SOURCECORS_ALLOWED_ORIGINS(跨域携带 Cookie 的允许域)COOKIE_SAMESITE,COOKIE_SECURESRT_ENABLED,SRT_LISTEN,SRT_FORWARD
VITE_API_BASE(后端 API 基础地址)VITE_WS_URL(可覆盖 WS 地址)
GET /api/streamGET /api/stream/statsGET /api/stream/healthGET /api/ingest/configGET /api/stream/ingestGET /api/stream/playGET /api/scheduleGET /api/channelsGET /api/ops/alertsGET /api/ingest/nodesGET /api/chat/latestGET /api/mediamtx/metrics
POST /api/admin/loginPOST /api/admin/stream/updatePOST /api/admin/stats/replacePOST /api/admin/health/replacePOST /api/admin/schedule/replacePOST /api/admin/channels/replacePOST /api/admin/ops/replacePOST /api/admin/nodes/replacePOST /api/admin/ingest/replacePOST /api/admin/room/createPOST /api/admin/smtp(保存 SMTP)GET /api/admin/smtp(读取 SMTP)POST /api/admin/smtp/test(测试邮件)GET /api/admin/telegram/channel(读取 Telegram 频道)POST /api/admin/telegram/channel(保存 Telegram 频道)GET /api/admin/viewer-anti-abuse(读取防盗刷配置)POST /api/admin/viewer-anti-abuse(保存防盗刷配置)
POST /api/viewer/loginPOST /api/viewer/register/tokenPOST /api/viewer/register/startPOST /api/viewer/register/verifyGET /api/viewer/meGET /api/viewer/profilePOST /api/viewer/profile
POST /api/chat/send(需要观众登录)
ws://localhost:5174/ws- 连接后发送
{ type: "snapshot", data: { ... } } - 更新推送:
stream:update,chat:new,ops:update等
MediaMTX 指向:
POST /api/mediamtx/auth
后端会校验 publish/read Token。
后端在 SRT_ENABLED=true 时监听 SRT_LISTEN(默认 0.0.0.0:9000)。
如果只使用 MediaMTX 自带的 SRT/RTMP/RTSP 推流,可设置 SRT_ENABLED=false。
可选转发:
SRT_FORWARD=srt://127.0.0.1:9001?mode=caller
- 推流 Token 会在首次启动时生成并持久化保存(重启不会改变)。
- 如需手动刷新推流 Key,可在管理端点击“刷新推流 Key”,或调用:
POST /api/admin/ingest/refresh
前端使用:
- Site Key:
TURNSTILE_SITE_KEY
后端需要:
TURNSTILE_SECRET
- 设置后端环境变量
TELEGRAM_BOT_TOKEN。 - 在管理端「Telegram 通知」里填写频道(支持
@channel、-100...、或https://t.me/xxx)。 - 触发直播状态/排期更新时,后端会推送消息到配置的频道。
- 管理端可配置通知标题、内容与直播地址。
- 支持占位符:
{title},{host},{roomId},{status},{time},{liveUrl},{scheduleTime},{scheduleTitle},{scheduleHost} - 支持规则匹配(正则)按需替换,规则里可用
$1等捕获组。
CHAT_FILTER_WORDS:用英文逗号分隔敏感词(大小写不敏感)。- 示例(中英混合):
傻逼,操你妈,色情,约炮,赌博,博彩,诈骗,引流,刷单,贷款,sex,porn,casino,scam
- Admin Bearer Token
CF-Access-Jwt-Assertion头(由 Cloudflare Access 注入)
Cloudflare Pages 不会读取 仓库里的 .env。请在:
Settings → Environment variables
配置 VITE_* 前缀变量。
CI工作流会构建前端,并在 Linux、Windows、macOS 上对 Rust 服务端运行格式检查、Clippy 和测试。Release Server工作流会在推送v*tag 时发布服务端发行包,也支持手动输入 tag 触发。- 发行产物包含
.env.example、服务端二进制、运行目录和平台文档:meow-live-server-linux-x64.tar.gzmeow-live-server-windows-x64.zipmeow-live-server-macos-universal.tar.gz
MIT
A full-stack live streaming platform with a Rust backend, MediaMTX integration, SRT ingest relay, WHEP playback, viewer login, and a themed admin + viewer UI.
- Viewer page as homepage (
/) with WHEP/HLS playback and realtime chat. - Admin console (
/admin.html) for stream config, ingest data, metrics, and SMTP settings. - MediaMTX auth proxy for publish/read tokens.
- Built-in SRT listener/relay for ingest testing.
- Rust backend builds and ships for Linux, Windows, and macOS.
- Viewer accounts with email verification.
- Turnstile verification for admin + viewer auth.
- Viewer email anti-abuse (one-time register token + rate limits).
- Optional Cloudflare Access for admin APIs.
- Create MySQL database
live_streaming. - Copy
.env.example→.envand update values. - Start backend:
cd server-rust
cargo run- Start frontend:
npm run dev- Visit:
- Viewer:
http://localhost:5173/ - Admin:
http://localhost:5173/admin.html
The backend runs on Linux, Windows, and macOS. Platform-specific notes are in docs/server-platforms.md.
- Install dependencies:
- Rust (stable, only when building from source)
- MySQL
- MediaMTX
- FFmpeg (only when thumbnails or clip creation are enabled)
- Create database:
- name:
live_streaming
- name:
- Configure environment:
- copy
.env.example→.env - update
PORT,BIND_HOST,MEDIAMTX_*,TURNSTILE_SECRET
- copy
- Build backend:
cd server-rust
cargo build --release- Run:
./target/release/server-rustWindows PowerShell:
.\target\release\server-rust.exe-
Reverse proxy (recommended):
- proxy
/apiand/wsto backendPORT - proxy
/live/stream/whepor other playback paths to MediaMTX if needed - pass
X-Forwarded-Protoso the backend can emit HTTPS playback URLs
- proxy
-
MediaMTX auth:
- set auth hook to
POST /api/mediamtx/auth
- set auth hook to
-
Suggested ports:
- backend:
5174 - MediaMTX WHEP:
8889 - MediaMTX HLS:
8888 - MediaMTX SRT:
8890
- backend:
Relative paths such as CLIP_DIR and LIVE_DIR are resolved from the backend process working directory. Prefer absolute paths for service-managed deployments.
If you use systemd, place the binary in a fixed path and load .env in the service unit.
Assuming the backend lives in /opt/meow-live:
[Unit]
Description=Meow Live Streaming Backend
After=network.target
[Service]
WorkingDirectory=/opt/meow-live/server-rust
ExecStart=/opt/meow-live/server-rust/target/release/server-rust
Restart=on-failure
RestartSec=3
EnvironmentFile=/opt/meow-live/.env
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl enable meow-live
sudo systemctl start meow-live
sudo systemctl status meow-liveAssuming MediaMTX is installed at /opt/mediamtx and config is /opt/mediamtx/mediamtx.yml:
[Unit]
Description=MediaMTX Streaming Server
After=network.target
[Service]
WorkingDirectory=/opt/mediamtx
ExecStart=/opt/mediamtx/mediamtx
Restart=on-failure
RestartSec=3
# If you want to specify the config file:
# ExecStart=/opt/mediamtx/mediamtx /opt/mediamtx/mediamtx.yml
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl enable mediamtx
sudo systemctl start mediamtx
sudo systemctl status mediamtxMYSQL_HOST,MYSQL_PORT,MYSQL_USER,MYSQL_PASSWORD,MYSQL_DATABASEADMIN_USER,ADMIN_PASSPORT(default5174),BIND_HOST(default0.0.0.0)WS_PATH(default/ws)TOKEN_TTL_HOURSADMIN_TOKEN_MIN,ADMIN_REFRESH_DAYSADMIN_LOGIN_WINDOW_SEC,ADMIN_LOGIN_IP_MAX,ADMIN_LOGIN_USER_MAXVIEWER_TOKEN_DAYSTURNSTILE_SECRETEMAIL_CODE_TTL_MIN,EMAIL_ECHOLIVE_COUNT_FALLBACK_SECSVIEWER_VERIFY_EMAIL_RATE_LIMIT_WINDOW_SECVIEWER_VERIFY_EMAIL_RATE_LIMIT_MAXVIEWER_VERIFY_EMAIL_RATE_LIMIT_EMAIL_MAXVIEWER_VERIFY_EMAIL_COOLDOWN_SECVIEWER_BLOCK_DISPOSABLE_EMAILVIEWER_BLOCK_EDU_GOV_EMAILVIEWER_REGISTER_TOKEN_TTL_SECSMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASS,SMTP_FROM,SMTP_REPLY_TO,SMTP_STARTTLSMEDIAMTX_API,MEDIAMTX_METRICS,MEDIAMTX_WEBRTC,MEDIAMTX_HLS,MEDIAMTX_PATH,MEDIAMTX_POLL_MSHLS_SEGMENT_DURATION_SECS,HLS_SEGMENT_COUNT,REPLAY_MAX_SECONDSCLIP_MIN_SECS,CLIP_MAX_SECS,CLIP_TTL_SECS,CLIP_DIR,CLIP_TMP_DIR,LIVE_DIR,FFMPEG_BINTHUMBNAIL_ENABLED,THUMBNAIL_INTERVAL_SECS,THUMBNAIL_SOURCECORS_ALLOWED_ORIGINS,COOKIE_SAMESITE,COOKIE_SECURESRT_ENABLED,SRT_LISTEN,SRT_FORWARD
VITE_API_BASE(API base URL)VITE_WS_URL(override WS endpoint)
GET /api/streamGET /api/stream/statsGET /api/stream/healthGET /api/ingest/configGET /api/stream/ingestGET /api/stream/playGET /api/scheduleGET /api/channelsGET /api/ops/alertsGET /api/ingest/nodesGET /api/chat/latestGET /api/mediamtx/metrics
POST /api/admin/loginPOST /api/admin/stream/updatePOST /api/admin/stats/replacePOST /api/admin/health/replacePOST /api/admin/schedule/replacePOST /api/admin/channels/replacePOST /api/admin/ops/replacePOST /api/admin/nodes/replacePOST /api/admin/ingest/replacePOST /api/admin/room/createPOST /api/admin/smtp(save SMTP)GET /api/admin/smtp(load SMTP)POST /api/admin/smtp/testGET /api/admin/telegram/channelPOST /api/admin/telegram/channelGET /api/admin/viewer-anti-abusePOST /api/admin/viewer-anti-abuse
POST /api/viewer/loginPOST /api/viewer/register/tokenPOST /api/viewer/register/startPOST /api/viewer/register/verifyGET /api/viewer/meGET /api/viewer/profilePOST /api/viewer/profile
POST /api/chat/send(viewer auth required)
ws://localhost:5174/ws- Sends snapshot on connect:
{ type: "snapshot", data: { ... } } - Broadcasts updates:
stream:update,chat:new,ops:update, etc.
Configure MediaMTX to call:
POST /api/mediamtx/auth
The backend validates token for publish/read actions.
The Rust backend listens on SRT_LISTEN (default 0.0.0.0:9000) when SRT_ENABLED=true.
Set SRT_ENABLED=false if you only use MediaMTX ingest.
Optional forward target:
SRT_FORWARD=srt://127.0.0.1:9001?mode=caller
- The publish token is generated once and persisted (it won’t change after restarts).
- To rotate it manually, click “刷新推流 Key” in the admin UI or call:
POST /api/admin/ingest/refresh
The frontend uses Cloudflare Turnstile with:
- Site Key:
TURNSTILE_SITE_KEY
The backend expects:
TURNSTILE_SECRETin environment
- Set
TELEGRAM_BOT_TOKENin the backend environment. - In the admin UI, fill the channel (
@channel,-100..., orhttps://t.me/xxx). - Live/schedule events will be sent to the configured channel.
- Admin Bearer Token
CF-Access-Jwt-Assertionheader (injected by Cloudflare Access)
Cloudflare Pages does not read .env from the repo. Set Vite variables in:
Settings → Environment variables
Use VITE_* prefixed vars only.
CIbuilds the frontend and runs Rust formatting, Clippy, and tests on Linux, Windows, and macOS.Release Serverpublishes backend packages when av*tag is pushed, and also supports manual dispatch with a tag.- Release assets include
.env.example, the server binary, runtime directories, and platform docs:meow-live-server-linux-x64.tar.gzmeow-live-server-windows-x64.zipmeow-live-server-macos-universal.tar.gz
MIT