Start typing to search across invoices, services, domains, tickets, and more...
To run self-hosted live streaming for Asian audiences, put an SRS (or nginx-rtmp) origin on a dedicated server in Hong Kong, Tokyo or Singapore, ingest with RTMP or SRT, output HLS and WebRTC, and let a CDN fan the stream out to viewers. IMIDC provides the pieces: Hong Kong dedicated servers from $139/mo with CN2 GIA routing to mainland China, Japan dedicated servers, Singapore servers on request, 10Gbps uplinks, DDoS protection and the IMIDC CDN.
A live platform has four stages: ingest, origin/packaging, distribution and playback.
Typical use cases are webinars and corporate town halls, e-learning classes, product launches and events, and gaming or esports streams where you want your own branding, access control and recordings instead of a third-party platform.
Use RTMP or SRT in, HLS for scale and WebRTC only where interactivity matters.
| Protocol | Role | Typical latency | Best for |
|---|---|---|---|
| RTMP | Ingest | 1-3 s to origin | Universal OBS/encoder support |
| SRT | Ingest | Configurable, sub-second to a few seconds | Lossy or long-distance uplinks, remote venues |
| HLS | Playback | About 6-20 s | Large audiences via CDN, all devices |
| LL-HLS | Playback | About 2-5 s | Events needing faster chat interaction; needs packager and CDN support |
| HTTP-FLV | Playback | About 1-3 s | Web players in some Asian markets |
| WebRTC (WHIP/WHEP) | Ingest and playback | Under 1 s | Interactive classes, auctions, co-hosting; heavier per viewer |
SRS handles RTMP, SRT, HLS, HTTP-FLV and WebRTC in one process. If you specifically need LL-HLS with partial segments, check that both your packager and your CDN support it before you promise viewers low latency.
SRS runs well in Docker; the only details to get right are ports, the WebRTC candidate IP and persistent folders.
mkdir -p /opt/srs/conf /opt/srs/html /opt/srs/record
# put srs.conf (below) into /opt/srs/conf/srs.conf, then:
docker run -d --name srs --restart unless-stopped \
-p 1935:1935 -p 1985:1985 -p 8080:8080 \
-p 8000:8000/udp -p 10080:10080/udp \
-e CANDIDATE=203.0.113.20 \
-v /opt/srs/conf/srs.conf:/usr/local/srs/conf/srs.conf \
-v /opt/srs/html:/usr/local/srs/objs/nginx/html \
-v /opt/srs/record:/usr/local/srs/objs/record \
ossrs/srs:5 ./objs/srs -c conf/srs.conf
docker logs -f srs # watch publish / play events
ufw allow 1935/tcp; ufw allow 8000/udp; ufw allow 10080/udp
A production-oriented srs.conf with HLS, HTTP-FLV, WebRTC, SRT, recording and a publish hook:
listen 1935;
max_connections 3000;
daemon off;
srs_log_tank console;
http_api { enabled on; listen 1985; }
http_server { enabled on; listen 8080; dir ./objs/nginx/html; }
rtc_server { enabled on; listen 8000; candidate $CANDIDATE; }
srt_server { enabled on; listen 10080; }
vhost __defaultVhost__ {
hls {
enabled on;
hls_fragment 2;
hls_window 12;
hls_path ./objs/nginx/html;
hls_m3u8_file [app]/[stream].m3u8;
hls_ts_file [app]/[stream]-[seq].ts;
hls_cleanup on;
}
http_remux { enabled on; mount [vhost]/[app]/[stream].flv; }
rtc { enabled on; rtmp_to_rtc on; rtc_to_rtmp on; }
srt { enabled on; srt_to_rtmp on; }
dvr {
enabled on;
dvr_plan session;
dvr_path ./objs/record/[app]/[stream]/[2006]-[01]-[02]_[15][04][05].mp4;
}
http_hooks {
enabled on;
on_publish http://127.0.0.1:8085/api/streams/on_publish;
}
play { gop_cache on; }
}
Push from OBS or ffmpeg and test playback:
# OBS (RTMP): Server rtmp://203.0.113.20/live Stream key event1?secret=YOUR_KEY
# SRT push from ffmpeg (OBS can also output SRT):
ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -b:v 4000k -g 60 \
-c:a aac -b:a 128k -f mpegts \
"srt://203.0.113.20:10080?streamid=#!::r=live/event1,m=publish"
# Playback URLs
# HLS http://203.0.113.20:8080/live/event1.m3u8
# HTTP-FLV http://203.0.113.20:8080/live/event1.flv
# WebRTC http://203.0.113.20:1985/rtc/v1/whep/?app=live&stream=event1 (WHEP)
hls_fragment 2.CANDIDATE must be the server's public IP, or WebRTC players will fail to connect.on_publish hook lets your app check the stream key; return HTTP 200 with body 0 to allow, anything else to reject.For adaptive bitrate, add an ffmpeg transcoder that publishes extra renditions, then reference them from a master playlist:
# simple ABR ladder: pull the source from SRS and publish 720p + 480p renditions
ffmpeg -i rtmp://127.0.0.1/live/event1 \
-map 0:v -map 0:a -c:v libx264 -preset veryfast -s 1280x720 -b:v 2500k -g 60 \
-c:a aac -b:a 128k -f flv rtmp://127.0.0.1/live/event1_720 \
-map 0:v -map 0:a -c:v libx264 -preset veryfast -s 854x480 -b:v 1000k -g 60 \
-c:a aac -b:a 96k -f flv rtmp://127.0.0.1/live/event1_480
Prefer nginx-rtmp? It covers RTMP in and HLS out with a small footprint, but has no native SRT or WebRTC:
# nginx-rtmp alternative (nginx.conf, top level)
rtmp {
server {
listen 1935;
application live {
live on;
hls on;
hls_path /var/www/hls;
hls_fragment 2s;
hls_playlist_length 12s;
on_publish http://127.0.0.1:8085/api/streams/on_publish;
}
}
}
Peak egress is simply concurrent viewers multiplied by average bitrate, plus about 10% protocol overhead.
| Concurrent viewers | Average bitrate | Peak egress | Data per hour |
|---|---|---|---|
| 50 | 2.5 Mbps | 125 Mbps | about 56 GB |
| 200 | 2.5 Mbps | 500 Mbps | about 225 GB |
| 1,000 | 3 Mbps | 3 Gbps | about 1.35 TB |
| 3,000 | 2 Mbps (ABR mix) | 6 Gbps | about 2.7 TB |
| 10,000 | 2 Mbps (ABR mix) | 20 Gbps | about 9 TB |
Formula: GB per hour = Mbps x 3600 / 8 / 1000. A single origin on a 10Gbps uplink can serve a few hundred viewers directly with comfortable headroom; beyond that, serve viewers from a CDN so the origin only feeds the CDN's cache. Ingest is small by comparison: one 1080p stream at 4-6 Mbps per presenter.
Let the CDN pull HLS over HTTPS from the origin, cache segments for a long time and playlists for about one second.
# Nginx in front of SRS as the HTTPS origin for the CDN
server {
listen 443 ssl;
http2 on;
server_name origin-live.example.com;
ssl_certificate /etc/nginx/ssl/origin-live.crt;
ssl_certificate_key /etc/nginx/ssl/origin-live.key;
location ~ \.m3u8$ {
proxy_pass http://127.0.0.1:8080;
add_header Cache-Control "max-age=1" always;
add_header Access-Control-Allow-Origin "*" always;
}
location ~ \.(ts|m4s)$ {
proxy_pass http://127.0.0.1:8080;
add_header Cache-Control "max-age=86400" always;
add_header Access-Control-Allow-Origin "*" always;
}
}
.m3u8) change every segment, so cache them for 1-2 seconds; segments never change, so cache them long.Record every session on the origin, then move finished files to object storage for replay and on-demand viewing.
# move finished recordings to S3-compatible object storage every 10 minutes (cron)
*/10 * * * * rclone move /opt/srs/record s3store:live-archive --min-age 10m --delete-empty-src-dirs
The DVR folder in the config above is kept outside the public web directory, so raw recordings are not downloadable by guessing URLs. Use a separate storage server or object storage bucket for long-term archives, and transcode replays to an HLS ladder if you publish them.
Put the origin close to the presenters and the main audience, and protect public endpoints.
| Origin location | Best audience | Notes |
|---|---|---|
| Hong Kong | Mainland China, Hong Kong, Greater China | CN2 GIA (AS4809) to mainland China, no ICP filing for hosting |
| Tokyo, Japan | Japan, South Korea, Pacific | Native Japanese IPs; China-optimized CN2 route option on VPS |
| Singapore | Southeast Asia, India, Oceania | Configured on request via IMIDC sales |
| Taipei / Seoul / Bangkok | Single-country events | Local native IPs for in-country viewers |
Size the origin by presenters, transcoding load and how much traffic the CDN absorbs.
Hong Kong is the usual choice when many viewers are in mainland China, because IMIDC Hong Kong servers use China Telecom CN2 GIA. Tokyo suits Japan and Korea, and Singapore suits Southeast Asia; for mixed audiences, use one origin plus a CDN.
At 3 Mbps per viewer you need about 3 Gbps of peak egress and roughly 1.35 TB per hour. That is why audiences of this size should be served through a CDN rather than straight from the origin.
SRS supports RTMP, SRT, HLS, HTTP-FLV and WebRTC in one server and has an HTTP API, so it is the more complete choice. nginx-rtmp is lighter and fine for simple RTMP-to-HLS workflows.
Sub-second delivery needs WebRTC, which is much heavier per viewer than HLS and is not cached by ordinary CDNs. Most platforms use WebRTC for presenters and interactive participants and HLS or LL-HLS for the wider audience.
Yes. IMIDC offers DDoS protection that can be added to servers used as streaming origins. Tell sales about your expected event sizes so the protection and port setup match your traffic.
Planning your own streaming platform? Start with a Hong Kong dedicated server or Tokyo dedicated server and the IMIDC CDN, or open a ticket and the IMIDC team will help size your origin.