Files
radio-free-elsewhere/SETUP.md
T
Daniel MesserandClaude Opus 5.5 f659b09a0b Show the queued show and its start time in the index.php sidebar
- Shows get a description and an icon upload; broadcasts get a scheduled_at
  start time. schema.sql adds the columns to existing databases and seeds
  the descriptions from the old hand-written sidebar.
- The dashboard and cli/set_show.php take an optional date and Eastern start
  time when queuing; index.php shows it with the UTC conversion.
- liveBroadcast() and currentShow() ignore broadcasts unseen for longer than
  the grace period, so a stopped poller can't leave a show stuck as live.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 09:30:20 -05:00

8.7 KiB

Setting Up Radio Free Elsewhere on Yunohost

This guide covers installing the Radio Free Elsewhere website on a Yunohost server: the public pages, the admin backend, the database and the track-history poller. It assumes Icecast is already running and streaming; setting up Icecast itself is not covered here.

You'll need:

  • Admin access to the Yunohost web panel
  • SSH access to the server with sudo
  • An SFTP client
  • A copy of this repository

Throughout this guide, my_webapp stands for the app's system user and /var/www/my_webapp/www stands for the site's folder. Yours may differ (a second install becomes my_webapp__2, for example), so substitute your own values wherever they appear.

1. Install the My Webapp app

The site is plain PHP with a MariaDB database, which is what Yunohost's My Webapp app provides.

  1. In the Yunohost admin panel, go to Applications → Install and choose My Webapp.
  2. Pick the domain and path for the site.
  3. Set an SFTP password. You'll use it to upload files.
  4. Choose a PHP version (8.1 or newer) and MySQL as the database.
  5. Install.

Yunohost creates a system user for the app, a PHP-FPM pool that runs as that user, and a database with its own database user.

Note the PHP version you picked. You'll need the matching command-line PHP for the cron job and the CLI tools.

2. Check PHP

The site needs these PHP extensions: pdo_mysql, mbstring and fileinfo. It also needs allow_url_fopen turned on, because it fetches the Icecast status and album art over HTTPS. These are normally present on Yunohost. To check over SSH, run:

ls /usr/bin/php*        # find the CLI matching your chosen version, e.g. /usr/bin/php8.2
/usr/bin/php8.2 -m | grep -Ei 'pdo_mysql|mbstring|fileinfo'
/usr/bin/php8.2 -i | grep allow_url_fopen

Use that same versioned binary (for example /usr/bin/php8.2) everywhere this guide runs PHP. The plain php command may point to a different version that lacks the MySQL driver.

3. Upload the site

Connect over SFTP as the app user (my_webapp, with the password from step 1). Then upload the repository's contents into the site folder (www/), so that index.php sits at /var/www/my_webapp/www/index.php.

Don't upload .git, archive/ or unneededsections.html; the site doesn't need them.

On later deployments, never overwrite config/db_credentials.php or the contents of images/backgrounds/ on the server. Both belong to that server.

4. Create the database tables

Find the database name, database user and password Yunohost created:

sudo yunohost app setting my_webapp db_name
sudo yunohost app setting my_webapp db_user
sudo yunohost app setting my_webapp db_pwd

Then apply the schema. It creates the tables and adds the five shows with starting descriptions, and it's safe to re-run. Re-run it after updates that change the schema; it adds any new columns to an existing database:

cd /var/www/my_webapp/www
mysql -u <db_user> -p <db_name> < sql/schema.sql

If the database user lacks permission to create tables, run it as root instead:

sudo mysql <db_name> < sql/schema.sql

5. Add the database credentials

Copy the template, then edit the copy:

cd /var/www/my_webapp/www/config
sudo cp db_credentials.example.php db_credentials.php
sudo nano db_credentials.php

Fill in database, username and password with the values from step 4, and leave host, port and charset as they are.

Then make the file readable by the app user only:

sudo chown my_webapp:my_webapp db_credentials.php
sudo chmod 640 db_credentials.php

The web server and the cron job both run as the app user, so they can read it. The file is gitignored and is never committed.

6. Make the backgrounds folder writable

Show background images and icons are uploaded through the admin pages into images/backgrounds/. The app user needs to be able to write there:

sudo chown my_webapp:my_webapp /var/www/my_webapp/www/images/backgrounds
sudo chmod 755 /var/www/my_webapp/www/images/backgrounds

Uploads are limited to 5 MB. PHP's post_max_size must be at least that; the default of 8 MB is fine.

7. Create an admin account

Create the account as the app user, so the script can read the credentials file:

cd /var/www/my_webapp/www
sudo -u my_webapp /usr/bin/php8.2 cli/create_admin.php <username>

You'll be prompted for a password of at least 12 characters. Running the same command again for an existing username resets that account's password. The site never sends email, so this command is the only way to reset a password.

Log in at /admin/ on your site to check it works.

8. Set up the track-history cron job

Don't skip this step. Without it, the recently played list on live.php stays empty and queued shows never go live, even though the now-playing widget looks fine. The widget reads Icecast directly; the recently played list only shows what the poller has saved to the database.

cli/poll_icecast.php must run once a minute. Each run checks Icecast four times, 15 seconds apart. It starts broadcasts when the stream comes online, records each new track and ends broadcasts once the stream has been gone for five minutes.

Test it by hand first

Start a stream, then run the poller as the app user:

sudo -u my_webapp /usr/bin/php8.2 /var/www/my_webapp/www/cli/poll_icecast.php

It takes about 45 seconds and prints nothing when it succeeds. The current track should then appear on live.php. If it prints an error instead, fix that before going on. The most common one is the credentials file not being readable by this user (see step 5).

Add the cron job

Create a cron file:

sudo nano /etc/cron.d/rfe-poll-icecast

Put this single line in it, with your user, PHP version and path, and finish the file with a newline:

* * * * * my_webapp /usr/bin/php8.2 /var/www/my_webapp/www/cli/poll_icecast.php 2>&1 | logger -t rfe-poll

Then set its ownership and permissions:

sudo chown root:root /etc/cron.d/rfe-poll-icecast
sudo chmod 644 /etc/cron.d/rfe-poll-icecast

Things to know about this file:

  • Use /etc/cron.d, not a personal crontab. It survives Yunohost upgrades, and its sixth field names the user the job runs as.
  • Run it as the app user, the same user PHP-FPM uses. Other users usually can't read the credentials file.
  • Don't put a dot in the filename. Cron silently ignores files in /etc/cron.d whose names contain one, so rfe-poll-icecast.cron would never run.
  • The file must be owned by root and not writable by anyone else, or cron ignores it.
  • The logger part keeps errors. Anything the poller prints goes to the system journal under the tag rfe-poll instead of being thrown away.

Check it's running

After a couple of minutes, run:

journalctl -u cron --since "10 min ago"          # the job should appear once a minute
journalctl -t rfe-poll --since "10 min ago"      # poller errors; empty means all is well

During your next stream, tracks should start appearing on live.php within a minute.

9. Before each broadcast

  1. Queue the show from the admin dashboard, or over SSH, ideally with its date and start time (Eastern). The main page's sidebar then shows the show, its description and the start time with a UTC conversion:

    sudo -u my_webapp /usr/bin/php8.2 cli/set_show.php                           # list shows
    sudo -u my_webapp /usr/bin/php8.2 cli/set_show.php <slug>                    # queue one
    sudo -u my_webapp /usr/bin/php8.2 cli/set_show.php <slug> 2026-10-30 19:30   # queue one with a start time
    
  2. Start streaming. Within a minute, the poller starts the queued broadcast. The live page's heading and background switch to the show, and tracks begin to appear.

  3. Point listeners to live.php.

If you forget to queue a show, the broadcast is still recorded without one. You can assign a show from the dashboard while you're live.

Troubleshooting

The recently played list says "Nothing played yet" during a stream. The poller isn't saving tracks. Check that the cron file exists and is named correctly (step 8). Look at journalctl -t rfe-poll for errors, and try the manual run while streaming.

The recently played list says "Unable to load recently played tracks". The site can't reach the database. Check config/db_credentials.php and confirm the schema was applied (step 4).

The admin dashboard shows a queued show that never goes live. This is the same cause as an empty recently played list: the poller isn't running.

Background image uploads fail. The app user can't write to images/backgrounds/ (see step 6), or the image is over 5 MB.

Tracks disappear after the show. That's expected. Track history is cleared ten minutes after a broadcast ends.