Icecast is an open source streaming server that accepts an audio feed from a source client and relays it over HTTP to any number of listeners, which makes it the usual backbone for internet radio stations and live audio broadcasts. In this tutorial you will install Icecast on Ubuntu 24.04, replace its default passwords, define a mount point, and build an automated 24/7 radio station with Liquidsoap running as a systemd service. You will also connect a live source client, read listener statistics and set up a relay.

Prerequisites

To follow this guide you need:

  • A server running Ubuntu 24.04 LTS, for example a CubePath VPS. 1 vCPU and 1 GB of RAM are enough for a small station.
  • A non-root user with sudo privileges and UFW enabled.
  • A few MP3 files to play, and optionally a domain (your_domain) pointing to your_server_ip.

Plan your bandwidth: each listener consumes the stream bitrate continuously, so 100 listeners at 128 kbps need about 12.8 Mbps of upload.

Step 1 - Installing Icecast

Icecast is available in the Ubuntu archive as icecast2:

sudo apt update
sudo apt install -y icecast2

During installation a dialog asks whether to configure Icecast2. You can answer No, because you will set the hostname and passwords directly in the configuration file in the next step, which is easier to review.

Enable the service and check that it is running:

sudo systemctl enable --now icecast2
systemctl status icecast2 --no-pager
● icecast2.service - LSB: Starts the icecast audio streaming server daemon
     Loaded: loaded (/etc/init.d/icecast2; generated)
     Active: active (running) since ...

Icecast listens on port 8000 by default. Confirm it with ss:

sudo ss -tlnp | grep 8000
LISTEN 0      5            0.0.0.0:8000       0.0.0.0:*    users:(("icecast2",pid=1234,fd=4))

Step 2 - Configuring passwords, hostname and limits

The configuration lives in /etc/icecast2/icecast.xml. The package ships with the password hackme for sources, relays and the administrator, so change them before opening the port. Generate three random passwords:

for i in 1 2 3; do openssl rand -base64 18; done

Open the configuration file:

sudo nano /etc/icecast2/icecast.xml

Find the <authentication> block and replace the values with your own passwords (your_source_password, your_relay_password and your_admin_password are placeholders):

<authentication>
    <source-password>your_source_password</source-password>
    <relay-password>your_relay_password</relay-password>
    <admin-user>admin</admin-user>
    <admin-password>your_admin_password</admin-password>
</authentication>

Set <hostname> to the domain or IP that listeners use. Icecast uses it to build the links in its status pages and playlists:

<hostname>your_domain</hostname>

In the <limits> block, <clients> is the maximum number of simultaneous connections (listeners plus sources) and <sources> the maximum number of feeds. Adjust them to your bandwidth:

<limits>
    <clients>200</clients>
    <sources>4</sources>
    <queue-size>524288</queue-size>
    <client-timeout>30</client-timeout>
    <header-timeout>15</header-timeout>
    <source-timeout>10</source-timeout>
    <burst-on-connect>1</burst-on-connect>
    <burst-size>65535</burst-size>
</limits>

burst-size sends the first 64 KB to a new listener at once so playback starts quickly.

Finally, describe your station with a mount point. Add this block inside <icecast>, for example right after </limits>:

<mount type="normal">
    <mount-name>/radio.mp3</mount-name>
    <max-listeners>180</max-listeners>
    <public>0</public>
    <stream-name>My Radio</stream-name>
    <stream-description>Music around the clock</stream-description>
    <genre>Various</genre>
</mount>

Setting <public> to 1 would list the stream in public directories; keep it at 0 until the station is ready.

Validate the XML and restart Icecast. xmllint is part of libxml2-utils:

sudo apt install -y libxml2-utils
xmllint --noout /etc/icecast2/icecast.xml && sudo systemctl restart icecast2

No output from xmllint means the file is well formed. Allow the port through the firewall:

sudo ufw allow 8000/tcp

Browse to http://your_server_ip:8000. You should see the Icecast status page, with no active mount points yet.

Step 3 - Creating an automated station with Liquidsoap

A source client sends audio to Icecast. For an unattended station, Liquidsoap is the standard choice: it plays playlists, handles crossfades and jingles, and reconnects automatically if Icecast restarts.

Install Liquidsoap and create a dedicated user and a music directory:

sudo apt install -y liquidsoap
sudo useradd --system --home-dir /srv/radio --shell /usr/sbin/nologin radio
sudo install -d -o radio -g radio /srv/radio /srv/radio/music
sudo install -d -o root -g radio -m 0750 /etc/radio

Copy some MP3 files into /srv/radio/music, for example with rsync from your computer, then give the radio user read access:

sudo chown -R radio:radio /srv/radio/music

Create the Liquidsoap script:

sudo nano /etc/radio/radio.liq
settings.log.stdout := true
settings.log.file := false

# Play the music folder in random order and pick up new files automatically
music = playlist(mode="randomize", reload_mode="watch", "/srv/radio/music")

# Fall back to silence instead of stopping if the playlist is empty
radio = mksafe(music)

output.icecast(
  %mp3(bitrate=128),
  host="localhost",
  port=8000,
  password="your_source_password",
  mount="/radio.mp3",
  name="My Radio",
  description="Music around the clock",
  radio
)

The file contains the source password, so restrict it to root and the radio group:

sudo chown root:radio /etc/radio/radio.liq
sudo chmod 640 /etc/radio/radio.liq

Run the script once in the foreground to catch errors; stop it with Ctrl+C after it connects:

sudo -u radio liquidsoap /etc/radio/radio.liq
... [output.icecast:3] Connecting mount /radio.mp3 for source@localhost...
... [output.icecast:3] Connection setup was successful.

Now create a systemd unit so the station starts at boot:

sudo nano /etc/systemd/system/liquidsoap-radio.service
[Unit]
Description=Liquidsoap radio automation
After=network-online.target icecast2.service
Wants=network-online.target

[Service]
User=radio
Group=radio
ExecStart=/usr/bin/liquidsoap /etc/radio/radio.liq
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Enable and start it:

sudo systemctl daemon-reload
sudo systemctl enable --now liquidsoap-radio
systemctl status liquidsoap-radio --no-pager

Confirm the mount is live. Icecast exposes its status as JSON:

curl -s http://localhost:8000/status-json.xsl
{"icestats":{"admin":"icemaster@localhost","host":"your_domain","location":"Earth","server_id":"Icecast 2.4.4", ... "source":{"audio_info":"bitrate=128","genre":"Various","listeners":0,"listenurl":"http://your_domain:8000/radio.mp3","server_name":"My Radio", ... }}}

Listen with any player, for example VLC or a browser, at http://your_domain:8000/radio.mp3.

Step 4 - Broadcasting live from a source client

To go live from your computer, use a desktop source client such as BUTT (Broadcast Using This Tool) or Mixxx. Stream to a separate mount so your live show and the automated playlist do not collide. In BUTT, open Settings > Main > Server > Add and fill in:

  • Type: Icecast
  • Address: your_domain
  • Port: 8000
  • Password: your source password
  • Icecast mount: /live.mp3
  • Icecast user: source

Click Play in BUTT to start streaming, then check that /live.mp3 appears on http://your_domain:8000.

To switch listeners between the live show and the playlist automatically, make the live mount fall back to the automated one. Add this block to icecast.xml and restart Icecast:

<mount type="normal">
    <mount-name>/live.mp3</mount-name>
    <fallback-mount>/radio.mp3</fallback-mount>
    <fallback-override>1</fallback-override>
</mount>

With this setup, point listeners to /live.mp3: when the live source disconnects they are moved to /radio.mp3, and fallback-override moves them back when the DJ reconnects. Both streams must use the same format and bitrate for the switch to be seamless.

Step 5 - Reading listener statistics

The public JSON status is the easiest way to feed a website widget or a monitoring system. Extract the listener count with jq:

sudo apt install -y jq
curl -s http://localhost:8000/status-json.xsl | jq '.icestats.source | if type == "array" then .[] else . end | {mount: .listenurl, listeners}'
{
  "mount": "http://your_domain:8000/radio.mp3",
  "listeners": 3
}

The source field is an object when there is one mount and an array when there are several, which is why the filter handles both. For per-listener details (IP address, user agent, connection time), query the admin API with the admin credentials:

curl -s -u admin:your_admin_password "http://localhost:8000/admin/listclients?mount=/radio.mp3"

Icecast also records every listener session in /var/log/icecast2/access.log, which you can analyze with standard log tools.

Step 6 - Relaying a stream from another server (optional)

A relay pulls a stream from another Icecast server and redistributes it, which spreads listener load across locations. On the relay server, add a <relay> block to icecast.xml:

<relay>
    <server>origin.example.com</server>
    <port>8000</port>
    <mount>/radio.mp3</mount>
    <local-mount>/radio.mp3</local-mount>
    <on-demand>0</on-demand>
    <relay-shoutcast-metadata>1</relay-shoutcast-metadata>
</relay>

Restart Icecast on the relay and confirm that /radio.mp3 appears in its status-json.xsl. With <on-demand>1</on-demand> the relay only connects to the origin while at least one listener is tuned in.

Troubleshooting

The source client gets "authentication failed" or 401. The source password or username does not match icecast.xml. The default source username is source. Check the log with sudo tail -n 50 /var/log/icecast2/error.log.

Liquidsoap fails with an unknown encoder error for %mp3. Your Liquidsoap build lacks MP3 encoding. Replace %mp3(bitrate=128) with %vorbis, change the mount to /radio.ogg, and update the mount name in icecast.xml.

Listeners are refused when the station is busy. You reached <clients> or the mount's <max-listeners>. Raise the limits if your bandwidth allows it and restart Icecast.

Changes to icecast.xml have no effect. Icecast only reads the file at startup. Validate it with xmllint --noout and restart the service.

Conclusion

Icecast is now serving an automated radio station from Liquidsoap on Ubuntu 24.04, with custom passwords, a defined mount point, live broadcasting through a fallback mount and listener statistics in JSON. As next steps, put Icecast behind Nginx with a Let's Encrypt certificate so browsers can play the stream over HTTPS, add jingles and crossfades to the Liquidsoap script, and set up relays in other regions as your audience grows.