MistServer on Ubuntu 24.04 on Azure User Guide
Overview
MistServer is a full featured, broadcast grade open source streaming media server. A publisher such as OBS Studio, ffmpeg or a hardware encoder pushes a live feed over RTMP, and MistServer republishes it in real time as HLS, MPEG DASH, WebRTC, progressive HTTP, MP4 and RTMP for low latency playback in browsers and native players. Everything is driven from the MistController web management interface, backed by a JSON API for automation.
The cloudimg image installs the official prebuilt MistServer (verified at 3.11.1) into /usr/bin, running as the unprivileged mistserver service. The MistController management interface and JSON API are bound to loopback and served over HTTPS by nginx on port 443. RTMP ingest listens on port 1935 and the multi protocol HTTP output (HLS, MPEG DASH, progressive TS, MP4, FLV) listens on port 8080.
Secure by default, no default login: an unprotected media server hands an attacker full control. This image never ships that. Three independent secrets are generated on each VM's first boot, written to a root only file: a MistServer administrator password for the management interface and API, an HTTP Basic credential that protects the network facing management surface, and a passphrase that every RTMP publisher must supply to push a stream. MistController refuses to start unless a per VM administrator account exists, so an instance can never come up in the insecure open mode, and no two VMs share a credential. Nothing is baked into the image.
HTTPS by default: the MistController interface is bound to 127.0.0.1:4242 and is reachable only through the nginx reverse proxy on port 443, which terminates TLS with a self signed certificate regenerated per VM. An unauthenticated request to the management surface returns 401 until the administrator credential is supplied.
Batteries included: the image ships ffmpeg and the mist-selftest helper, which publishes a short test pattern over the passphrase protected RTMP endpoint, pulls it back over the HTTP output as MPEG transport stream and HLS, authenticates the management API, and confirms the authentication rules all behave.
What is included:
- MistServer (verified at 3.11.1), the official prebuilt build, running as an unprivileged system user
- The MistController web management interface and JSON API on
127.0.0.1:4242, served over HTTPS on port 443 by nginx - RTMP ingest on port 1935; multi protocol HTTP output (HLS, MPEG DASH, progressive TS, MP4, FLV) on port 8080
mistserver-firstboot.servicefor the per VM secret generation- A per VM admin password, an HTTPS Basic credential and an RTMP push passphrase in a root only
0600file - ffmpeg and the
mist-selftestend to end verification helper - Ubuntu 24.04 LTS base, fully patched
- 24/7 cloudimg support, 24h response SLA
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet with a subnet. MistServer is efficient, but sustained throughput scales with the number of concurrent publishers and viewers and with the bitrate of each stream. Recommended VM size: Standard_B2s (2 vCPU, 4 GB RAM) for evaluation and a handful of streams, or a Standard_D2s_v5 or larger for production workloads with many concurrent viewers. Live streams are relayed in real time, so plan for outbound network bandwidth rather than disk.
Step 1: Deploy from the Azure Portal
Search the Marketplace for MistServer on Ubuntu 24.04, choose your VM size, and attach an NSG that allows TCP 22 (SSH) from your management network, TCP 443 (HTTPS management interface) from your administrators, TCP 1935 (RTMP ingest) from your publishers, and TCP 8080 (HLS / DASH / HTTP playback) from the networks and players that consume the stream.
Step 2: Deploy from the Azure CLI
RG="mistserver-prod"; LOCATION="eastus"; VM_NAME="mist-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/mistserver-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name mist-vnet --address-prefix 10.90.0.0/16 --subnet-name mist-subnet --subnet-prefix 10.90.1.0/24
az network nsg create -g "$RG" --name mist-nsg
az network nsg rule create -g "$RG" --nsg-name mist-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name mist-nsg --name allow-https --priority 110 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 443 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name mist-nsg --name allow-rtmp --priority 120 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 1935 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name mist-nsg --name allow-play --priority 130 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 8080 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name mist-vnet --subnet mist-subnet --nsg mist-nsg --public-ip-sku Standard
Step 3: Connect via SSH
ssh azureuser@<vm-ip>
Step 4: Verify the service is running
MistServer runs as mistserver.service, with nginx terminating TLS in front of the loopback bound management interface. RTMP ingest listens on port 1935 and the multi protocol HTTP output on port 8080. An unauthenticated HTTPS health endpoint is provided for load balancer probes.
systemctl is-active mistserver nginx
ss -tln | grep -E '127.0.0.1:4242 |:1935 |:8080 '
curl -ks https://127.0.0.1/healthz
You should see both services active, the MistController API bound to 127.0.0.1:4242, RTMP on 1935, the HTTP output on 8080, and ok from the health endpoint.

Step 5: Read your per-VM secrets
Three secrets were generated on this VM's first boot and stored in a root only file: the MistServer administrator password (used for both the HTTPS Basic auth prompt and the MistController login), and the RTMP push passphrase. Read them and keep them secret. Confirm that unauthenticated requests to the management interface are rejected.
sudo cat /root/mistserver-credentials.txt
echo "unauthenticated https management -> HTTP $(curl -ks -o /dev/null -w '%{http_code}' https://127.0.0.1/)"
The note holds MIST_ADMIN_USER, MIST_ADMIN_PASSWORD and MIST_PUSH_PASSPHRASE, is owned root:root with mode 0600, and an unauthenticated call to the management interface returns 401 because it is behind the per VM credential.

Step 6: Open the MistController management interface
Point a browser at https://<vm-ip>/ and accept the self signed certificate. Your browser first prompts for the HTTPS Basic credential (enter admin and your MIST_ADMIN_PASSWORD), then the MistController interface presents its own login. Enter the same administrator username and password. Both layers use the per VM credential from /root/mistserver-credentials.txt, so the management surface is never reachable anonymously.

Once signed in, the Overview page shows the running MistServer version, the enabled ingest and output protocols, and the configured and active stream counts.

Step 7: Publish a stream and play it back
The image ships with a stream named live that accepts an RTMP push protected by your per VM passphrase. A publisher supplies the passphrase as the RTMP application segment, so the publish URL is rtmp://<vm-ip>:1935/<passphrase>/live where <passphrase> is your MIST_PUSH_PASSPHRASE. Point OBS at the server rtmp://<vm-ip>:1935/<passphrase> with the stream key live, or publish from ffmpeg:
# Publish a file or a live source to the passphrase-protected RTMP endpoint:
ffmpeg -re -i input.mp4 -c copy -f flv "rtmp://<vm-ip>:1935/<passphrase>/live"
Play the stream back over the HTTP output as HLS in a browser or native player, or as a progressive MPEG transport stream:
# HLS playlist (browsers, iOS, native players):
ffplay "http://<vm-ip>:8080/hls/live/index.m3u8"
# Progressive MPEG-TS:
ffplay "http://<vm-ip>:8080/live.ts"
The published live stream appears in the MistController Streams panel with its state, viewers and inputs. You can left click a stream to preview it in the browser.

To verify the whole pipeline end to end at any time, run the bundled self test. It publishes a short test pattern to the passphrase protected RTMP endpoint, confirms the management API lists the live stream, pulls it back over the HTTP output as MPEG transport stream and HLS, authenticates the management API, and proves that an unauthenticated management request and a wrong passphrase publish are both refused:
sudo mist-selftest
You should see a single OK line confirming the passphrase publish, the MPEG-TS and HLS pull and the authenticated management interface all worked, and that the unauthenticated and wrong passphrase attempts were refused.

Step 8: Protocols, runtime and hardening
The Protocols panel in the management interface lists every enabled ingest and output connector. RTMP ingest and the base HTTP output are active on their ports, and the HLS, MPEG DASH (CMAF), progressive TS, MP4 and FLV outputs are enabled and served through the HTTP output on port 8080.

On first boot a one shot service mints all three per VM secrets and then MistController starts, so the insecure open mode is never reachable. The OS is fully patched with unattended security upgrades enabled.
MistController -v 2>&1 | head -1
systemctl is-enabled mistserver nginx
apt-mark showhold
You should see MistServer 3.11.1, both services enabled, and apt-mark showhold printing nothing (no held packages). The mistserver-firstboot.service is a one shot that runs once on first boot to mint the per VM secrets and then disables itself.

Use a real certificate for production
The management interface ships with a self signed certificate regenerated per VM. For production, replace it with a certificate from a trusted CA, or front the VM with an Azure Application Gateway that terminates TLS. To install a Let's Encrypt certificate for the management interface with your own domain:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>
For public playback, the HTTP output on port 8080 is plain HTTP; front it with a CDN or a TLS terminating reverse proxy so viewers receive HTTPS, and restrict port 8080 at the NSG so only the proxy or CDN reaches the origin.
Security and operations notes
- Rotate the secrets: the per VM secrets live in
/etc/mistserver/secrets.env(the machine readable copy), the MistController account in/etc/mistserver.conf(stored MD5 hashed), and the nginx Basic credential in/etc/nginx/mistserver.htpasswd; all are recorded in/root/mistserver-credentials.txt. To regenerate a fresh set, remove the first-boot sentinel/var/lib/cloudimg/mistserver-firstboot.doneand reboot. - Restrict the ports: only expose port 1935 to trusted publishers, port 8080 to your players or CDN, and port 443 to your administrators. The MistController interface is bound to loopback and is only reachable through the authenticated nginx proxy.
- Push passphrase: every RTMP publisher must supply your
MIST_PUSH_PASSPHRASEas the application segment of the RTMP URL (rtmp://<vm-ip>:1935/<passphrase>/<stream>). A push with the wrong or missing passphrase is refused. - Scale out: for many concurrent viewers, put a CDN or an nginx cache in front of the HLS and DASH endpoints on port 8080, or run several instances behind a load balancer.
Support
Every cloudimg image includes 24/7 support with a 24-hour response SLA. Email support@cloudimg.co.uk with the offer name and your VM details. MistServer is developed by DDVTech and released into the public domain under the Unlicense; the cloudimg charge covers packaging, security patching, image maintenance and support.