
You want your own video streaming server: one machine that takes a live feed in, turns it into something a browser can play, and hands it to viewers. For internal events, a club or church channel or a licensed satellite feed, the architecture is the same: ingest, an optional transcode, an origin that serves HLS, and a CDN. Below: the protocols, a working FFmpeg setup from SRT to HLS, the bandwidth sums that decide most designs, and when an on premise server in your own building beats a cloud VPS.
Quick answer: For most one-to-many streams, ingest with SRT (or RTMP when the uplink is stable), let FFmpeg or Nginx with the RTMP module package the stream as HLS on the VPS, and put a CDN in front once viewers multiply your bitrate past what the server's port and monthly transfer can carry: 100 viewers at 6 Mbps is already 600 Mbps. Use WebRTC only when viewers must react within a second. Keep the server on premise only when the whole audience sits on your own network.
Clarify your goal: live, on-demand, or both
Live means a sustained outbound bitrate and a constant connection from the encoder, which is what this guide is about. On-demand is a library of files transcoded offline into HLS and served from a web server or object storage, where storage and caching matter more than latency (use signed URLs for private video). Many teams stream live and publish the recording afterwards, so plan for storage growth.
Ingest and transport: RTMP, SRT or WebRTC
RTMP and Nginx with the RTMP module
RTMP is still the most widely supported ingest. The nginx-rtmp-module lists RTMP, HLS and MPEG-DASH live streaming, relaying with push and pull, recording, and running FFmpeg on each published stream through exec. It is simple and well documented, but it has nothing of its own for a lossy uplink, which is the problem SRT was made for.
SRT
SRT (Secure Reliable Transport) is built for the public internet. Its project page says it recovers from severe packet loss, adapts to changing network conditions and encrypts streams with AES. FFmpeg supports it through libsrt with URLs of the form srt://hostname:port?options. Three options matter on day one:
mode:caller(the default) connects out,listenerwaits for an incoming connection, andrendezvousis for two peers. On a VPS you runlistenerand let the encoder call in.latency: set in microseconds, so 200 ms islatency=200000. It is the buffer SRT uses to absorb retransmissions. The OBS SRT guide gives 120 ms as the default and advises at least 2.5 times the round trip time between encoder and server.passphrase(10 to 79 characters) andpbkeylen(0, 16, 24 or 32 bytes; the default 0 means no encryption): the sender sets both. The receiver only needs the passphrase and gets the key length from the sender during the handshake.
WebRTC
WebRTC is an open standard for real-time communication in browsers and apps. It is the choice when viewers must react within a second, such as webinars with live questions or auctions. Serving it to thousands of viewers is a much bigger project than SRT or RTMP into a CDN, so add it only when latency demands it. For everything else, start with RTMP or SRT in and HLS out; the full comparison is in RTMP vs SRT vs SRTLA.
From SRT in to HLS out: a working FFmpeg setup
This is the core of a self-hosted live server on Linux: FFmpeg listens for SRT, repackages the stream without re-encoding it, and writes an HLS playlist plus segments into a folder your web server serves.
First check that your FFmpeg build has SRT. FFmpeg's SRT support comes from libsrt, so if this prints nothing, install a build that includes it (the -w keeps FFmpeg's built-in srtp protocol, which is a different thing, out of the result):
ffmpeg -hide_banner -protocols | grep -w srt
SRT runs over UDP, so open the port for UDP in the firewall (UFW shown):
sudo ufw allow 9000/udp
Create the output folder and give your user write access to it:
sudo mkdir -p /var/www/live && sudo chown "$USER" /var/www/live
Then start the listener as that user:
ffmpeg -i 'srt://0.0.0.0:9000?mode=listener&latency=200000&passphrase=use-a-long-secret-here' \
-c copy -f hls \
-hls_time 4 -hls_list_size 6 \
-hls_flags delete_segments+temp_file \
-hls_segment_filename '/var/www/live/ch1_%05d.ts' \
/var/www/live/ch1.m3u8
The sender (a second FFmpeg, a hardware encoder or a professional receiver with SRT output) pushes MPEG-TS to srt://YOUR_VPS_IP:9000?mode=caller&latency=200000&passphrase=use-a-long-secret-here&pbkeylen=32. With FFmpeg's default enforced_encryption=1, a sender without the matching passphrase is rejected.
What the HLS options do, from FFmpeg's muxer documentation:
| Option | What it does | FFmpeg default |
|---|---|---|
hls_time 4 | Target segment length in seconds; FFmpeg cuts on the next keyframe after this time | 2 |
hls_list_size 6 | Number of segments listed in the playlist (0 keeps all of them) | 5 |
hls_flags delete_segments | Deletes segments that have left the playlist, after one segment duration plus the playlist duration | not set |
hls_flags temp_file | Writes each segment as .tmp and renames it when complete, so the web server can refuse requests for *.tmp | not set |
Because segments are cut on keyframes, with -c copy the segment length follows the source's keyframe interval. FFmpeg's docs ask for a closed GOP and a GOP size that fits the segment time, so set the encoder to a keyframe every 2 or 4 seconds for hls_time 4. If your viewers' players cannot decode the incoming codec, replace -c copy with a transcode such as -c:v libx264 -preset veryfast -c:a aac, which moves the work onto the CPU.
Disk stays small: at 5 Mbps a 4 second segment is 2.5 MB (5 × 4 ÷ 8), so the six listed segments plus the one or two awaiting deletion take about 20 MB per channel. For a systemd service and bind errors, see the FFmpeg SRT listener setup.
CPU encoding and bandwidth
CPU or GPU encoding
Software encoding (x264, x265) needs no graphics hardware, which is why it is the normal route on a VPS. Its CPU cost grows with resolution, frame rate, the number of renditions and how slow a preset you pick. Stream copy, as in the command above, costs almost nothing; every transcoded rendition costs real cores, so measure with top while you stream. Hardware encoders on graphics cards take that load off the CPU, but VPS plans with a graphics card are rarer and cost more, so confirm the card, the driver and whether your VM may use it before you build around one.
Bandwidth: the real bill
Viewers multiply your outbound bitrate. One 6 Mbps stream to 100 viewers is 600 Mbps leaving the server, more than half of a 1 Gbps port. Either push one copy to a CDN that fans it out, or pay for all of that traffic on the server.
Write down a monthly model: peak viewers times average Mbps times hours live, then add 30% for spikes and retransmissions. A worked example for a club that streams 8 matches a month, 3 hours each, to at most 40 viewers at 4 Mbps:
- 40 × 4 Mbps = 160 Mbps while live
- 160 Mbps ÷ 8 = 20 MB per second, which is 72 GB per hour
- 72 GB × 3 hours × 8 matches = 1,728 GB
- plus 30% = about 2.25 TB a month
That fits a server with 10 TB of monthly transfer without a CDN. Double the viewers and move to 1080p at 6 Mbps and you are at 80 × 6 = 480 Mbps and about 6.7 TB a month with headroom: time for a CDN. Redo the sum after every growth step.
On premise server or cloud VPS?
An on premise server sits in your own building. What decides it is where your viewers are, because every viewer outside the building gets their own copy through your internet upload.
| Your situation | Pick | Why |
|---|---|---|
| Internal audience on your own LAN only (school, church, office) | On premise server | Viewers fetch the stream across the LAN, so it never uses the internet connection |
| Public audience on the internet | Cloud origin plus a CDN | Every viewer's copy leaves through the building's upload: 50 viewers × 5 Mbps = 250 Mbps outbound |
| Compliance or archive rules | Hybrid | Record the master locally, distribute from the cloud |
| A 24/7 public channel | Cloud | A power cut or ISP outage in your building does not stop the stream, because the server runs in a data center on its own power and network |
Compare your outbound sum with the upload speed of your line, which the stream shares with everyone else in the building. On premise also means paying for hardware, power, a UPS and spare parts, plus someone who patches the OS and is on call during events; on an unmanaged VPS you still patch the OS, but the hardware and power are the data center's problem. A public ingest on an office network opens a port to the internet, so keep it on the LAN or behind a VPN where you can. For a creator's home PC against a server, see dedicated streaming server vs home PC.
Software stack overview
- OBS Studio is the usual broadcaster. Keep the bitrate below your real upload, prefer a wired connection and turn on automatic reconnect. OBS also sends SRT: it accepts
srt://IP:port?optionsURLs. - FFmpeg does the plumbing: SRT in, RTMP or HLS out, audio normalisation, subtitles.
- Nginx serves the HLS folder over HTTPS (Let's Encrypt for the certificate) and, with the RTMP module, can terminate RTMP ingest. If you use
temp_file, refuse requests for*.tmp.
CDN integration
Without a CDN, every viewer byte leaves through your VPS network port, and that caps the number of viewers early. With push, your origin sends the live stream to the CDN's ingest endpoint; with pull, the CDN fetches the HLS segments from your origin.
For caching, an HLS player must reload a live playlist, but RFC 8216 (section 6.3.4) says it waits at least the target duration after a playlist changes before it reloads. So cache the .m3u8 playlist for less than one segment (with hls_time 4, a second or two) and the segments much longer, since a finished segment does not change. Log 404s on segments: they usually mean the encoder and the CDN are out of step.
Your origin still sends traffic: one 5 Mbps rendition pulled around the clock for 30 days is 1.62 TB (5 ÷ 8 × 2,592,000 seconds). Treat that as the floor, because a pull CDN can fetch the same segment more than once.
Monitoring stream health
Track publisher connects and disconnects, dropped frames in the OBS log, encoder restarts, CPU, disk IO wait and network throughput. A scheduled check that fetches the playlist and one segment from outside your network catches CDN mistakes before viewers do. Alert on sustained ingest failure, low free disk space and certificate expiry.
Troubleshooting common failures
- Viewers buffer endlessly: check that the playlist updates while the segments it lists exist. A stale cached
.m3u8while segments roll forward is the classic mismatch; purge it or shorten its cache time while testing. - Encoder disconnect loops: usually an unstable uplink or a firewall that drops idle connections. Turn on reconnect in OBS; for SRT, raise
latencyto at least 2.5 times the measured round trip time. - CPU at 100% but the stream looks soft: a slow preset at a high resolution. Lower the resolution or frame rate, pick a faster preset, or move transcoding to a bigger plan.
- Disk fills overnight: segment folders without
delete_segments, big access logs or long DVR buffers. Add logrotate and alert when free space drops below 20%.
Security basics
- Stream keys and SRT passphrases are secrets. Rotate them after a leak.
- HTTPS for playback, and RTMPS where your ingest supports it. SRT does not use TLS; it has its own AES encryption through
passphraseandpbkeylen. - Firewall the ingest port to known contributor IPs when contributors are fixed.
- Rate limits on publishing endpoints against brute forcing.
Running this on Space-Node
Our VPS plans run in an EU data center with a 1 Gbps port, NVMe storage, full root access and 5 to 30 TB of monthly transfer depending on the plan, which suits an FFmpeg SRT to HLS origin or an RTMP relay in front of a CDN. If you would rather run OBS on the server itself, our streaming VPS comes with OBS Studio pre-installed and opens in your web browser.
Still choosing the server software itself? Our RTMP server comparison puts MediaMTX, SRS, nginx-rtmp and Owncast side by side.
FAQ
Can one video streaming server replace Twitch or YouTube?
For delivering a stream to an audience you already have, partly. Discovery, chat moderation and global scale are separate products. Self-hosting fits private communities, your own branding, licensed channels and full control over the workflow.
RTMP or SRT for unstable internet?
SRT, with a latency of at least 2.5 times your round trip time as the OBS guide advises: with an 80 ms round trip, latency=200000 or more. RTMP is fine on a stable wired uplink.
Do I need WebRTC?
Only when viewers must interact in under a second. For one-to-many broadcasts, HLS through a CDN is simpler and cheaper to run.
How much bandwidth does a video streaming server need?
Viewers times bitrate: 100 viewers at 6 Mbps is 600 Mbps. Divide by 8 and multiply by 3,600 for MB per hour, multiply by your hours live and add 30%. If that comes close to your port speed or monthly transfer, use a CDN from the start.
Can I use GPU encoding instead of x264?
On a regular VPS usually not: there is no graphics card to encode on, and our VPS plans list none, so use x264 or stream copy. Our streaming VPS plans have graphics, mostly shared with other customers and different per machine, so check which encoders OBS lists on your server. A graphics card of your own is only available on request: open a ticket and ask.
Can I run legal IPTV or satellite ingest on a VPS?
Only for channels you own or are licensed to distribute; this setup is not for restreaming channels you hold no rights to. The chain is the one in this guide: an encoder or professional receiver at the dish sends the feed as SRT to the VPS, where FFmpeg listens on srt://0.0.0.0:9000?mode=listener with the same passphrase (10 to 79 characters) that the sender uses together with pbkeylen 16, 24 or 32. FFmpeg packages the feed as HLS and a CDN fans it out. Do the sum first: one 5 Mbps channel to 200 viewers is 1,000 Mbps, a full 1 Gbps port, and at that rate a 10 TB monthly allowance lasts about 22 hours. So use a CDN. The listener is covered step by step in the FFmpeg SRT listener setup.
Sources
All opened on 4 November 2026:
- FFmpeg protocols documentation, SRT section: ffmpeg.org/ffmpeg-protocols.html
- FFmpeg formats documentation, HLS muxer: ffmpeg.org/ffmpeg-formats.html
- FFmpeg generic options (
-protocols,-hide_banner): ffmpeg.org/ffmpeg.html - SRT project by Haivision: github.com/Haivision/srt
- OBS knowledge base, SRT Protocol Streaming Guide: obsproject.com/kb/srt-protocol-streaming-guide
- nginx-rtmp-module README: github.com/arut/nginx-rtmp-module
- RFC 8216, HTTP Live Streaming, section 6.3.4: rfc-editor.org/rfc/rfc8216
- WebRTC project: webrtc.org
- UFW manual page (Ubuntu 24.04): manpages.ubuntu.com