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

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
:80as 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.serviceand a one-shotmopidy-firstboot.serviceas systemd units, with nginx gated on the first-boot marker- A small, self-created sample album under
/var/lib/mopidy/mediaso 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 + create → Create. 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.

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.

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.

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.


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.

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.

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.