ESC

Start typing to search across invoices, services, domains, tickets, and more...

Search... Ctrl+K
Use Cases & Solutions

Self-Hosted Live Streaming for Asia: SRS Origin on a Hong Kong, Tokyo or Singapore Server with CDN

8 steps 26 min read 13 views 0
On this page

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.

Key facts
  • Origin locations: Hong Kong (CN2 GIA to mainland China), Tokyo, Japan, Singapore (via sales), plus Taipei, Seoul and Bangkok.
  • Hong Kong dedicated servers from $139/mo; Japan VPS from $28/mo for small test origins.
  • 10Gbps uplinks, SSD storage and DDoS protection for public ingest and origin endpoints.
  • IMIDC CDN for HLS delivery, so the origin serves the CDN instead of every viewer.
  • This guide covers running your own streaming platform, not upload networks for TikTok sellers.

How a self-hosted live streaming stack fits together

A live platform has four stages: ingest, origin/packaging, distribution and playback.

  1. Ingest: the presenter's OBS, vMix or hardware encoder pushes RTMP or SRT to your origin.
  2. Origin: SRS receives the stream, optionally transcodes it into several bitrates, packages HLS segments, serves WebRTC and records to disk.
  3. Distribution: a CDN pulls HLS from the origin and caches segments near viewers.
  4. Playback: hls.js, Video.js or native players for HLS; a WebRTC player for sub-second interactive sessions.

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.

Choosing ingest and playback protocols

Use RTMP or SRT in, HLS for scale and WebRTC only where interactivity matters.

ProtocolRoleTypical latencyBest for
RTMPIngest1-3 s to originUniversal OBS/encoder support
SRTIngestConfigurable, sub-second to a few secondsLossy or long-distance uplinks, remote venues
HLSPlaybackAbout 6-20 sLarge audiences via CDN, all devices
LL-HLSPlaybackAbout 2-5 sEvents needing faster chat interaction; needs packager and CDN support
HTTP-FLVPlaybackAbout 1-3 sWeb players in some Asian markets
WebRTC (WHIP/WHEP)Ingest and playbackUnder 1 sInteractive 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.

Deploying SRS with Docker on a dedicated server

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)
  • Set the encoder keyframe interval to 2 seconds so it matches hls_fragment 2.
  • CANDIDATE must be the server's public IP, or WebRTC players will fail to connect.
  • The 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;
        }
    }
}

Bandwidth math: viewers x bitrate

Peak egress is simply concurrent viewers multiplied by average bitrate, plus about 10% protocol overhead.

Concurrent viewersAverage bitratePeak egressData per hour
502.5 Mbps125 Mbpsabout 56 GB
2002.5 Mbps500 Mbpsabout 225 GB
1,0003 Mbps3 Gbpsabout 1.35 TB
3,0002 Mbps (ABR mix)6 Gbpsabout 2.7 TB
10,0002 Mbps (ABR mix)20 Gbpsabout 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.

Pairing the origin with IMIDC CDN

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;
    }
}
  • Point a hostname such as origin-live.example.com at the origin and configure it as the origin in IMIDC CDN; viewers use the CDN hostname.
  • Playlists (.m3u8) change every segment, so cache them for 1-2 seconds; segments never change, so cache them long.
  • Use signed URLs or token authentication on the CDN for paid or private events.
  • Keep WebRTC sessions on the origin (or a few regional SRS edges), because WebRTC is not cached by HTTP CDNs.

Recording and archiving to storage

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.

Where to place the origin, and DDoS protection

Put the origin close to the presenters and the main audience, and protect public endpoints.

Origin locationBest audienceNotes
Hong KongMainland China, Hong Kong, Greater ChinaCN2 GIA (AS4809) to mainland China, no ICP filing for hosting
Tokyo, JapanJapan, South Korea, PacificNative Japanese IPs; China-optimized CN2 route option on VPS
SingaporeSoutheast Asia, India, OceaniaConfigured on request via IMIDC sales
Taipei / Seoul / BangkokSingle-country eventsLocal native IPs for in-country viewers
  • Order IMIDC DDoS protection for the origin; gaming and esports streams in particular attract floods.
  • Expose only what is needed: 1935/10080 for ingest (ideally allow-listed to presenter IPs), 443 for the CDN origin and WebRTC ports.
  • Rotate stream keys per event and validate them in the publish hook.
  • Streams aimed at mainland China viewers must carry lawful content, and live audio-video services there may be subject to separate licensing rules; this is not legal advice.

Which IMIDC setup fits

Size the origin by presenters, transcoding load and how much traffic the CDN absorbs.

  • Internal webinars or classes up to a few hundred viewers: one Hong Kong dedicated server or Japan dedicated server serving HLS directly.
  • Public events and gaming streams with thousands of viewers: a dedicated origin with DDoS protection plus IMIDC CDN.
  • Multi-region platform: origins in Hong Kong and Tokyo, Singapore on request via sales, with BGP and Anycast for ingest if you run your own ASN.
  • GPU or high-core transcoding nodes, large disks for archives: ask IMIDC sales for a custom configuration.

FAQ

What is the best server location to self-host live streams for viewers in Asia?

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.

How much bandwidth do I need for 1,000 live viewers?

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.

Should I use SRS or nginx-rtmp?

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.

Can I get sub-second latency for thousands of viewers?

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.

Does IMIDC offer DDoS protection for streaming origins?

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.

Was this answer helpful?

Related Tutorials