Deployment guide

LMS music server

Overview

LMS (Lightweight Music Server) is an open source, self-hosted music streaming server. It streams your personal music collection from anywhere, through a fast in-browser web player or any Subsonic-compatible mobile or desktop app.

LMS is written in C++ on the Wt web toolkit, which makes it unusually light on memory and CPU for a full-featured streaming server. It keeps its catalogue in an embedded SQLite database. It scans the audio files you copy into its library and presents your albums, artists, genres and playlists with cover art. It also offers on-the-fly transcoding through ffmpeg and a Subsonic-compatible API that a wide ecosystem of player apps already speak.

The SecureAnyCloud image serves LMS 3.79.0 behind an nginx reverse proxy on a hardened Ubuntu 24.04 LTS base that is patched at build time. The server listens only on the loopback interface (127.0.0.1:5082), and nginx serves it on port 80.

The image is secure by default. Upstream LMS opens a setup wizard to whoever reaches it first while no account exists. A shared image that shipped with an empty database would therefore hand the administrator account to whoever found the VM first.

This image instead generates a unique administrator password and a separate Subsonic API key on every VM's first boot, before LMS ever accepts a connection. No shared, default or guessable credential ships in the image.

What you get:

  • LMS 3.79.0 built from source and served behind nginx, managed by systemd
  • The LMS web player and Subsonic-compatible API on :80
  • A unique administrator password and Subsonic API key generated per VM on first boot
  • ffmpeg for on-the-fly transcoding to any bitrate or format
  • The server bound to 127.0.0.1:5082 only, never exposed directly to the network
  • A dedicated Azure data disk at /var/lms for the music library, the SQLite database and the transcode cache
  • A preconfigured music library at /var/lms/music and a nightly library scan at 03:00
  • lms.service and nginx.service as enabled systemd units
  • 24/7 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.

Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting point. Size up for larger libraries or more concurrent listeners.

Configure the NSG to allow inbound 22/tcp from your management network and 80/tcp for the web player. LMS serves plain HTTP on port 80, so for production, terminate TLS in front of it with your own domain. The server is never exposed directly. It listens on 127.0.0.1:5082 only, so port 5082 stays off the network.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure portal, choose Create a resource, and search the Marketplace for LMS Lightweight Music Server by SecureAnyCloud. 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).

Review the dedicated data disk on the Disks tab. Then choose Review + create, then Create.

Step 2 - Deploy from the Azure CLI

Accept the Marketplace terms once per subscription, then create the VM:

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:lms-music-server-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name lms \
  --image sac1647283583153:lms-music-server-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

Then open port 80 for the web player:

az vm open-port --resource-group <your-rg> --name lms --port 80

Step 3 - Confirm the services are running

SSH in as azureuser and confirm that LMS and nginx are active. The server listens only on 127.0.0.1:5082, while nginx serves the web player on port 80.

systemctl is-active lms nginx lms-firstboot

Confirm what is listening. LMS is on loopback only, and only nginx is bound to a public interface:

ss -lntH 'sport = :5082 or sport = :80' | awk '{print $1, $4}'

Step 4 - Retrieve this VM's administrator password

On first boot, lms-firstboot.service generates an administrator password and a Subsonic API key that are unique to this VM. It seeds them into the LMS database before the server starts accepting connections, and it writes them to a root-only file. Read them with:

sudo cat /root/lms-credentials.txt

The file contains four values:

  • lms.url: the address to open in a browser
  • lms.admin.username: the administrator login (lmsadmin)
  • lms.admin.password: the password for the web player
  • lms.subsonic.apikey: the key that Subsonic client apps use in place of a password

Confirm that first boot completed and that exactly one administrator exists:

test -f /var/lib/sac/data/lms-firstboot.done && echo "first boot complete"
sudo sqlite3 /var/lms/lms.db "SELECT login_name, CASE type WHEN 1 THEN 'admin' ELSE 'user' END FROM user;"

Step 5 - Sign in to the web player

Open http://<vm-public-ip>/ in a browser. LMS presents its login screen.

Sign in with the lms.admin.username and lms.admin.password values from Step 4. You land on the album library. A freshly deployed VM starts with an empty library. The screenshot below shows it after music has been added in Step 7.

You can change the password to one of your own at any time. Choose Settings from the user menu, then Change password.

Step 6 - Browse and stream

Select an album to open its detail page, with cover art, artist, year, genre and the full tracklist.

Press Play to start streaming. The player bar along the bottom shows the current track, artist and album, the elapsed and total time, a seek bar, the volume control and the play queue.

Step 7 - Add your own music

The image ships with a preconfigured library at /var/lms/music on the dedicated data disk. Copy your audio files in, and make sure that the lms service account can read them. From your workstation, upload the files:

scp -r ~/Music/* azureuser@<vm-public-ip>:/tmp/upload/

Then move them into the library and fix ownership:

sudo mkdir -p /var/lms/music
sudo chown -R lms:lms /var/lms/music ls /var/lms/music

LMS scans the library automatically every night at 03:00. To pick up new music immediately, sign in to the web player and choose Admin, then Scan settings. Alternatively, choose Admin, then Scanner, to run a scan on demand. Confirm what has been catalogued:

sudo sqlite3 /var/lms/lms.db "SELECT (SELECT COUNT(*) FROM track) || ' tracks, ' || (SELECT COUNT(*) FROM release) || ' albums, ' || (SELECT COUNT(*) FROM artist) || ' artists';"

LMS reads tags (title, artist, album, track number, year, genre) and embedded cover art from the files themselves, so a well-tagged collection browses best.

Step 8 - Connect a Subsonic compatible client app

LMS exposes a Subsonic-compatible API, so mobile and desktop apps that speak Subsonic can stream from this VM. Point the app at http://<vm-public-ip>/, use the administrator username, and use the lms.subsonic.apikey value as the password.

LMS authenticates the Subsonic API with an API key rather than your account password. The two values are deliberately different, so your web player password is never sent to client apps.

Verify the API from the VM. A successful call returns "status":"ok":

curl -s "http://127.0.0.1/rest/ping.view?u=<admin-username>&p=<subsonic-api-key>&v=1.16.1&c=sac&f=json"

An incorrect key is rejected, which confirms that the API is authenticated rather than open:

curl -s "http://127.0.0.1/rest/ping.view?u=<admin-username>&p=wrong-key&v=1.16.1&c=sac&f=json"

Step 9 - Where your data lives

/var/lms is a dedicated Azure data disk, separate from the OS disk and independently resizable. It holds the music library, the SQLite catalogue and the transcode cache. Rebuilding or resizing the OS disk therefore never touches your music.

df -hT /var/lms | tail -1 sudo du -sh /var/lms/music /var/lms/lms.db 2>/dev/null

The key configuration is in /etc/lms.conf:

grep -E "^listen-addr|^listen-port|^behind-reverse-proxy|^working-dir" /etc/lms.conf

Step 10 - Production hardening

LMS serves plain HTTP on port 80 in this image. For anything beyond a private network, put your own domain and a TLS certificate in front of it. Point a DNS A record at the VM's public IP, then issue a certificate with certbot and let certbot rewrite the nginx site:

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d music.your-domain.example --redirect --agree-tos -m you@your-domain.example

Also restrict the NSG so that ports 80 and 443 are reachable only from the networks that need them, and keep port 22 limited to your management range. Change the generated administrator password to one of your own from the web UI.

Unattended security upgrades are enabled in the image, so the OS keeps patching itself.

Step 11 - Troubleshooting

Check service health and recent logs:

systemctl is-active lms nginx
sudo journalctl -u lms --no-pager | tail -20

If the web player does not load, confirm that nginx is proxying to the server and that LMS is answering on loopback. Both should report HTTP 200.

Use a GET request rather than a HEAD request. LMS runs with behind-reverse-proxy enabled and answers a bare curl -I HEAD request with 400 Bad Request. This looks like a fault but is not one.

curl -s -o /dev/null -w 'via nginx: HTTP %{http_code}\n' http://127.0.0.1/
curl -s -o /dev/null -w 'lms direct: HTTP %{http_code}\n' http://127.0.0.1:5082/

If first boot did not complete, the credentials file still holds its original pre-boot text. Re-run the first-boot unit:

sudo rm -f /var/lib/sac/data/lms-firstboot.done
sudo systemctl restart lms-firstboot.service
sudo systemctl restart lms nginx

If a scan does not pick up new files, confirm that the lms account can read them. LMS silently skips unreadable files:

sudo -u lms test -r /var/lms/music && echo "library readable by lms"

Support

SecureAnyCloud publishes and maintains this image and provides 24/7 support. For help with the image, deployment or configuration, contact sales@secureanycloud.com.

LMS is free software licensed under the GNU General Public License v3.0 or later. SecureAnyCloud distributes it unmodified. The project itself is at github.com/epoupon/lms.

Deploy on Azure

Launch LMS Lightweight Music Server 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