Ss
Application Infrastructure Azure

SRS Streaming Media Server on Ubuntu 24.04 on Azure User Guide

| Product: SRS Streaming Media Server on Ubuntu 24.04 LTS on Azure

Overview

SRS (Simple Realtime Server) is an open source, high performance streaming and WebRTC media server. A single native binary ingests live video over RTMP, WebRTC or SRT, and republishes it as RTMP, WebRTC, HLS or SRT to any number of viewers, with a built in HTTP JSON API and a set of web based test players. The cloudimg image runs the official pinned ossrs/srs:v6.0-r0 Docker image as a systemd managed container (srs.service) using host networking, so the RTMP and WebRTC media ports bind directly with no NAT translation to get in the way of playback. nginx fronts the HTTP API and web console on port 80 with per-VM HTTP Basic Authentication; an unauthenticated /healthz endpoint is always available for load balancer probes. RTMP ingest (port 1935) and WebRTC media (UDP port 8000) are exposed directly, since these are the real media planes and cannot be proxied through nginx.

Because WebRTC needs a routable address for its ICE candidate, the appliance detects this VM's public IP on first boot and writes it into the SRS configuration as the candidate - WebRTC media will not connect if that address is wrong, so this guide shows how to confirm it. A unique console password is generated on the first boot of every VM (username admin, HTTP Basic Auth via nginx). SRS is licensed under the MIT license. Backed by 24/7 cloudimg support.

What is included:

  • SRS v6.0-r0 (the official pinned ossrs/srs Docker image) run as the srs.service systemd unit with host networking
  • RTMP ingest on :1935, WebRTC media on UDP :8000, both bound directly for real media, no proxy in the path
  • The built in HTTP JSON API (:1985) and HTTP web console + test players (:8080), fronted by nginx on :80 with per-VM HTTP Basic Authentication
  • An unauthenticated /healthz endpoint for load balancer and platform health probes
  • The WebRTC candidate (ICE address) automatically templated to this VM's live public IP on first boot
  • A dedicated Azure data disk at /var/lib/srs holding live HLS segment output
  • srs.service + nginx.service as systemd units, enabled and active
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a reasonable starting point for a handful of concurrent streams; size up for more publishers or viewers. A public IP is required for WebRTC media to reach remote browsers - Azure assigns a new public IP on a full VM stop/deallocate and start unless you attach a Static Public IP SKU, so use a static IP for any production WebRTC deployment. NSG inbound rules:

  • 22/tcp from your management network (SSH)
  • 80/tcp (the web console, test players and JSON API, behind Basic Auth) and 443/tcp if you add your own TLS front end
  • 1935/tcp (RTMP ingest - required to publish a stream)
  • 8000/udp (WebRTC media - required for WebRTC publish/play to connect)

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for SRS by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). After creation, add inbound NSG rules for TCP 1935 and UDP 8000 (see Step 3) so publishing and WebRTC media can flow. Review the dedicated data disk on the Disks tab, then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name srs \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name srs --port 80 --priority 1010

Step 3 - Open the RTMP and WebRTC media ports (required)

RTMP ingest and WebRTC media cannot be proxied through nginx, so both must be reachable directly:

az network nsg rule create \
  --resource-group <your-rg> \
  --nsg-name <your-nsg> \
  --name Allow-SRS-RTMP \
  --priority 1020 \
  --direction Inbound --access Allow --protocol Tcp \
  --destination-port-ranges 1935 \
  --source-address-prefixes '*'

az network nsg rule create \
  --resource-group <your-rg> \
  --nsg-name <your-nsg> \
  --name Allow-SRS-WebRTC \
  --priority 1030 \
  --direction Inbound --access Allow --protocol Udp \
  --destination-port-ranges 8000 \
  --source-address-prefixes '*'

Without these rules the web console still loads over port 80, but you will not be able to publish a stream (RTMP) or connect WebRTC media.

Step 4 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 5 - Confirm the services and listening ports

systemctl is-active docker.service srs.service nginx.service srs-firstboot.service
sudo docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'

All four report active, and the container shows Up. SRS is running with host networking, so RTMP (:1935), the HTTP API (:1985), the web console (:8080) and the WebRTC media port (UDP :8000) all bind directly on the VM.

docker.service, srs.service, nginx.service and srs-firstboot.service all active, and the ossrs/srs container up and running

Step 6 - Confirm the WebRTC candidate IP

WebRTC needs a routable address for its ICE candidate. On first boot the appliance detects this VM's public IP and templates it into the running SRS configuration:

sudo sed -n '/rtc_server/,/^}/p' /etc/srs/srs.conf

The candidate value should equal your VM's public IP address exactly - if it does not, WebRTC publish/play will fail to connect even though RTMP and the console work fine. If you later reassign the VM's public IP (or attach a Static Public IP SKU), re-run first boot so the new address is templated in: sudo rm -f /var/lib/cloudimg/srs-firstboot.done && sudo systemctl restart srs-firstboot.service.

The rtc_server block in the running SRS configuration showing the WebRTC candidate templated to this VM's real public IP, and the per-VM credentials file proven to exist at mode 0600

Step 7 - Confirm the health endpoint and Basic Auth

nginx serves an unauthenticated health endpoint for load balancers and probes, and gates everything else with per-VM HTTP Basic Authentication:

curl -s http://localhost/healthz
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/

/healthz returns ok with no credentials required. A bare request to / returns HTTP 401 until you supply the per-VM admin password from Step 8; a wrong password also returns 401.

The nginx Basic Auth roundtrip: unauthenticated and wrong-password requests both return 401, the correct per-VM password returns 200

Step 8 - Retrieve your console password

The SRS console password is generated uniquely on the first boot of your VM and written to a root only file:

sudo cat /root/srs-credentials.txt

This file contains SRS_ADMIN_USER (always admin), SRS_ADMIN_PASSWORD, the console URL, and a ready made RTMP publish URL. Store the password somewhere safe. The file is mode 0600 and owned by root, so only an administrator can read it.

Step 9 - Sign in to the web console

Browse to http://<vm-public-ip>/ and enter the username admin and the password from Step 8 at the browser's Basic Auth prompt. The console home page confirms SRS is working and links to the built in test players.

The SRS console home page after signing in with the per-VM Basic Auth credentials, showing publish instructions and links to the test player and console

Step 10 - Publish a test stream over RTMP

From any remote machine with ffmpeg installed (or OBS Studio, pointed at rtmp://<vm-public-ip>:1935/live with stream key livestream), you can publish a live stream from anywhere on the internet - that is what NSG rule from Step 3 is for. To quickly prove ingest works without leaving your SSH session, publish a short test pattern from the VM itself over loopback:

ffmpeg -re -f lavfi -i "testsrc=size=1280x720:rate=30" -f lavfi -i "sine=frequency=1000" \
    -t 20 -c:v libx264 -preset veryfast -c:a aac -f flv \
    rtmp://127.0.0.1:1935/live/livestream &
sleep 4

Confirm the stream is live in the authenticated HTTP API (substitute your own password for <SRS_ADMIN_PASSWORD>):

curl -s -u "admin:<SRS_ADMIN_PASSWORD>" http://127.0.0.1/api/v1/streams/ | python3 -m json.tool

The response lists your stream by name with "publish": {"active": true} and the real video/audio codec details SRS negotiated - proof the whole pipeline (RTMP ingest through the HTTP API) is wired up correctly end to end. The same check works from a remote publisher too - just replace 127.0.0.1 with the VM's public IP once you are publishing from outside the VM.

ffmpeg publishing a synthetic test pattern over RTMP, and the authenticated HTTP API JSON response confirming the stream is live with H.264/AAC codec details

Step 11 - Watch it back in the built in test player

Browse to http://<vm-public-ip>/players/srs_player.html, enter the HLS URL for your stream (http://<vm-public-ip>/live/livestream.m3u8) and select Play. SRS automatically generates HLS segments from any published RTMP stream, so the same publish in Step 10 is watchable within a few seconds.

The SRS built in test player (players/srs_player.html) playing back the live published test stream over HLS

Step 12 - Inspect the live streams and clients list

The same authenticated /api/v1/streams/ endpoint from Step 10 doubles as SRS's streams and clients roster - open it directly in a browser (you will be prompted for the Basic Auth credentials from Step 8):

http://<vm-public-ip>/api/v1/streams/

The authenticated /api/v1/streams/ JSON endpoint viewed in-browser, listing the live stream, its connected client count and live bitrate

Step 13 - Confirm the server version via the API

http://<vm-public-ip>/api/v1/versions

The authenticated /api/v1/versions JSON endpoint viewed in-browser, confirming the SRS server build version

Step 14 - Confirm data lives on the dedicated disk

Live HLS segment output is stored under /var/lib/srs on the dedicated Azure data disk, so it survives OS changes and can be resized independently:

findmnt /var/lib/srs

The mount is backed by a separate Azure data disk captured into the image and re-provisioned on every VM.

Maintenance

  • Console password: the console password is set on first boot and stored in /root/srs-credentials.txt. To rotate it, run sudo htpasswd -bc /etc/nginx/.srs_htpasswd admin '<new-password>' and sudo systemctl reload nginx.
  • WebRTC candidate / public IP: WebRTC media needs the VM's public IP templated into /etc/srs/srs.conf and reachable on UDP 8000. If you reassign the public IP, clear the first boot marker and restart the first boot service so the new address is re-detected: sudo rm -f /var/lib/cloudimg/srs-firstboot.done && sudo systemctl restart srs-firstboot.service.
  • Your own domain and TLS: the appliance serves plain HTTP on port 80. For production, put your own domain and a trusted certificate (for example with certbot / Let's Encrypt) in front of nginx at /etc/nginx/sites-available/cloudimg-srs, then reload nginx.
  • Configuration: all SRS settings live in /etc/srs/srs.conf (see the SRS documentation for the full reference); after any change, restart the container with sudo systemctl restart srs.service.
  • Storage: live HLS segment output lives under /var/lib/srs on the data disk.
  • Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.

Licensing

SRS (Simple Realtime Server) is distributed under the MIT license, a permissive license with no source-disclosure obligation. cloudimg ships the pinned upstream ossrs/srs:v6.0-r0 Docker image unmodified together with appliance packaging (systemd units, the nginx front end and the first boot configuration).

Support

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.