Ov
Streaming & Messaging Azure

OvenMediaEngine on Ubuntu 24.04 on Azure User Guide

| Product: OvenMediaEngine on Ubuntu 24.04 LTS on Azure

Overview

This image runs OvenMediaEngine v0.20.5, the open source sub second latency live streaming server by AirenSoft, on Ubuntu 24.04 LTS. OvenMediaEngine ingests live video over RTMP, SRT, WebRTC and MPEG-TS and delivers it to viewers over WebRTC and Low-Latency HLS (LLHLS) with end to end latency measured in fractions of a second, rather than the many seconds of conventional HLS. A REST API drives stream management and statistics for automation.

Terminal showing the ovenmediaengine and nginx services active, the pinned upstream container running, and the RTMP, LLHLS and API ports listening

Licensed under AGPL-3.0. OvenMediaEngine is free software under the GNU Affero General Public License v3.0. This image runs the official, unmodified upstream release — the container airensoft/ovenmediaengine:v0.20.5 pulled straight from Docker Hub — driven entirely by external configuration; the AGPL source is never rebuilt or patched. In accordance with AGPL section 13, the exact Corresponding Source for the running version is the upstream tag it was built from: AirenSoft/OvenMediaEngine at v0.20.5. cloudimg is not affiliated with the OvenMediaEngine project.

Architecture. OvenMediaEngine runs as the ovenmediaengine systemd service (a docker run of the pinned upstream image) configured by a mounted /etc/ovenmediaengine/Server.xml. nginx on port 80 serves a static /healthz endpoint for load balancer probes, reverse proxies the LLHLS server, and hosts a small self contained demo player. The default application does pass-through packaging — it repackages the ingested H.264/AAC into LLHLS and WebRTC without CPU heavy transcoding — so it runs comfortably on the 4 GiB Standard_B2s size. Transcoding and adaptive bitrate are CPU intensive; size the VM up for those.

Secure by default. The only secret OvenMediaEngine needs is its REST API access token, and no fixed token ships in the image. On the first boot of every VM, ovenmediaengine-firstboot.service generates a token unique to that VM, writes it to a root owned file with mode 0600, and only then starts the streaming service. The API is bound to localhost only. No two VMs built from this image share a token, and the captured image contains no usable credential.


Step 1 — Launch the VM

Launch from the Azure Marketplace listing, or from the Azure CLI. Standard_B2s is the recommended size for evaluation and pass-through streaming; size up for transcoding or many concurrent streams.

az group create --name ovenmediaengine-rg --location eastus

az vm create \
  --resource-group ovenmediaengine-rg \
  --name ovenmediaengine-vm \
  --image cloudimg:ovenmediaengine-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

# Open port 80 (health + demo player). The streaming/media ports are opened in Step 6.
az vm open-port --resource-group ovenmediaengine-rg --name ovenmediaengine-vm --port 80 --priority 900

Note the public IP that az vm create prints — it is used as <vm-ip> throughout this guide.


Step 2 — Confirm the services are running

SSH in as azureuser and confirm the units are active. ovenmediaengine-firstboot is a oneshot unit, so active here means it ran to completion and generated this VM's API token.

systemctl is-active ovenmediaengine nginx ovenmediaengine-firstboot

Expected output:

active
active
active

Confirm the ingest, delivery and API ports are listening. RTMP is on 1935, LLHLS and WebRTC signalling share 3333, and the REST API on 8081 is bound to 127.0.0.1 only:

sudo ss -tlnp | grep -E ':1935 |:3333 |:8081 |:80 '

Step 3 — Retrieve this VM's REST API token

The API token was generated on this VM's first boot and written to a root owned file with mode 0600.

sudo ls -l /root/ovenmediaengine-credentials.txt
sudo cat /root/ovenmediaengine-credentials.txt

The file contains the manager API URL, the OME_API_TOKEN, and ready to use RTMP ingest, LLHLS playback, WebRTC playback and demo player URLs for this VM.

Terminal showing the credentials file with the per VM API token redacted, then the REST API returning 401 with no token or a wrong token and 200 with the per VM token

Store the token in your password manager. It is unique to this VM.


Step 4 — Verify the REST API and its token

The REST API on 8081 is protected by HTTP Basic authentication using the per VM token. Read the token from the credentials file and confirm that a request without a token is rejected with 401, while a request with the token succeeds with 200:

TOKEN=$(sudo awk -F= '/^OME_API_TOKEN=/{print $2}' /root/ovenmediaengine-credentials.txt)
AUTH="Basic $(printf '%s' "$TOKEN" | base64)"

# No token — rejected
curl -s -o /dev/null -w 'no token:  HTTP %{http_code}\n' http://127.0.0.1:8081/v1/vhosts

# Per-VM token — accepted
curl -s -o /dev/null -w 'with token: HTTP %{http_code}\n' -H "Authorization: $AUTH" http://127.0.0.1:8081/v1/vhosts

nginx also serves a static health endpoint for load balancer probes:

curl -s http://127.0.0.1/healthz

Step 5 — Publish a live stream and play it back

Publish a source to the default application app under any stream key you choose. Any RTMP encoder works — OBS Studio, a hardware encoder, or ffmpeg. This example generates a test pattern with ffmpeg (installed on the image) and publishes it to the stream key mystream. It runs for 60 seconds in the background so you can play it back below; to stream continuously from your own source, drop the -t 60 and the trailing & and run it in the foreground:

nohup ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 -f lavfi -i sine=frequency=440 \
  -c:v libx264 -preset veryfast -tune zerolatency -profile:v baseline -pix_fmt yuv420p -g 30 \
  -c:a aac -ar 44100 -b:a 128k \
  -t 60 -f flv rtmp://127.0.0.1:1935/app/mystream >/tmp/ome-publish.log 2>&1 &

sleep 6   # give OvenMediaEngine a moment to start packaging the stream

While it is publishing, OvenMediaEngine repackages it in real time. Fetch the Low-Latency HLS master playlist — it lists the video and audio renditions and their codecs:

curl -s http://127.0.0.1:3333/app/mystream/llhls.m3u8

Terminal showing ffmpeg publishing a test pattern over RTMP and the resulting LLHLS master playlist served by OvenMediaEngine with H.264 video and AAC audio renditions

From a browser, play the stream three ways once the media ports are open (Step 6):

  • Low-Latency HLS: http://<vm-ip>:3333/app/mystream/llhls.m3u8 in any LLHLS capable player.
  • WebRTC (lowest latency): the signalling URL ws://<vm-ip>:3333/app/mystream in a WebRTC player such as OvenPlayer.
  • The built in demo player: http://<vm-ip>/player/?stream=mystream, a small OvenPlayer page served by this image.

Step 6 — Open the streaming ports

The launch in Step 1 opened only port 80. Live streaming needs the ingest and media ports open on the VM's network security group. Open RTMP ingest, the LLHLS and WebRTC signalling port, the WebRTC TURN port, the SRT ingest port, and the WebRTC ICE media range:

az network nsg rule create --resource-group ovenmediaengine-rg --nsg-name ovenmediaengine-vmNSG \
  --name ome-tcp --priority 1001 --access Allow --protocol Tcp --direction Inbound \
  --destination-port-ranges 1935 3333 3478

az network nsg rule create --resource-group ovenmediaengine-rg --nsg-name ovenmediaengine-vmNSG \
  --name ome-udp --priority 1002 --access Allow --protocol Udp --direction Inbound \
  --destination-port-ranges 3478 9999 10000-10004

For external WebRTC playback, OvenMediaEngine advertises this VM's public IP as its ICE candidate, resolved automatically through a STUN server on startup — no manual configuration is needed as long as the ICE UDP range 10000-10004 is open.


Step 7 — Inspect and manage streams over the REST API

The REST API reports every active stream and its ingested tracks, and lets you manage the server programmatically. List the active streams in the default application, then inspect one stream's tracks:

TOKEN=$(sudo awk -F= '/^OME_API_TOKEN=/{print $2}' /root/ovenmediaengine-credentials.txt)
AUTH="Basic $(printf '%s' "$TOKEN" | base64)"

# Active streams in vhost "default", application "app"
curl -s -H "Authorization: $AUTH" http://127.0.0.1:8081/v1/vhosts/default/apps/app/streams

# Tracks (video + audio) for one stream
curl -s -H "Authorization: $AUTH" http://127.0.0.1:8081/v1/vhosts/default/apps/app/streams/mystream

Terminal showing the REST API listing the active stream and reporting its ingested H.264 video and AAC audio tracks

The full REST API reference is in the OvenMediaEngine documentation.


Step 8 — Secure and tune streaming

By default any encoder that can reach port 1935 may publish, which is the upstream default and convenient for a trusted network. For a public deployment, restrict who can publish and play by enabling SignedPolicy (signed, expiring URLs) or AdmissionWebhooks (defer the decision to your own auth server) in /etc/ovenmediaengine/Server.xml, then restart the service:

sudo systemctl restart ovenmediaengine

Both mechanisms are documented in the OvenMediaEngine access control guide. To serve LLHLS and WebRTC signalling over TLS, add your certificate to the <Host><TLS> block in Server.xml and enable the 3334/3335 TLS ports. Transcoding and adaptive bitrate output are configured per application under <OutputProfiles>; they are CPU intensive, so move to a compute optimised VM size before enabling them.


Troubleshooting

A published RTMP stream never appears. Port 1935/tcp is not open, or the encoder's server URL is not rtmp://<vm-ip>:1935/app with the stream key as the path. Confirm the rule from Step 6 exists and check sudo journalctl -u ovenmediaengine -n 50.

The LLHLS playlist returns 404. No stream is currently publishing to that key. The playlist only exists while a source is live; start the encoder, then fetch llhls.m3u8 again.

A WebRTC stream connects but shows no video. The ICE UDP range 10000-10004 (and 3478 for TURN) is not open on the network security group. WebRTC signalling rides port 3333, but the media itself is UDP and needs Step 6.

The service will not start. Run sudo systemctl status ovenmediaengine and sudo docker logs ovenmediaengine. The service is intentionally held back until first boot writes the API token, so on a brand new VM allow a few seconds for ovenmediaengine-firstboot.service to complete.

The API returns 401 with my token. Re-read the token exactly from /root/ovenmediaengine-credentials.txt — it must be Base64 encoded into the Authorization: Basic header, as shown in Step 4.


What is installed

Component Detail
OvenMediaEngine v0.20.5, AGPL-3.0, official image airensoft/ovenmediaengine:v0.20.5
Runtime Docker Engine, ovenmediaengine.service (systemd)
Configuration /etc/ovenmediaengine/Server.xml (mounted into the stock container)
Web server nginx on port 80 — /healthz, LLHLS reverse proxy, /player/ demo page
REST API Port 8081, bound to 127.0.0.1, per VM Basic auth token
Ingest RTMP 1935/tcp, SRT 9999/udp, MPEG-TS 4000/udp, WebRTC (WHIP)
Delivery LLHLS + WebRTC on 3333/tcp, WebRTC ICE 10000-10004/udp, TURN 3478
Packaging Pass-through (no transcode) — tuned for Standard_B2s
Credentials /root/ovenmediaengine-credentials.txt, mode 0600 root:root
Firstboot ovenmediaengine-firstboot.service, generates the per VM API token

Support

This image is packaged and maintained by cloudimg. OvenMediaEngine is free software under the GNU Affero General Public License v3.0, developed by AirenSoft and its contributors — cloudimg is not affiliated with the OvenMediaEngine project. In accordance with AGPL section 13, the Corresponding Source for the version in this image is the upstream release it is built from: AirenSoft/OvenMediaEngine at v0.20.5.

For image specific questions, contact cloudimg support through the Azure Marketplace listing. For questions about OvenMediaEngine itself, see the OvenMediaEngine documentation.