Deployment guide

MistServer

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.

This SecureAnyCloud image installs the official prebuilt MistServer (verified at 3.11.1) into /usr/bin, running as the unprivileged mistserver service. It is secure by default: there is no default login, and every VM generates its own credentials on first boot.

What you get:

  • 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, bound to loopback and served over HTTPS on port 443 by nginx
  • RTMP ingest on port 1935, and a multi-protocol HTTP output (HLS, MPEG DASH, progressive TS, MP4, FLV) on port 8080
  • mistserver-firstboot.service, which generates three independent secrets on each VM's first boot: 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
  • A per-VM admin password, an HTTPS Basic credential and an RTMP push passphrase in a root-only 0600 file. 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 on 127.0.0.1:4242 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.
  • ffmpeg and the mist-selftest end-to-end verification helper. mist-selftest 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 that the authentication rules behave as expected.
  • Ubuntu 24.04 LTS base, patched at build time
  • 24/7 SecureAnyCloud support, 24h response SLA

Prerequisites

  • An active Azure subscription, an SSH key pair, and a VNet with a subnet.
  • Recommended VM size: Standard_B2s (2 vCPU, 4 GB RAM) for evaluation and a handful of streams, or Standard_D2s_v5 or larger for production workloads with many concurrent viewers.
  • Sustained throughput scales with the number of concurrent publishers and viewers and with the bitrate of each stream. Live streams are relayed in real time, so plan for outbound network bandwidth rather than disk.
1

Deploy from the Azure Portal

In the Azure Marketplace, search for MistServer on Ubuntu 24.04 and choose your VM size. Attach a network security group (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
  • TCP 8080 (HLS / DASH / HTTP playback) from the networks and players that consume the stream
2

Deploy from the Azure CLI

Create the VM from the Azure CLI:

RG="mistserver-prod"; LOCATION="eastus"; VM_NAME="mist-01" IMAGE_URN="sac1647283583153:mistserver-ubuntu-24-04:default:latest" 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
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:mistserver-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
  --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
3

Connect over SSH

Connect to the VM over SSH:

ssh azureuser@<vm-ip>
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. Check the services and ports:

systemctl is-active mistserver nginx ss -tln | grep -E '127.0.0.1:4242 |:1935 |:8080 ' curl -ks https://127.0.0.1/healthz

The output shows 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.

5

Read your per-VM secrets

This VM's first boot generated its secrets and stored them in a root-only file. The MistServer administrator password is used for both the HTTPS Basic auth prompt and the MistController login, and the RTMP push passphrase protects publishing. Read the file and keep its contents secret. Then 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 file holds MIST_ADMIN_USER, MIST_ADMIN_PASSWORD and MIST_PUSH_PASSPHRASE, and is owned root:root with mode 0600. An unauthenticated call to the management interface returns 401 because it is behind the per-VM credential.

6

Open the MistController management interface

Browse to 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. The MistController interface then 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. After you sign in, the Overview page shows the running MistServer version, the enabled ingest and output protocols, and the configured and active stream counts.

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, either 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. 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 and confirms that the management API lists the live stream. It pulls the stream back over the HTTP output as MPEG transport stream and HLS, authenticates the management API, and proves that an unauthenticated management request and a publish with a wrong passphrase are both refused:

sudo mist-selftest

The output is a single OK line. It confirms that 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.

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. 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 generates all three per-VM secrets, and only then does MistController start, so the insecure open mode is never reachable. The OS is patched at build time and ships with unattended security upgrades enabled. Check the version, service state and held packages:

MistController -v 2>&1 | head -1 systemctl is-enabled mistserver nginx apt-mark showhold

The output shows MistServer 3.11.1, both services enabled, and apt-mark showhold printing nothing (no held packages). mistserver-firstboot.service is a one-shot unit that runs once on first boot to generate the per-VM secrets and then disables itself.

Use a real certificate for production

The management interface ships with a self-signed certificate that is 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, run:

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>

For public playback, note that 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 in the NSG so that 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/sac/data/mistserver-firstboot.done and reboot.
  • Restrict the ports. Expose port 1935 only 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 reachable only through the authenticated nginx proxy.
  • Use the push passphrase. Every RTMP publisher must supply your MIST_PUSH_PASSPHRASE as the application segment of the RTMP URL (rtmp://<vm-ip>:1935/<passphrase>/<stream>). A push with a 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 SecureAnyCloud image includes 24/7 support with a 24-hour response SLA. Email sales@secureanycloud.com with the offer name and your VM details.

MistServer is developed by DDVTech and released into the public domain under the Unlicense. The SecureAnyCloud charge covers packaging, security patching, image maintenance and support.

Deploy on Azure

Launch MistServer on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure