How to Self-Host MediaMTX with Docker Compose
What Is MediaMTX?
MediaMTX (formerly rtsp-simple-server) is a zero-dependency real-time media server and proxy. It receives, publishes, and proxies video and audio streams using every major streaming protocol: RTSP, RTMP, HLS, WebRTC, SRT, and WHIP/WHEP. It’s written in Go, ships as a single binary, and requires no external dependencies. Use it to aggregate IP camera feeds, restream to multiple viewers, record streams, or convert between protocols. The project is actively maintained with frequent releases.
MediaMTX is not a media library like Jellyfin or Plex. It handles real-time streams — think security cameras, live broadcasts, and video ingestion — not stored media files.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 512 MB of RAM minimum (scales with concurrent streams)
- 5 GB of free disk space (more if recording streams)
- A domain name (optional, for remote WebRTC/HLS access)
Docker Compose Configuration
Create a mediamtx.yml configuration file:
# mediamtx.yml — main configuration
logLevel: info
logDestinations: [stdout]
# Protocol settings
rtsp: yes
rtspAddress: :8554
rtmp: yes
rtmpAddress: :1935
hls: yes
hlsAddress: :8888
webrtc: yes
webrtcAddress: :8889
# Recording (optional — uncomment to enable)
# record: yes
# recordPath: /recordings/%path/%Y-%m-%d_%H-%M-%S
# recordFormat: fmp4
# Authentication (optional — uncomment for basic auth)
# authMethod: internal
# authInternalUsers:
# - user: admin
# pass: changeme
# permissions:
# - action: publish
# path: ""
# - action: read
# path: ""
# - action: playback
# path: ""
# Paths — define named streams or let clients create them dynamically
paths:
all_others:
Create a docker-compose.yml file:
services:
mediamtx:
image: bluenviron/mediamtx:1.16.3
container_name: mediamtx
restart: unless-stopped
ports:
- "8554:8554" # RTSP
- "1935:1935" # RTMP
- "8888:8888" # HLS
- "8889:8889" # WebRTC
- "8890:8890/udp" # SRT
volumes:
- ./mediamtx.yml:/mediamtx.yml:ro
- mediamtx-recordings:/recordings
environment:
MTX_PROTOCOLS: tcp # RTSP transport (tcp recommended for Docker)
networks:
- mediamtx-net
volumes:
mediamtx-recordings:
networks:
mediamtx-net:
Start the server:
docker compose up -d
Initial Setup
MediaMTX starts accepting streams immediately. No web UI or login — it’s a protocol server.
Publish a Test Stream
Send a test stream using FFmpeg:
ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 \
-c:v libx264 -preset ultrafast -tune zerolatency \
-f rtsp rtsp://your-server-ip:8554/test
View the Stream
- RTSP:
rtsp://your-server-ip:8554/test(VLC, ffplay, or any RTSP client) - HLS:
http://your-server-ip:8888/test/(any web browser) - WebRTC:
http://your-server-ip:8889/test/(modern web browser) - RTMP:
rtmp://your-server-ip:1935/test(OBS, VLC)
Configuration
Protocol Reference
| Protocol | Port | Use Case |
|---|---|---|
| RTSP | 8554 | IP cameras, security systems, low-latency LAN streaming |
| RTMP | 1935 | OBS streaming, legacy encoders, live broadcast ingestion |
| HLS | 8888 | Web browser playback, CDN distribution, high compatibility |
| WebRTC | 8889 | Ultra-low latency browser playback (<500ms), interactive streams |
| SRT | 8890/udp | Reliable streaming over unreliable networks, broadcast-grade |
IP Camera Integration
Point your IP camera’s RTSP output at MediaMTX, or configure MediaMTX to pull from the camera:
# In mediamtx.yml
paths:
front_door:
source: rtsp://camera-user:[email protected]:554/stream1
sourceOnDemand: yes # Only connect to camera when someone is watching
backyard:
source: rtsp://camera-user:[email protected]:554/stream1
sourceOnDemand: yes
This proxies camera feeds through MediaMTX, converting them to any output protocol. View the front door camera in a browser at http://your-server-ip:8888/front_door/.
Stream Recording
Enable recording to save streams as MP4 files:
# In mediamtx.yml
record: yes
recordPath: /recordings/%path/%Y-%m-%d_%H-%M-%S
recordFormat: fmp4
recordSegmentDuration: 1h
Mount a volume for recordings in Docker Compose (already included in the configuration above).
Authentication
Add authentication to prevent unauthorized publishing or viewing:
# In mediamtx.yml
authMethod: internal
authInternalUsers:
- user: publisher
pass: strong-publish-password
permissions:
- action: publish
path: ""
- user: viewer
pass: strong-view-password
permissions:
- action: read
path: ""
Key Configuration Options
| Setting | Purpose | Default |
|---|---|---|
rtspAddress | RTSP listen address | :8554 |
rtmpAddress | RTMP listen address | :1935 |
hlsAddress | HLS listen address | :8888 |
webrtcAddress | WebRTC listen address | :8889 |
record | Enable stream recording | no |
sourceOnDemand | Only pull source when viewers connect | no |
readTimeout | Timeout for inactive readers | 10s |
Reverse Proxy
For remote WebRTC and HLS access with SSL:
- HLS: Forward port 8888 through your reverse proxy normally
- WebRTC: Requires UDP connectivity — configure STUN/TURN servers in
mediamtx.yml:
webrtcICEServers2:
- url: stun:stun.l.google.com:19302
See our Reverse Proxy Setup guide for details.
Backup
MediaMTX itself is stateless — the configuration file and recordings are all that matter:
| Data | Location |
|---|---|
| Configuration | ./mediamtx.yml (bind-mounted) |
| Recordings | mediamtx-recordings volume |
Back up the configuration file with your normal file backup. For recordings, back up the volume or mount it on persistent storage.
For a comprehensive strategy, see our Backup Strategy guide.
Troubleshooting
RTSP stream not connecting from IP camera
Symptom: Camera can’t reach MediaMTX, or stream doesn’t appear.
Fix: Ensure port 8554 is accessible from the camera’s network. In Docker, use MTX_PROTOCOLS=tcp to force TCP transport — UDP can be unreliable through Docker’s NAT. Check firewall rules with ufw status.
HLS stream has high latency
Symptom: Browser playback is 10–30 seconds behind the live stream.
Fix: HLS inherently has 3–10 second latency due to segment buffering. For lower latency, use WebRTC (sub-second) or Low-Latency HLS. Set hlsPartDuration: 200ms and hlsSegmentDuration: 1s in the config for reduced HLS latency.
WebRTC doesn’t work remotely
Symptom: WebRTC works on LAN but fails over the internet. Fix: WebRTC requires STUN/TURN servers for NAT traversal. Add a STUN server in the config (see Reverse Proxy section). If behind a symmetric NAT, you need a TURN server.
High CPU usage with many streams
Symptom: CPU spikes with multiple concurrent viewers or transcoding. Fix: MediaMTX doesn’t transcode by default — it proxies streams as-is. If CPU is high, check if FFmpeg is running for recording or protocol conversion. Reduce the number of HLS segments or disable unused protocols.
Resource Requirements
- RAM: 50 MB idle, 100–500 MB depending on concurrent streams
- CPU: Minimal for proxying. High if recording or converting protocols.
- Disk: 10 MB for application. Recording: 500 MB – 2 GB per camera per hour (varies with resolution and codec).
Verdict
MediaMTX is the best self-hosted real-time streaming server for IP camera aggregation and protocol conversion. Its zero-dependency Go binary handles RTSP, RTMP, HLS, WebRTC, and SRT with minimal resource usage. Configuration is straightforward YAML, and the Docker image works immediately.
For security camera management with a web UI, recording, and object detection, use Frigate or ZoneMinder instead — they’re NVR platforms that include MediaMTX-like functionality plus much more. MediaMTX is the right choice when you need a lightweight streaming proxy without the overhead of a full NVR system.
FAQ
Can MediaMTX replace Frigate or ZoneMinder?
No. MediaMTX is a streaming proxy — it receives, converts, and forwards video streams. It has no recording management, object detection, motion alerts, or web UI for camera management. Use Frigate or ZoneMinder for NVR functionality. MediaMTX is the right tool when you need lightweight protocol conversion or stream aggregation without NVR features.
What’s the difference between RTSP, RTMP, HLS, and WebRTC?
RTSP is the standard for IP cameras (low latency, requires special players). RTMP is for live broadcasting to platforms like YouTube/Twitch. HLS is for browser-based playback (higher latency, wide compatibility). WebRTC is for sub-second latency in browsers. MediaMTX can receive any of these and output any of the others — that’s its core value.
Can I record streams to disk?
Yes. Set record: yes in the path configuration and specify recordPath for the output directory. MediaMTX records in MPEG-TS format. The recording file size depends on the stream resolution and codec — budget 500 MB to 2 GB per camera per hour for 1080p.
Does MediaMTX transcode video?
Not by default. MediaMTX proxies streams as-is without re-encoding. You can configure an runOnReady command to pipe the stream through FFmpeg for transcoding, but this significantly increases CPU usage. For most use cases, protocol conversion (e.g., RTSP to HLS) doesn’t require transcoding.
How many cameras can MediaMTX handle?
Depends on whether you’re proxying or transcoding. For pure proxying (no transcoding), a single CPU core handles 20-50+ camera streams easily since MediaMTX just forwards packets. If recording or converting protocols via FFmpeg, each stream needs ~10-30% of a CPU core. Monitor CPU usage and add resources as needed.
Can I add authentication to streams?
Yes. MediaMTX supports authentication via external HTTP webhooks, static credentials in the config file, or JWT tokens. Configure authMethod and authHTTPAddress in mediamtx.yml to validate viewers and publishers against your own authentication backend.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments