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:5082only, never exposed directly to the network - A dedicated Azure data disk at
/var/lmsfor the music library, the SQLite database and the transcode cache - A preconfigured music library at
/var/lms/musicand a nightly library scan at 03:00 lms.serviceandnginx.serviceas 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 StandardThen open port 80 for the web player:
az vm open-port --resource-group <your-rg> --name lms --port 80Step 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-firstbootConfirm 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.txtThe file contains four values:
lms.url: the address to open in a browserlms.admin.username: the administrator login (lmsadmin)lms.admin.password: the password for the web playerlms.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/musicLMS 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/nullThe key configuration is in /etc/lms.conf:
grep -E "^listen-addr|^listen-port|^behind-reverse-proxy|^working-dir" /etc/lms.confStep 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.exampleAlso 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 -20If 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 nginxIf 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
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, fully patched Ubuntu 24.04 LTS base. The server listens only on the loopback interface (127.0.0.1:5082), and nginx serves it on port 80.
A small sample library ships in the image, so the album, artist and track views show content the moment you sign in. You can replace it with your own music at any time.
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 instance first.
This image instead generates a unique administrator password and a separate Subsonic API key on every instance'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 instance on first boot
- ffmpeg for on-the-fly transcoding to any bitrate or format
- The server bound to
127.0.0.1:5082only, never exposed directly to the network - A dedicated EBS data volume at
/var/lmsfor the music library, the SQLite database and the transcode cache - A preconfigured music library at
/var/lms/musicwith a small sample album, and a nightly library scan at 03:00 lms.serviceandnginx.serviceas enabled systemd units- 24/7 SecureAnyCloud support
Connecting to your instance
Connect over SSH on port 22 using your EC2 key pair. The login user depends on the operating system variant you launched. For Ubuntu 24.04 LTS, the login user is ubuntu.
ssh -i /path/to/your-key.pem ubuntu@<instance-public-ip>The web player is served on port 80. LMS itself is never exposed directly. It listens on 127.0.0.1:5082 only, so that port stays off the network.
Prerequisites
You need an AWS account, an EC2 key pair in the target region, and a VPC with a public subnet.
m5.large (2 vCPU / 8 GiB RAM) is a sensible starting point. Size up for larger libraries or more concurrent listeners.
Configure the security group to allow inbound 22/tcp from your management network and 80/tcp for the web player. Also allow 443/tcp if you terminate TLS. LMS serves plain HTTP on port 80, so for production, put your own domain and a certificate in front of it.
Step 1 - Launch from the AWS Marketplace
In the AWS Marketplace, find LMS Lightweight Music Server by SecureAnyCloud. Choose Continue to Subscribe and accept the terms. Then choose Continue to Configuration and Continue to Launch.
Pick your region, the m5.large instance type, your VPC and subnet, your key pair, and a security group that allows inbound 22 and 80. Launch the instance and note its public IP or DNS name.
Step 2 - Launch from the AWS CLI
You can also launch the published AMI directly. Replace the AMI id with the one from the Marketplace listing for your region:
aws ec2 run-instances \
--image-id <ami-id-from-listing> \
--instance-type m5.large \
--key-name <your-key-pair> \
--security-group-ids <sg-with-22-and-80> \
--subnet-id <your-public-subnet> \
--metadata-options "HttpTokens=required" \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=lms}]'Step 3 - Confirm the services are running
SSH in as ubuntu 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-firstbootConfirm 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 instance's administrator password
On first boot, lms-firstboot.service generates an administrator password and a Subsonic API key that are unique to this instance. 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.txtThe file contains four values:
lms.url: the address to open in a browserlms.admin.username: the administrator login (lmsadmin)lms.admin.password: the password for the web playerlms.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://<instance-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, which already holds the sample album that ships in the image.
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 EBS data volume. It contains a small sample album. Copy your own audio files in, and make sure that the lms service account can read them. From your workstation, upload the files:
scp -i /path/to/your-key.pem -r ~/Music/* ubuntu@<instance-public-ip>:/tmp/upload/Then move them into the library and fix ownership:
sudo mkdir -p /var/lms/music
sudo mv /tmp/upload/* /var/lms/music/
sudo chown -R lms:lms /var/lms/music ls /var/lms/musicLMS 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 instance. Point the app at http://<instance-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 instance. 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 EBS data volume, 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/nullThe key configuration is in /etc/lms.conf:
grep -E "^listen-addr|^listen-port|^behind-reverse-proxy|^working-dir" /etc/lms.confStep 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 instance'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.exampleAlso restrict the security group 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 -20If 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 nginxIf 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 AWS
Launch LMS Lightweight Music Server on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com