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

ProtocolPortUse Case
RTSP8554IP cameras, security systems, low-latency LAN streaming
RTMP1935OBS streaming, legacy encoders, live broadcast ingestion
HLS8888Web browser playback, CDN distribution, high compatibility
WebRTC8889Ultra-low latency browser playback (<500ms), interactive streams
SRT8890/udpReliable 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

SettingPurposeDefault
rtspAddressRTSP listen address:8554
rtmpAddressRTMP listen address:1935
hlsAddressHLS listen address:8888
webrtcAddressWebRTC listen address:8889
recordEnable stream recordingno
sourceOnDemandOnly pull source when viewers connectno
readTimeoutTimeout for inactive readers10s

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:

DataLocation
Configuration./mediamtx.yml (bind-mounted)
Recordingsmediamtx-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.

Comments