⚘ April Chu
𞠕 Last updated on 11.30.2023
When you liberate programming from the requirement to be professional and scalable, it becomes a different activity altogether, just as cooking at home is really nothing like cooking in a commercial kitchen. I can report to you: not only is this different activity rewarding in almost exactly the same way that cooking for someone you love is rewarding, there’s another feeling, too, specific to this realm…What is this feeling? Independence? Security? Sovereignty?
𞠕 Robin Sloan, An App Can Be A Home-cooked Meal
This manual is not a technical tutorial to building a reliable and scalable online radio. It is not intended to be an authoritative or exhaustive reference.
Instead, this guide is an invitation to build your own “home-cooked” radio. This manual will walk through how to assemble free and open source software on a Raspberry Pi to stream audio online. It covers the construction of a radio within a local network and offers steps to make it public (if and when you choose to do so). It is for those who have no experience with servers and the command line, for people who have even the slightest interest in building or understanding networks and infrastructure.
This guide aims to serve as a resource to those seeking to participate as collaborators, and not mere consumers, in our increasingly technical world. This guide aligns with notions of liberating technological creation from industrial hands. I hope that the act of creating handmade platforms built by and for us, we can begin to re-enchant our digital realms. Even more so, I hope that you will begin to engage with new feelings of independence, security, and sovereignty.
Before we begin building the radio, let’s take a step back and look at ① the parts of a network and ② the Internet radio toolchain.
A “local network” refers to a network within a scoped geographic area like a home or office. Devices within a local network can communicate directly with each other without the Internet using local IP addresses.
Internet Service Provider (ISP): The company that provides your local network with an Internet connection.
Local Network Devices: The devices connected to your local network such as computers, smartphones, and IoT (Internet of Things) devices. The Raspberry Pi is a server within the local network, hosting various services like a web and radio server.
Networking Equipment
Network Services
Most of the data that flows in and out of your home is managed automatically by the network devices.
Let’s picture a Raspberry Pi connected to your home’s local network.
For all outbound traffic from the Pi, like streaming music online, the router assigns a private IP to the Raspberry Pi and uses NAT to replace the private address with the router’s public IP. The request is forwarded to the Internet, traveling through the modem to your ISP to the target server. The target server processes the request, generates a response, and sends it back through the same path. Your router uses NAT to direct the response back to the Pi by replacing its public IP with the Pi’s private IP.
Inbound traffic, such as accessing a website hosted on the Pi, first reaches the router’s public IP address. The router uses NAT to forward the requests to the Raspberry Pi’s local IP address and the appropriate port. The Pi processes the request and sends an appropriate response back through the router. The responses traverse the modem and reach the device that initiated the request.
Beyond the automatic processes handled by the networking equipment, there are additional actions needed to secure external access to services hosted on the Pi:
Online radio is usually composed of three parts:
For this project, Broadcast Using This Tool (BUTT) is the stream generator. It captures and encodes audio to send to the Icecast server. Icecast is the streaming media server hosted on the Pi that distributes the stream from the Pi to listeners. Listeners can use the stream’s web page as the media player to tune in to the broadcast.
Additionally, we will be using a virtual audio cable to connect output from VLC to BUTT. This will allow us to stream pre-recorded media as well as broadcast live input at the some time.
You will need a Raspberry Pi and peripherals to interact with the computer:
I have not included any audio equipment. For the purposes of testing out your radio, having a computer with a microphone and speakers is sufficient. You can get additional equipment for the Pi if you want to broadcast from the Pi.
This guide prioritizes open source software. The following software are available to download and use for free:
The Raspberry Pi website has great documentation on how to set up your Pi out of the box. We will mostly be interfacing with the Raspberry Pi through the terminal in this guide.
Common Terminal Commands
sudo
: Stands for "Super User Do." Allows user to execute commands with elevated privileges.apt
: Stands for "Advanced Package Tool." A package management system install and remove software packages.systemctl
: Manages services and provides commands to start, stop, restart, enable, disable, and view status.nano
: Opens up a lightweight text editor within the terminal.
First, install the Apache web server. We need to set up a web server to use with Icecast, the streaming media server. This enables us to access Icecast’s web-based administration interface and host a webpage.
sudo apt update
sudo apt upgrade
sudo apt install apache2
Y
for “Yes” and hit Enter
sudo systemctl start apache2
sudo systemctl enable apache2
http://localhost/
on the Pi’s browser or enter the Pi’s IP address on another computer on the local network. You should see the Apache 2 default welcome page.hostname -I
Install Icecast2, the media streaming server.
sudo apt install icecast2 -y
Yes
on the pop-up that asks if you want to configure Icecast. Don’t change anything, just hit Enter
.sudo nano /etc/icecast2/icecast.xml
Source Password
(used for the source client authentication) and Admin Password
(used for authenticating admin features of Icecast) for security. You can read the Icecast Documentation to learn more about basic setup.systemctl restart icecast2
systemctl status icecast2
http://192.168.0.34:8000/
(use the IP address of your Pi) to see the status page of your stream. There will be nothing under “Server Status” because you have not started a stream yet. We have to install BUTT or a stream generator software to begin broadcasting. Download and configure BUTT, the stream generator.
Download Location
You can download BUTT on your Pi or your computer, depending on where you want to stream audio from. I downloaded it on both but remember that if you use your Pi to stream audio you need a mic for audio input and speakers or headphones for output.
Before installing anything, update and upgrade the system
sudo apt-get update
sudo apt-get upgrade
Choose and download the appropriate source package for your OS from the BUTT site and follow the installation directions on the manual.
Preferences
> Add/Remove Software
.butt
. Check the box next to the highlighted package and click Apply
. This will install the butt
.Sound & Video
you should see butt
as an available application.Open BUTT from terminal or by opening the application from the GUI.
butt
Go to Settings
> Main
> Server Settings
> Add
to add a server and link your BUTT broadcast to your Icecast2 stream.
localhost
or the IP address of your Pi8000
is the default from Icecast2 but use the number at <listen-socket>
in the Icecast2 configuration file<source-password>
stream
source
Hit the Play button on BUTT to begin the stream
http://localhost:8000/stream
or replace localhost
with the IP address of your Pihttp://localhost:8000/stream
, make sure you have configured the input device on BUTT. Click on Settings
, go to the Audio
tab, and choose a device under Primary Audio Device
.We're local!
We now have a working local radio. Now you should be able to hear your broadcast from
http://localhost:8000/stream
. The radio can only be accessed from devices connected to the same local network and not available publicly on the Internet. We have to make some configurations so that listeners can stream the broadcast.
If you want to stream pre-recorded media, like a playlist, you should connect VLC to BUTT with a virtual audio cable (VAC).
Download VLC from the website. Make sure to choose the appropriate package for your operating system.
Download VB-Cable VAC from the website. This is currently only available on Windows and MacOS. For Linux, try Jack Audio Connection Kit (JACK).
Latency
to 7168 smp
. This will help synchronize the audio from VLC to the Icecast stream so we can hear the media from VLC on the stream.Open VLC and upload some media to the Playlist
. Go to Audio
> Audio Device
and choose VB-Cable
or the name of the VAC you are using. This will output the media from VLC to the VAC.
Open BUTT and go to Settings
> Audio
to change the input devices.
Macbook Microphone
as the Primary Audio Device
and VB-Cable
as the Secondary Audio Device
. This allows me to stream the media from VLC and my microphone input at the same time. You can set VB-Cable
as the only audio device if you only want to stream from VLC.Verify the media is streaming from VLC
http://localhost:8000/stream
. You should be able to hear the media from VLC.You might find it helpful to set up SSH on your Pi so you can access the computer remotely. SSH lets you control the Pi from your laptop without setting up a monitor.
Follow this guide from Tom's Hardware.
Make sure you know our username and password for the Pi. To change the default password:
passwd
Enable SSH
Option 01: Enable SSH through the Pi desktop
Preferences
> Raspberry Pi Configuration
Interfaces
tab and toggle on SSH
Option 02: Enable SSH from the terminal
sudo raspi-config
Select Interface Options
Select SSH
. Then choose Yes
when asked to enable SSH. Hit Enter
on the confirmation box.
Make sure you select Finish
at the end
Check if SSH is running. If not, start the SSH service.
# Check SSH status
sudo service ssh status
# Start SSH
sudo service ssh start
Disable Root Login
Disabling direct root login enhances the security of your system by reducing the risk of unauthorized access. It's recommended to log in as a regular user and then use
sudo
to perform administrative tasks.
nano /etc/ssh/sshd_config
#PermitRootLogin prohibit-password
#PermitRootLogin no
sudo systemctl restart sshd
Now we should be able to login from another computer on the same network!
ssh username@[address]
username
and address
with your username and Pi’s IP address (ex ssh april@192.168.0.20
).username@rpi:~
at the beginning of the line in your terminal.To exit out of SSH use:
exit
Once your radio is working locally, we can set up port forwarding and dynamic DNS to make sure your radio is available publicly.
If your Raspberry Pi is connected to a router, you’ll need to set up port forwarding to forward external traffic to your Raspberry Pi’s local IP address. I set up port forwarding on 8000 (for Icecast), port 80 (for HTTP), port 22 (for SSH), and port 443 (for HTTPS).
192.168.0.1
or 192.168.1.1
. If you’re not sure, check your router’s documentation or your ISP. My router had a label on the bottom of the device with the address and settings password.Service | Internal IP Address | Internal Port | External Port | Protocol |
---|---|---|---|---|
Icecast | Pi’s Local IP | 8000 | 8000 | Both (TCP & UDP) |
SSH | Pi’s Local IP | 22 | 22 | TCP |
HTTP | Pi’s Local IP | 80 | 80 | TCP |
HTTPS | Pi’s Local IP | 443 | 443 | TCP |
- If your router settings uses port ranges (ex: local start port, local end port, external start port, external end port), just set them all to the same port number.
- Port 8000 is the default port for Icecast. If you changed the port number in your Icecast configuration file, use the port that you specified. This should also be the same port you used in your BUTT settings.
The public IP address assigned to your router is often dynamic, meaning it can change periodically due to actions by your Internet Service Provider (ISP) or when you switch networks. By configuring a Dynamic DNS, you can associate a domain name with your router’s changing public IP address. This makes it easier to maintain the access to your stream.
I provide steps to register with two free DDNS providers, No-IP and DuckDNS. No-IP requires you to manually confirm that the hostname is in use every 30 days while DuckDNS does not require any verification. I found that I ran into more issues with network security using a DuckDNS hostname which is why I switched over to No-IP.
No-IP will send you and email every 30 days to confirm that the hostname is still in use. If you do not confirm the hostname is active, your hostname will be deleted.
Register with No-IP
Dynamic DNS
tab > No-IP Hostname
. If you created a hostname, you should be able to see your hostname on the dashboard. If not, create a hostname.IP/ Target
and make sure the Hostname Type
is DNS Hostname A
. This will map your hostname to the public IP address of your router, which forwards traffic to your Pi.Configure DDNS on the Raspberry Pi
Follow No-IP's official documentation.
wget https://dmej8g5cpdyqd.cloudfront.net/downloads/noip-duc_3.0.0-beta.7.tar.gz
tar xf noip-duc_3.0.0-beta.7.tar.gz
cd /home/$USER/noip-duc_3.0.0-beta.7/binaries && sudo apt install ./noip-duc_3.0.0-beta.7_armhf.deb
noip-duc -g name.ddns.net -u username -p password
name.ddns.net
with your hostname.username
and password
with your email and account password. If your password uses special characters, put it in single quotes (ex: '!Password'
) to prevent errors.Verify DDNS by entering the domain you just set up (ex http://radio.ddns.net
) into a web browser. You should see the same web page as when you use your router’s public IP.
Register with Duck DNS
Create an account on Duck DNS or sign in with an existing account.
Once you are logged in, you will see the section to add a domain. Choose a subdomain name and click Add Domain
.
You should your router’s public IP address automatically filled next the domain name. You can find your router’s public IP address by through an online IP address checker.
Configure DDNS with the Raspberry Pi
Follow the Duck DNS official documentation. Choose
pi
as the operating system.
SSH into your Pi or open the terminal on your Pi. We will be setting up a script to intermittently check the router’s IP address and to update DuckDNS with any changes.
Make a directory for duckdns, and create the script in the directory.
mkdir duckdns
cd duckdns
nano duck.sh
In the duck.sh
document, add the follow line.
echo url="https://www.duckdns.org/update?domains=YOUR_DOMAIN&token=YOUR_TOKEN&ip=" | curl -k -o ~/duckdns/duck.log -K -
Replace YOUR_DOMAIN
with the DuckDNS subdomain associated with your Pi (ex http://radio.duckdns.org
).
Replace YOUR_TOKEN
with the token provided on your DuckDNS account page.
The API will detect the IP address automatically so there is no need to enter an IP address.
Save the file (enter ctrl + X
to exit and enter Y
to save).
Make the script file executable:
chmod 700 duck.sh
Then using cron, we will make the script run every 5 minutes. First, open cron:
crontab -e
*/5 * * * * ~/duckdns/duck.sh >/dev/null 2>&1
ctrl + X
to exit and enter Y
to save).You can verify the script is running if the following comand returns a prompt.
./duck.sh
You can also check the log to see if the last attempt was successful (returns OK
).
cat duck.log
Verify DDNS by entering the domain you just set up (ex http://radio.duckdns.org
) into a web browser. You should see the same web page as when you use your router’s public IP.
A firewall is a security system that enhances the security of the Pi by regulating the flow of traffic between the Pi and local network. We have to update the Pi’s firewall rules to allow traffic at specific ports. iptables
is the command-line utility uses on a Pi to define the rules for network traffic.
Check if iptables
is installed from the terminal
sudo iptables --version
iptables
sudo apt-get update
sudo apt-get install iptables
Allow the four ports for which we have set up port forwarding.
sudo iptables -A INPUT -p tcp --dport 8000 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
Save and restart iptables
sudo service iptables save
sudo service iptables restart
Check the current firewall rules. The output should list the four ports above.
sudo iptables -L
We're public!
From a device outside of the local network that your Pi is connected to, you can access your stream from
http://public-ip:8000/stream
(replacepublic-ip
with your router's Public IP address) orhttp://radio.ddns.org:8000/stream
. Make sure you are streaming from BUTT or there will be an 404 error.
A downside with dynamic DNS hostnames is that they often get blocked by enterprise wifi networks (like school and company networks). This means blocked access to the stream.
One workaround is to buy a custom domain and connect the DDNS hostname to the domain. Using a custom domain associated with a DDNS hostname is not guaranteed to work in all situations, as network administrators can employ various methods to control access. Some domain providers like namecheap.com
offer free DDNS services with domain registration so you don’t have to use third-party DDNS services.
Purchase a domain on Namecheap
Configure Dynamic DNS on the domain in Namecheap
Enable Dynamic DNS for the domain
Domain List
, click on Manage
> Advanced DNS
> Enable the Dynamic DNS
toggle.Dynamic DNS Password
. You will need this later when configuring the Pi.Create A+Dynamic DNS records. This associates an IP Address with the domain name.
Click on Manage
for the domain. On the Advanced DNS
tab, go to Host records
.
Click on Add New Record
.
If you want your stream to be accessed at your-domain.com
and www.your-domain.com
, add the following records.
your-domain.com
)A+ Dynamic DNS Record
@
127.0.0.1
*www.your-domain.com
)A+ Dynamic DNS Record
www
127.0.0.1
*I have main website deployed on Vercel on my base domain and the stream is only accessible on the subdomain stream.domain.com
. To set up the record on a subdomain:
stream.your-domain.com
)A+ Dynamic DNS Record
stream
127.0.0.1
*You can use any IP address for
Value
. Once the DDNS client is configured, the IP address will be automatically updated.
Configure DDNS on Raspberry Pi
Like we did above when we set up DDNS, we have to configure a client to update the A record on Namecheap to correct the public IP address.
From the Pi’s terminal or via SSH, update packages and install ddclient
:
sudo apt-get update
sudo apt-get install ddclient
Open the configuration file using nano
:
sudo nano /etc/ddclient.conf
You will see the answers to the installation pop-up. Replace the file’s content:
use=web, web=dynamicdns.park-your-domain.com/getip
protocol=namecheap
server=dynamicdns.park-your-domain.com
login=[your-domain.com]
password=[your namecheap dyndns password]
[subdomain]
[your-domain.com]
with your domain nameAdvanced DNS
@
to update the base domain, www
for www.domain.com
or subdomain
for subdomain.domain.com
.Exit (CTRL + X
)and save the file (Hit Y
)
Setup the client to run at startup
sudo systemctl start ddclient.service
Update Icecast configuration
We have to update the Icecast configuration with the new hostname
Before making changes, create a backup of the Icecast configuration file
# Navigate to configuration file directory
cd /etc/icecast2/
# Create a backup of the configuration file
sudo cp icecast.xml icecast.xml.bak
Open the configuration file using nano
:
sudo nano /etc/icecast2/icecast.xml
Update the hostname
tag with your domain. If you set it up on your subdomain (stream.your-domain.com
), then use the subdomain.
<hostname>your-domain.com</hostname>
Exit (CTRL + X
)and save the file (Hit Y
)
Restart Icecast
sudo service icecast2 restart
Now if you go to your-domain.com
or stream.subdomain.com
, you should see the Icecast status page.
Update BUTT
Settings
. On the Main
tab, go to Server Settings
and click on Edit
Address
with your domain (or subdomain). Hit Save
.your-domain.com/stream
or stream.your-domain.com/stream
.Now that you have a domain, it’s a good idea to set up SSL. When your site has a HTTPS padlock, it enhances security, ensures encryption, and reduces the likelihood of browsers blocking it.
Install Cerbot, a client for Let’s Encrypt and a free Certificate Authority. From the terminal, run:
sudo apt-get update
sudo apt-get install certbot
Obtain an SSL certificate for the domain.
sudo certbot certonly --standalone -d your-domain.com
your-domain.com
with your actual domain.Check the certificate for your domain is listed when you run:
sudo certbot certificates
Configure automatic renewal
sudo certbot renew --dry-run
crontab
to add a job.sudo crontab -e
0 */12 * * * certbot renew
sudo nano /etc/icecast2/icecast.xml
<!-- Enable SSL -->
<ssl>1</ssl>
<ssl-certificate>/etc/letsencrypt/live/[your-domain.com]/fullchain.pem<ssl-certificate>
<ssl-private-key>/etc/letsencrypt/live/[your-domain.com]/privkey.pem<ssl-private-key>
<port>443</port>
[your-domain.com]
for both the <ssl-certificate>
and <ssl-private-key>
with the your actual domain.CTRL + X
) and save the changes (Y
)sudo service icecast2 restart
Broadcast Using This Tool (BUTT)
Domain Name System (DNS)
Dynamic DNS (DDNS)
Dynamic Host Configuration Protocol (DHCP)
Internet Service Provider (ISP)
IP Address
Modem
Network Address Translation (NAT)
Ports
Radio Server
Raspberry Pi
Router
Secure Shell (SSH)
Secure Sockets Layer (SSL)
Server
Web Server
Virtual Audio Cable (VAC)