Icecast Liquidsoap
Overview
This image is a complete internet radio station on Ubuntu 24.04 LTS. It pairs two open source projects into one ready-to-broadcast appliance.
Liquidsoap 2.4.5, from savonet, is a scriptable audio engine that builds a station. It plays playlists, mixes live and scheduled sources, crossfades tracks, inserts jingles and streams the result out to a server.
Icecast 2.4.4, from the Xiph.Org Foundation, is the streaming server. It takes that single live feed on a named mountpoint and relays it to many simultaneous listeners over ordinary HTTP. It speaks Ogg Vorbis, Opus and MP3, and publishes M3U and XSPF playlists that any media player understands.
The appliance boots already streaming. On first boot, Liquidsoap connects a license-clean generated demo source to Icecast on the /stream.ogg mountpoint. The whole chain is proven the moment the VM starts, and the status page shows a live mountpoint out of the box.
You then point Liquidsoap at your own music to go live. Because Icecast relays over plain HTTP, listeners need no special software. A browser, VLC or any internet radio app can play a mountpoint directly.
Secure by default. The stock Icecast configuration ships the well-known default password hackme for its source, relay and admin accounts. This image ships no working password at all.
On the first boot of every VM, icecast-liquidsoap-firstboot.service generates three independent random passwords and writes them into the configuration. It also wires Liquidsoap to authenticate with the same per-VM source password. Both Icecast and the Liquidsoap source are configured to refuse to start if that rotation has not run, so a VM can never come up serving a default or stand-in credential.
No copyrighted audio ships in this image. The out-of-the-box demo source is a generated reference tone, not a recording of anyone's work, so you can demonstrate the appliance freely. Step 11 shows how to swap in your own playlist.
What you get:
- Liquidsoap 2.4.5 installed from savonet's official release, streaming a license-clean demo source to Icecast out of the box
- Icecast 2.4.4 installed from the stock Ubuntu 24.04 archive package, so it inherits Ubuntu's security maintenance
- Icecast listening on port
8000, its native port, for both listeners and source clients - nginx on port
80, reverse proxying the status and admin interface so the server is reachable without a port suffix, plus an unauthenticated/healthzendpoint for Azure Load Balancer health probes - Per-VM admin, source and relay passwords generated on first boot and recorded at
/root/icecast-liquidsoap-credentials.txt(mode0600) icecast2.service,nginx.service,sac-radio.service(Liquidsoap) and a one-shoticecast-liquidsoap-firstboot.serviceas systemd units, enabled and active- An Ubuntu 24.04 LTS base, patched at build time, with unattended security upgrades enabled
- 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) comfortably serves a typical station. Icecast is light on CPU because it relays the source stream rather than re-encoding it, so listener count is mostly a bandwidth question. Liquidsoap's own CPU use depends on how much mixing and encoding your station script does.
For NSG inbound rules, allow 22/tcp from your management network, 80/tcp for the status and admin interface, and 8000/tcp for listeners and source clients.
Icecast serves plain HTTP. For a public station, or any time an admin or source password crosses the internet, terminate TLS in front of it with your own domain. Use a reverse proxy or Azure Application Gateway.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Icecast + Liquidsoap Internet Radio Station by SecureAnyCloud, and select Create.
On the Basics tab, 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 click Review + create, followed by Create. After deployment, open port 8000 as well (Step 2 shows the CLI equivalent).
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:icecast-liquidsoap:default:latest
az vm create \
--resource-group <your-rg> \
--name radio \
--image sac1647283583153:icecast-liquidsoap:default:latest \
--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 radio --port 80 --priority 1010
az vm open-port --resource-group <your-rg> --name radio --port 8000 --priority 1011Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>Step 4 - Confirm the services are running
Four units make up the appliance:
icecast-liquidsoap-firstboot.serviceruns once on first boot to generate this VM's passwords.icecast2.serviceis the streaming server.sac-radio.serviceis the Liquidsoap source feeding it.nginx.servicefronts it on port 80.
Confirm that all four are active, and that Icecast is listening on port 8000 with nginx on port 80:
systemctl is-active icecast2 nginx sac-radio icecast-liquidsoap-firstboot
sudo ss -tlnp | grep -E ':80 |:8000 'Expected output:
active active active active LISTEN 0 5 0.0.0.0:8000 0.0.0.0:* users:(("icecast2",pid=...)) LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=...)) LISTEN 0 511 [::]:80 [::]:* users:(("nginx",pid=...))Step 5 - Retrieve your per-VM passwords
On first boot, icecast-liquidsoap-firstboot.service generated three independent random passwords for this VM and recorded them in a root-only file:
ICECAST_ADMIN_PASSWORDsigns you in to theadmininterface as user admin.ICECAST_SOURCE_PASSWORDis what asourceclient uses (with user source) to start broadcasting. The built-in Liquidsoap source already uses this value.ICECAST_RELAY_PASSWORDis used by another Icecast server pulling a relay from this one.
Read them with:
sudo cat /root/icecast-liquidsoap-credentials.txtThe three passwords are distinct on purpose. Handing a presenter the source password does not give them admin access.
When you need to share the file, for example in a support bundle or a screenshot, print it with the secrets masked:
sudo sed -E 's/^(ICECAST_[A-Z_]*PASSWORD=).*/\1********/' /root/icecast-liquidsoap-credentials.txtStep 6 - Confirm the appliance is already streaming
nginx serves an unauthenticated /healthz endpoint for load balancer probes. Icecast publishes machine-readable server statistics at /status-json.xsl. Because Liquidsoap connected the demo source on first boot, the status JSON already lists a live /stream.ogg mountpoint.
The admin interface requires the password from Step 5. An unauthenticated request is rejected with 401, while an authenticated one returns 200:
curl -sI http://127.0.0.1/healthz | head -1
curl -s http://127.0.0.1/status-json.xsl | jq -r '.icestats.server_id, .icestats.source.listenurl'PW=$(sudo grep '^ICECAST_ADMIN_PASSWORD=' /root/icecast-liquidsoap-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w "no auth -> HTTP %{http_code}\n" http://127.0.0.1/admin/stats
curl -s -o /dev/null -w "with pw -> HTTP %{http_code}\n" -u "admin:$PW" http://127.0.0.1/admin/statsExpected output:
HTTP/1.1 200 OK Icecast 2.4.4 http://<vm-public-ip>:8000/stream.ogg no auth -> HTTP 401 with pw -> HTTP 200You can pull the live audio itself to prove the stream end to end. A listener needs no credentials. This command reads a few seconds of audio and reports how many bytes arrived:
curl -s -m 3 -o /tmp/stream-sample.ogg http://127.0.0.1:8000/stream.ogg || true echo "pulled $(wc -c < /tmp/stream-sample.ogg) bytes of live Ogg audio"; rm -f /tmp/stream-sample.oggStep 7 - Confirm no default password shipped
Upstream Icecast ships the default password hackme. This image removes it everywhere, including from the commented examples in the configuration file, and generates per-VM secrets instead.
Prove it for yourself. The default appears nowhere in the configuration, and it does not authenticate. Also, icecast2.service declares a hard Requires dependency on the first-boot rotation, so it cannot start without real per-VM credentials:
sudo grep -c hackme /etc/icecast2/icecast.xml || echo "0 (the upstream default password is not present)" curl -s -o /dev/null -w "admin:hackme -> HTTP %{http_code}\n" -u admin:hackme http://127.0.0.1/admin/stats systemctl show icecast2 -p Requires --valueExpected output:
0 (the upstream default password is not present) admin:hackme -> HTTP 401 icecast-liquidsoap-firstboot.service system.slice sysinit.target -.mountStep 8 - Open the status page
Browse to http://<vm-public-ip>/. The public status page lists every active mountpoint with its stream name, description, content type, listener count and current track. It also provides M3U and XSPF playlist links and an inline player.
Because the appliance boots streaming, you will see the live /stream.ogg mountpoint with its current track set by Liquidsoap.
Step 9 - Explore the admin interface
Browse to http://<vm-public-ip>/admin/ and sign in as admin with the password from Step 5. Admin Home shows global server statistics: the resolved host, total connections, current listeners, source count and server version.
Mountpoint List shows every active mountpoint with its live controls:
- List Clients shows who is connected.
- Move Listeners migrates an audience to another mountpoint without interrupting them.
- Update Metadata changes the track title shown to listeners.
- Kill Source disconnects the broadcaster.
Step 10 - Inspect connected listeners
From the Mountpoint List, choose List Clients on the /stream.ogg mountpoint. This shows each connected listener, with their IP address, how long they have been connected and the player they are using. Each row has a Kick action to disconnect a single listener.
Step 11 - Replace the demo source with your own playlist
The station is driven by a Liquidsoap script at /opt/sac-radio/sac-radio.liq, run by sac-radio.service. Out of the box it streams a generated reference tone, so the appliance is demonstrably live without shipping anyone's music.
To broadcast your own library, upload your audio to a directory the sac-radio user can read. Then edit the script to play a playlist instead of the tone. Replace the radio = ... source line with a playlist source, and keep the output.icecast(...) block as is:
# /opt/sac-radio/sac-radio.liq source_password = environment.get("ICECAST_SOURCE_PASSWORD")
# Play everything under /srv/music on shuffle, and never fall silent. radio = mksafe(playlist(mode="randomize", "/srv/music")) output.icecast( %vorbis(quality=0.4), host="localhost", port=8000, password=source_password, mount="/stream.ogg", name="My Station", description="My internet radio", genre="Various", public=false, radio)The Icecast source password is injected from /var/lib/sac/config/sac-radio/sac-radio.env, which first boot populated with this VM's ICECAST_SOURCE_PASSWORD. You never hard-code a secret in the script. Apply your changes with:
sudo systemctl restart sac-radioLiquidsoap reconnects to Icecast within a couple of seconds, and your playlist replaces the demo tone on /stream.ogg.
Liquidsoap can do much more than play a folder. It supports crossfades, scheduled shows with switch, live input that takes over from the playlist, request queues, jingles and per-track normalization. See the Liquidsoap documentation for the full language.
Step 12 - Broadcast from an external source client instead
You can also disable the built-in Liquidsoap source and broadcast from a source client on your machine. Stop sac-radio (sudo systemctl stop sac-radio), then point any Icecast-compatible client at the server using the source password from Step 5:
Server / host : <vm-public-ip> (or your DNS name from Step 13) Port : 8000 Mountpoint : /stream.ogg Username : source Password : the ICECAST_SOURCE_PASSWORD value from Step 5 Format : Ogg Vorbis, Opus or MP3Popular choices are butt (Broadcast Using This Tool) and Mixxx for live shows, and OBS Studio for streaming a desktop or console audio feed.
Once connected, the mountpoint appears immediately on the status page. Listeners can tune in at http://<vm-public-ip>:8000/stream.ogg.
Step 13 - Set your public hostname
Icecast uses the <hostname> setting to build the stream URLs it advertises. These appear as the listen URLs on the status page and in the M3U and XSPF playlists that listeners download.
On first boot the appliance resolves this automatically. However, Azure's instance metadata service does not report a public IP for every VM configuration, so it may have fallen back to the private address of the VM. Check what it resolved to:
grep -E '<hostname>' /etc/icecast2/icecast.xmlIf that is a private address (for example 10.x.x.x), playlists handed to external listeners will not work. It is good practice in any case to publish a stable DNS name rather than an IP, because an Azure public IP can change.
Set it to the name or address your listeners will use, then restart Icecast:
sudo sed -i -E 's#<hostname>[^<]*</hostname>#<hostname>radio.your-domain.example</hostname>#' /etc/icecast2/icecast.xml
sudo systemctl restart icecast2Maintenance
- Station script: the Liquidsoap station lives in
/opt/sac-radio/sac-radio.liq. Restart withsudo systemctl restart sac-radioafter editing. Check what it is doing withjournalctl -u sac-radio -f. - Icecast configuration: everything lives in
/etc/icecast2/icecast.xml. Restart withsudo systemctl restart icecast2after editing. Common changes are raising<clients>in<limits>for a larger audience, and adding<mount>sections to set per-mountpoint limits or fallback streams. - Logs: Icecast access and error logs are in
/var/log/icecast2/. Liquidsoap logs to the journal (journalctl -u sac-radio). - Rotating passwords: edit the
<source-password>,<relay-password>and<admin-password>values in/etc/icecast2/icecast.xmland restart Icecast. If you change the source password, update/var/lib/sac/config/sac-radio/sac-radio.envto match and restartsac-radio. The first-boot generator only runs once, so it does not overwrite your changes. - Security updates: unattended security upgrades are enabled, so the OS keeps itself patched. Reboot when a new kernel is installed.
- TLS and access control: for a public station, front Icecast with your own domain and a TLS-terminating reverse proxy or Azure Application Gateway. Restrict the admin interface in the NSG to the networks that need it.
Support
SecureAnyCloud provides 24/7/365 expert technical support for this image. Contact sales@secureanycloud.com.
Icecast is developed by the Xiph.Org Foundation and Liquidsoap by savonet. Both are licensed under the GNU General Public License version 2. The corresponding source is available from the Ubuntu archive with apt-get source icecast2 for Icecast, and from github.com/savonet/liquidsoap for Liquidsoap.
This image is provided by SecureAnyCloud and is not affiliated with or endorsed by the Xiph.Org Foundation or savonet. Additional charges apply for build, maintenance and 24/7 support.
Deploy on Azure
Launch Icecast + Liquidsoap Internet Radio Station on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com