Self-Hosting FreshRSS on a Raspberry Pi with Docker
RSS isn’t dead — it’s just not something most people bother setting up anymore. FreshRSS is a self-hosted feed aggregator that gives you a clean, fast, no-algorithm feed reader you fully control. This post walks through getting it running on a Raspberry Pi using Docker, including a few gotchas that’ll save you some head-scratching.
How It Works
| Component | Detail |
|---|---|
| App | FreshRSS — PHP-based self-hosted RSS aggregator |
| Container runtime | Docker (snap install on Ubuntu 25.04) |
| Database | SQLite (default, no setup required) |
| Feed refresh | Cron job inside the container — every 30 mins |
| Host | tartaria-pi-01 (Raspberry Pi, Ubuntu 25.04 aarch64) |
| Access URL | http://<pi-ip>:8081 |
Prerequisites
- Raspberry Pi running Ubuntu (tested on 25.04)
- Docker installed (snap or native)
- Basic comfort with the terminal
Step 1 — Check Port Availability
The default FreshRSS Docker example maps to port 8080, but that’s commonly occupied. Check before you run anything:
1
ss -tlnp | grep 8080
If you see a LISTEN entry, pick a different host port — 8081 is a safe fallback and what we’ll use throughout this guide.
warning: Don’t skip this check. Docker will pull the full image, start the container, and then fail on port binding — leaving a dead container you’ll need to clean up manually.
Step 2 — Run the Container
1
2
3
4
5
6
7
8
9
# freshrss/docker-run.sh
sudo docker run -d --restart unless-stopped --log-opt max-size=10m \
-p 8081:80 \
-e TZ=Australia/Brisbane \
-e 'CRON_MIN=1,31' \
-v freshrss_data:/var/www/FreshRSS/data \
-v freshrss_extensions:/var/www/FreshRSS/extensions \
--name freshrss \
freshrss/freshrss
A few things worth noting here:
-p 8081:80maps host port8081to the container’s internal port80CRON_MIN=1,31runs the feed sync at :01 and :31 past every hour- Both volumes are named Docker volumes — data persists across container restarts and upgrades
--restart unless-stoppedbrings the container back up automatically after a reboot
info:
CRON_MIN=1,31gives you a 30-minute refresh cycle. YouTube RSS feeds are rate-limited on YouTube’s end anyway, so polling faster than this won’t get you more updates.
Step 3 — Clean Up a Failed Run (If Needed)
If you ran the command with port 8080 and hit a port binding error, Docker will have left a stopped container behind with the name already claimed. Remove it before retrying:
1
sudo docker rm freshrss
Then re-run the command above with 8081.
Step 4 — Fix Docker Permissions (Snap Install)
On Ubuntu with Docker installed via snap, the docker group doesn’t exist out of the box. Without it, every Docker command requires sudo. Fix it once:
1
2
3
4
sudo addgroup docker
sudo usermod -aG docker $USER
sudo snap connect docker:home
newgrp docker
Then log out and back in (or start a new SSH session) for the group membership to take effect. After that, docker ps should work without sudo.
Step 5 — Verify It’s Running
1
2
docker ps | grep freshrss
curl http://localhost:8081
If docker ps shows the container as Up and curl returns HTML, you’re good. Hit it in your browser:
1
http://<your-pi-ip>:8081
Complete the web-based setup wizard — create your admin account and you’re in.
Database
tip: Stick with SQLite — it’s the default and requires zero configuration. Only consider switching to PostgreSQL if you’re running multiple users or have an unusually large number of feeds. MySQL/MariaDB is supported but offers no real advantage over Postgres if you do need a proper DB.
Adding Feeds
FreshRSS supports standard RSS/Atom feeds. YouTube channels expose a public RSS feed in the format:
1
https://www.youtube.com/feeds/videos.xml?channel_id=<CHANNEL_ID>
To find a channel ID, open the channel page, right-click → View Source, and search for channel_id. Paste the full URL into FreshRSS as a new subscription. On first sync it’ll pull the full available backlog — typically 2–3 months of videos.
Managing the Container
Stop / Start
1
2
docker stop freshrss
docker start freshrss
View Logs
1
2
docker logs freshrss
docker logs -f freshrss # follow
Update to Latest Image
1
2
3
4
docker stop freshrss
docker rm freshrss
sudo docker pull freshrss/freshrss
# re-run the docker run command from Step 2
Your data is safe — it lives in the named volumes, not the container.
Remove Everything (Nuclear)
1
2
3
4
docker stop freshrss
docker rm freshrss
docker volume rm freshrss_data freshrss_extensions
docker rmi freshrss/freshrss