Add Yunohost setup guide and make the poller lock per-script

The poller's lock file in /tmp could be left owned by another user after a
manual run, leaving cron unable to open it. Lock the script file instead.

SETUP.md walks through installing the site on Yunohost, including the
/etc/cron.d entry for the poller, which was missing on the server and left
the recently played list empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daniel MesserandClaude Opus 5.5 committed 2026-10-29 20:48:52 -05:00
1 parent 5c5e2e17ba
commit 6e8b473dff
3 files changed
+210 -3

No files matched your search

+201
View File
@@ -0,0 +1,201 @@
# 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:
```bash
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:
```bash
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, and it's safe to re-run:
```bash
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:
```bash
sudo mysql <db_name> < sql/schema.sql
```
## 5. Add the database credentials
Copy the template, then edit the copy:
```bash
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:
```bash
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 are uploaded through the admin pages into `images/backgrounds/`. The app user needs to be able to write there:
```bash
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:
```bash
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:
```bash
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:
```bash
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:
```bash
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:
```bash
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:
```bash
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
```
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.