Media & Entertainment Azure

Mopidy on Ubuntu 24.04 on Azure User Guide

| Product: Mopidy on Ubuntu 24.04 LTS on Azure

Overview

Mopidy is an extensible music server written in Python. It plays music from your own local files and, through its plugin architecture, from online sources, and it exposes two control surfaces at once: a classic MPD server (so any MPD client can browse and control it) and an HTTP / JSON-RPC + WebSocket API. This cloudimg image bundles the Mopidy-Iris web player — a polished browser interface for your library, search, play queue, now playing and playback controls — so you can manage and drive Mopidy from any device without installing a desktop client.

Every Mopidy frontend is bound to the loopback interface only. The Iris web player and the JSON-RPC API listen on 127.0.0.1:6680 and the MPD server on 127.0.0.1:6600; neither is ever reachable directly from the network. The single public surface is nginx on port 80, configured as an authenticating reverse proxy in front of the Iris player, and / redirects to /iris/.

On the first boot of every deployed VM, a one-shot service generates a unique nginx HTTP Basic-Auth password for the user admin and a unique MPD password, writes both to /root/mopidy-credentials.txt with mode 0600, restarts Mopidy, and only then starts nginx. Because nginx is held back until that bootstrap has finished, port 80 never answers before your per-VM password exists. Two VMs deployed from the same image never share credentials, and no default web or MPD password ships in the captured image.

Mopidy Iris web player, now playing

What is included:

  • Mopidy 3.4.2 (Apache-2.0) with the MPD frontend (mopidy-mpd) and local-library backend (mopidy-local), installed from the Ubuntu 24.04 universe with the full GStreamer 1.0 plugin stack
  • The Mopidy-Iris web player (Apache-2.0) served at /iris/
  • nginx on :80 as an authenticating reverse proxy in front of Mopidy's loopback HTTP frontend on :6680; the MPD frontend on loopback :6600
  • A per-VM nginx Basic-Auth password and a per-VM MPD password generated at first boot, in a root-only file — no default login ships in the image
  • mopidy.service, nginx.service and a one-shot mopidy-firstboot.service as systemd units, with nginx gated on the first-boot marker
  • A small, self-created sample album under /var/lib/mopidy/media so the player has content on first sign-in
  • A fully patched Ubuntu 24.04 LTS security baseline at capture time, with unattended security updates enabled
  • 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 good starting point; scale up for very large libraries or many concurrent listeners, and attach a data disk or use a generous OS disk for your music collection. NSG inbound: allow 22/tcp from your management network and 80/tcp (plus 443/tcp once you put your own TLS in front) from the networks your listeners will reach Mopidy on. If you connect an MPD client from another machine, reach it over an SSH tunnel rather than exposing port 6600.

Step 1 — Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Mopidy 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). Then Review + createCreate. First-boot initialisation takes a few seconds after the VM starts.

Step 2 — Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name mopidy \
  --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 mopidy --port 80 --priority 1010

Step 3 — Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 — Verify the Mopidy stack

Confirm the services are active, and that Mopidy's HTTP and MPD frontends are bound to loopback while nginx is the only public listener:

systemctl is-active mopidy nginx
sudo ss -tlnp | grep -E ':80 |:6680 |:6600 '

Both service lines read active. Port 80 (nginx) listens on all interfaces; the Mopidy HTTP frontend on 6680 and the MPD frontend on 6600 are bound to loopback (127.0.0.1) only.

Service status and loopback bind

Step 5 — Retrieve your per-VM passwords

The credentials generated on the first boot of your VM are stored in a root-only file. It lists the Mopidy URL, the web player username (admin) and password, and the MPD host, port and password:

sudo cat /root/mopidy-credentials.txt

Store the passwords in your password manager and treat the file as sensitive.

Version and per-VM credentials

Step 6 — Verify authentication

nginx rejects an unauthenticated request with 401; with the per-VM web password the Iris player loads and the JSON-RPC API answers. The MPD frontend on loopback requires the per-VM MPD password too:

WPASS=$(sudo grep '^mopidy.web.pass=' /root/mopidy-credentials.txt | cut -d= -f2-)
MPASS=$(sudo grep '^mopidy.mpd.pass=' /root/mopidy-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'no credentials:   HTTP %{http_code}\n' http://127.0.0.1/iris/
curl -s -o /dev/null -w 'admin:<per-VM>:   HTTP %{http_code}\n' -u "admin:$WPASS" http://127.0.0.1/iris/
curl -s -u "admin:$WPASS" -X POST http://127.0.0.1/mopidy/rpc -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"core.get_version"}' | jq -r '"core.get_version: " + .result'
MPD_HOST="$MPASS@127.0.0.1" mpc -p 6600 status | head -1

The unauthenticated request returns 401, the authenticated one returns 200, JSON-RPC reports the Mopidy version, and the MPD client connects only with the per-VM password.

Authentication round-trip

Step 7 — Sign in to the Iris web player

Open a web browser and navigate to http://<vm-public-ip>/. Your browser prompts for a username and password: enter admin and the web password from /root/mopidy-credentials.txt. Mopidy redirects you to the Iris web player, which opens on the Now playing view. From the sidebar you can reach Search, Playlists, Artists, Albums, Tracks, Browse and Settings. The sample album that ships with the image is already in your library, so the player has something to show immediately.

Step 8 — Add and scan your music library

Mopidy plays music you already own. Copy your audio files onto the VM under /var/lib/mopidy/media (the local library folder), make sure the mopidy service user can read them, then run a scan so Mopidy indexes the new tracks — reading tags and cover art and grouping them into albums and artists:

sudo mopidyctl local scan

The scan reports how many files it found and indexed. Refresh the Albums or Tracks view in Iris and your library appears. You can confirm the library over the JSON-RPC API too:

WPASS=$(sudo grep '^mopidy.web.pass=' /root/mopidy-credentials.txt | cut -d= -f2-)
curl -s -u "admin:$WPASS" -X POST http://127.0.0.1/mopidy/rpc -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"core.library.browse","params":{"uri":"local:directory"}}' \
  | jq -r '.result[].name'

To keep large libraries up to date, copy new music into the folder and re-run sudo mopidyctl local scan.

Step 9 — Browse and play your music

In Iris, open Albums, Artists or Tracks to browse your collection. Select an album to see its tracks, then play any track — the transport controls at the bottom of the window show the current track, artwork, a seek bar and volume, and the play queue fills from your selection.

Album library with cover art

Track library

Step 10 — Control Mopidy from an MPD client

Because Mopidy speaks the MPD protocol, any MPD client (for example ncmpcpp, mpc, or a mobile MPD app) can browse and control it. The MPD frontend is bound to loopback and protected by the per-VM MPD password, so reach it over an SSH tunnel from your workstation rather than opening port 6600:

ssh -L 6600:127.0.0.1:6600 azureuser@<vm-public-ip>
# then, on your workstation, with the MPD password from the credentials file:
MPD_HOST="<mpd-password>@127.0.0.1" mpc status

From the VM itself you can confirm an MPD client sees the library and the player state, using the per-VM password:

MPASS=$(sudo grep '^mopidy.mpd.pass=' /root/mopidy-credentials.txt | cut -d= -f2-)
export MPD_HOST="$MPASS@127.0.0.1"
mpc -p 6600 ls
mpc -p 6600 search album "cloudimg Sample Album"
mpc -p 6600 status

mpc ls lists the top of the library (Local media), mpc search returns the tracks it matched, and mpc status shows the current player state. To queue and play an album, an MPD client uses findadd then play — for example:

mpc findadd album "cloudimg Sample Album"   # queue an album
mpc play                                    # start playback
mpc current                                 # show the current track

Step 11 — Configure a real audio output

Because a cloud VM has no sound card, the image ships with Mopidy's audio output set to a null GStreamer sink (fakesink) so the playback pipeline runs cleanly and clients see accurate playback state. To actually hear audio you configure a real GStreamer output for your environment — for example an Icecast/shout2send stream that listeners connect to, or a Snapcast multi-room setup. Edit the [audio] section of /etc/mopidy/mopidy.conf and restart Mopidy:

sudo nano /etc/mopidy/mopidy.conf     # set output = <your GStreamer output pipeline>
sudo systemctl restart mopidy

See the Mopidy audio documentation for output pipelines and streaming options.

Step 12 — Extend Mopidy with plugins

Mopidy's power is its plugin ecosystem — backends for Spotify, SoundCloud, TIDAL, YouTube, podcasts and more. Install an extension with pip into the system packages so the packaged Mopidy can load it, add its [extension] section to /etc/mopidy/mopidy.conf, and restart:

sudo pip3 install --break-system-packages Mopidy-SoundCloud
sudo nano /etc/mopidy/mopidy.conf     # add the [soundcloud] section with your auth token
sudo systemctl restart mopidy

The Settings page in Iris lists the extensions Mopidy has loaded and lets you manage the connection to the server.

Iris settings and loaded services

Security baseline

The image is captured with the Ubuntu 24.04 security baseline fully applied (including phased updates) and ships with unattended security upgrades enabled, so your VM keeps patching itself after deployment:

cat /etc/apt/apt.conf.d/20auto-upgrades
grep ConditionPathExists /etc/systemd/system/nginx.service.d/*.conf

Every Mopidy frontend binds to loopback only and nginx is the single public listener, gated on the first-boot marker so port 80 never answers before your per-VM password has been generated. The credentials file is root-only, and Mopidy runs as an unprivileged mopidy system user.

Security posture

Support

cloudimg images include 24/7 support. If you have any questions about this Mopidy image or need help with your deployment, contact us at support@cloudimg.co.uk.