OvenMediaEngine on Ubuntu 24.04 on Azure User Guide
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.

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.

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

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.m3u8in any LLHLS capable player. - WebRTC (lowest latency): the signalling URL
ws://<vm-ip>:3333/app/mystreamin 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

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.