Most small live-video jobs need the same box: something that takes a stream in — OBS over SRT or WHIP, IP cameras over RTSP — and serves it out as WebRTC for sub-second browser playback, LL-HLS for bigger audiences, or RTSP for an NVR. A MediaMTX server does all of that from one binary, and a small VPS suits it, because the work is moving packets, not encoding them.
This post covers what MediaMTX is, the ports to open, a minimal config with authentication, three common setups, sizing (you are buying bandwidth, not CPU), security, and where one server stops being enough. Config keys and default ports come from the mediamtx.yml of the current release, v1.21.2.
What a MediaMTX server is (and is not)
MediaMTX — called rtsp-simple-server until it outgrew RTSP — is an MIT-licensed live media server and proxy from the bluenviron project. It is written in Go and ships as a single executable with no dependencies, or as the bluenviron/mediamtx Docker image. Publishers push to a named path; readers pull that path in any protocol the server speaks.
- In: SRT, WebRTC (WHIP), RTSP, RTMP, HLS, MPEG-TS, RTP and Media-over-QUIC, or pulled from cameras and other servers.
- Out: SRT, WebRTC (WHEP and a browser player), RTSP, RTMP, HLS and LL-HLS, Media-over-QUIC.
- Also: recording, native forwarding, hooks that run commands on events, a control API and Prometheus metrics.
The part that matters for sizing: MediaMTX remuxes, it does not transcode. Resolution, bitrate and codec arrive as your source sent them; to change them, the docs pair it with FFmpeg. That keeps the server light, and it means the codec you publish decides who can watch. For on-demand playback of a file library you want a different tool — see our Jellyfin guide.
MediaMTX ports: what to open on the VPS
The defaults from the stock config. Open only the rows you use, and switch the rest off in the config too.
| Port | Protocol | Open it? |
|---|---|---|
| 8554/tcp | RTSP | If cameras, NVRs or players use RTSP |
| 8000–8001/udp | RTP/RTCP for RTSP | No: set rtspTransports: [tcp] |
| 1935/tcp | RTMP (RTMPS on 1936) | Only for RTMP ingest |
| 8890/udp | SRT | For SRT ingest |
| 8889/tcp | WebRTC: player, WHIP, WHEP | For WebRTC |
| 8189/udp | WebRTC media (ICE) | Always with 8889 |
| 8888/tcp | HLS / LL-HLS | For HLS viewers |
| 8892/tcp+udp, 8893/udp | Media-over-QUIC, on by default | No, unless used: moq: no |
| 9997/tcp, 9998/tcp | Control API, metrics (off by default) | Never |
On a public VPS, WebRTC is the usual snag: the handshake uses 8889/tcp, the video 8189/udp, and the server must tell each browser where to send it. Set webrtcAdditionalHosts to the public IP or a DNS name — required on Docker's bridge network, cheap insurance elsewhere — and if a viewer's network blocks UDP, webrtcLocalTCPAddress: :8189 adds a TCP fallback. Older guides use protocols, webrtcICEHostNAT1To1IPs and runOnReady; these are deprecated in favour of rtspTransports, webrtcAdditionalHosts and runOnAvailable.
MediaMTX setup: install and a minimal config
Docker with host networking is the simplest install: RTSP over UDP sees real client addresses, and Docker adds no firewall rules in host mode, so ufw applies as written.
docker run -d --name mediamtx --restart always \
--network host \
-v /etc/mediamtx/mediamtx.yml:/mediamtx.yml \
bluenviron/mediamtx:1
The :1 tag tracks the latest 1.x release; 1-ffmpeg adds FFmpeg for hooks. Without Docker, put the release binary in /usr/local/bin and add the short systemd unit from the docs' start-on-boot page; mediamtx --upgrade updates it in place.
Start from the stock mediamtx.yml and change three things. First, the default lets anyone publish and read any path, so replace authInternalUsers:
authInternalUsers:
- user: obs
pass: long-random-publish-secret
permissions:
- action: publish
path: live
- user: viewer
pass: different-read-secret
permissions:
- action: read
path: "~^(live|cam[0-9]+)$"
- user: any
ips: ["127.0.0.1", "::1"]
permissions:
- action: api
A leading tilde makes path a regular expression. Browsers show a login prompt; for a public stream, give user: any the read permission instead. Argon2 or SHA-256 hashed passwords also work. Second, switch off unused protocols and set the WebRTC address. Third, replace the catch-all all_others path with your own — unlisted paths are refused:
rtspTransports: [tcp]
rtmp: no
moq: no
webrtcAdditionalHosts: [203.0.113.10]
paths:
live:
Three setups that cover most jobs
IP cameras: RTSP to WebRTC in the browser
Cameras sit on a private network, and exposing their RTSP ports to the internet is the thing not to do. Either run a WireGuard tunnel from the site so the VPS pulls cameras over private addresses, or run MediaMTX at the site and forward each camera to the VPS over SRT. Over a tunnel:
paths:
cam1:
source: rtsp://user:[email protected]:554/stream1
rtspTransport: tcp
sourceOnDemand: yes
sourceOnDemand pulls the camera only while someone watches. Browsers open http://your-vps:8889/cam1; an NVR reads rtsp://your-vps:8554/cam1. Set cameras to H.264: many browsers cannot play H.265 over WebRTC, and MediaMTX will not convert it.
OBS: SRT or WHIP in, WebRTC and LL-HLS out
For SRT, pick a Custom service in OBS, use srt://your-vps:8890?streamid=publish:live:obs:SECRET&pkt_size=1316 as the server and leave the key empty; it is the right choice on a lossy uplink, as our SRT ingest post explains. For WHIP, the server is http://your-vps:8889/live/whip and the Bearer Token obs:SECRET.
The choice decides who hears audio. WebRTC carries Opus or G.711, not AAC, and MediaMTX skips a track it cannot deliver rather than converting it. OBS's usual SRT setup sends AAC, so WebRTC viewers get silent video; its WHIP output sends Opus with B-frames off, as browsers require. HLS takes AAC or Opus. So: WHIP for WebRTC audiences, SRT for HLS audiences or bad uplinks — or a runOnAvailable hook running one audio-only FFmpeg re-encode to Opus into a second path. Viewers use port 8889 for WebRTC or 8888 for LL-HLS, the default HLS variant: http://your-vps:8888/live.
Relay: forward to another server or platform
Current releases forward natively, without FFmpeg:
paths:
live:
forward:
- dest: srt://backup.example.net:8890?streamid=publish:live:relay:SECRET
- dest: rtmps://a.rtmps.youtube.com/live2#YOUR-STREAM-KEY
RTMP destinations take the stream key after a #; check the platform's current ingest URL, and note YouTube rejects streams without audio. Each destination is another copy of the bitrate leaving the server. For a web UI across several platforms, see the Restreamer walkthrough and our multistreaming use case.
Sizing a MediaMTX VPS: bandwidth, not CPU
Because MediaMTX repackages rather than re-encodes, CPU and memory stay modest; its scalability docs say bottlenecks are "almost always related to the limited bandwidth between server and readers". Two things do use real CPU: transcoding, and large WebRTC audiences, since WebRTC encrypts each viewer's connection separately while HLS is packaged once and served as files. There is no GPU on any of our VPS plans, so encode on the sender, and if you must transcode on the server, keep it to one rendition or to audio.
Egress is bitrate × concurrent viewers, plus forwarded copies, plus about 20% headroom for overhead and encoder peaks. Our standard shapes have no transfer quota but are shaped per machine, from 100 to 300 Mbps; the media server plans are unmetered with no per-VM ceiling. For a 6 Mbps stream:
| Viewers | Egress + 20% | Fits on | Bucharest, monthly |
|---|---|---|---|
| 10 | 72 Mbps | VPS I (100 Mbps) | €4 |
| 20 | 144 Mbps | VPS III (180 Mbps) | €10 |
| 30 | 216 Mbps | VPS IV (220 Mbps) | €16 |
| 50 | 360 Mbps | Streaming II or III | €18.99 / €34.99 |
| 200 | 1,440 Mbps | Streaming III or IV | €34.99 / €59.99 |
The crossover is around 30 viewers: beyond it, VPS V at €30 or VPS VI at €58 would be bought only for their bandwidth figure, and Streaming II at €18.99 has no ceiling at all. The streaming line also carries more vCPU from the third shape up — 4 on Streaming III against 2 on VPS III — which large WebRTC audiences use. At 200 viewers you depend on the node's shared uplink, so talk to us before a big event or put a CDN in front. Location premiums apply: Streaming II is €23.99 and Streaming III €44.99 in Warsaw, Sofia or Vienna; VPS III is €14 in Warsaw and €16 in Sofia or Vienna.
Locking it down
- Credentials on publish and read, separate and scoped to paths. SRT can also encrypt per path with
srtPublishPassphraseandsrtReadPassphrase. - Firewall to the rows you use, plus SSH, and switch unused protocols off so a firewall mistake exposes nothing.
- API and metrics on localhost. Both are off by default; if enabled, set
apiAddress: 127.0.0.1:9997andmetricsAddress: 127.0.0.1:9998and reach them over SSH. - TLS for HLS and WebRTC. Set
hlsEncryption: yesandwebrtcEncryption: yes, withhlsServerKey/hlsServerCertandwebrtcServerKey/webrtcServerCertpointing at an ACME certificate; restart after renewals. LL-HLS needs HTTPS to work properly on Apple devices. A TLS reverse proxy in front of 8888 and 8889 also works; list it inhlsTrustedProxiesandwebrtcTrustedProxies. - Ban repeat offenders. The authentication docs include a fail2ban filter for failed logins. DDoS protection is included on every Noded VPS; it stops floods, not weak passwords.
Where one VPS stops being the answer
- No GPU. None of our VPS plans has one, so a multi-rendition bitrate ladder encoded on the server is the wrong job for this box.
- Not a CDN. This is one origin in one city. For thousands of viewers, put a CDN in front of the HLS output — MediaMTX has an
hlsCDNSecretsetting to recognise its requests — or add read replicas behind a load balancer. WebRTC cannot be cached, so sub-second delivery at scale means more servers. - Disk. The largest disk a VPS can carry is 270 GB: 120 GB on the biggest shape plus three 50 GB add-ons at €4 a month each. A 6 Mbps recording grows about 2.7 GB an hour — roughly 100 hours, minus the OS.
recordDeleteAfterdefaults to one day; set it deliberately. - Unmanaged. You patch it, rotate the secrets and watch it during the event.
How Noded Can Help
Test the config first: an hourly VPS II from the VPS page is €0.0083 an hour in Bucharest, so an evening with OBS and a camera costs about four cents. Hourly machines need €5 of account credit and bill until destroyed, not merely powered off. If your audience fits under the shaped rate, run a standard shape monthly; if not, move to the media server line with the same config. For a second opinion before an event, open a ticket.
FAQ
What ports does MediaMTX use?
By default 8554/tcp for RTSP, 1935/tcp for RTMP, 8888/tcp for HLS, 8889/tcp plus 8189/udp for WebRTC, 8890/udp for SRT and 8892–8893 for Media-over-QUIC. The API (9997) and metrics (9998) are off by default.
Can MediaMTX convert RTSP to WebRTC?
Yes: pull or publish an RTSP stream into a path and open it on port 8889 in a browser. Use H.264 without B-frames and Opus or G.711 audio, because MediaMTX repackages streams but does not transcode them.
How much bandwidth does a MediaMTX server need?
Bitrate times concurrent viewers, plus forwarded copies, plus about 20% headroom. Twenty viewers of a 6 Mbps stream need about 144 Mbps, which fits a VPS III; past roughly 30 viewers the unshaped media server plans are the cheaper fit.
Why does my WebRTC stream not play from a VPS?
Usually 8189/udp is closed or the server advertises the wrong address. Open it, set webrtcAdditionalHosts to the public IP, and enable webrtcLocalTCPAddress for networks that block UDP.