FreshRSS Docker Install: Self-Host a Lightweight Feed Aggregator
Complete guide to self-hosting FreshRSS using Docker Compose. Build a fast, lightweight RSS feed aggregator with multi-user support and feed fetching.
System Requirements & Prerequisites
Before deploying FreshRSS, ensure your VPS meets the following requirements: * OS: Ubuntu 22.04 LTS or any modern Linux distribution with Docker installed. * Resources: Minimal resources are required (as low as 1 CPU core and 512MB RAM for small instances). * Docker Engine: v20.10+ and Docker Compose v2.0+. * Networking: Ports 80 and 443 open on the host. DNS A/AAAA records configured for your subdomain (e.g., rss.example.com).
Docker Compose Configurations
FreshRSS can be deployed using SQLite for small, single-user setups, or PostgreSQL for high-volume, multi-user deployments. Below are both configurations.
Option A: FreshRSS with SQLite (Single-User Stack)
SQLite is lightweight and requires no separate database container. All data is stored in a single file on the host.
Create a new directory /opt/freshrss and place the following docker-compose.yml inside it:
version: '3.8'
services:
freshrss:
image: freshrss/freshrss:latest
container_name: freshrss
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
environment:
- TZ=Europe/Paris
- CRON_MIN=*/20
volumes:
- ./data:/var/www/FreshRSS/data
- ./extensions:/var/www/FreshRSS/xExtension
Option B: FreshRSS with PostgreSQL (Multi-User Stack)
For multiple active users, extensive feed lists, or long retention periods, PostgreSQL provides better concurrency and reliability.
version: '3.8'
services:
freshrss:
image: freshrss/freshrss:latest
container_name: freshrss-app
restart: unless-stopped
depends_on:
freshrss-db:
condition: service_healthy
ports:
- "127.0.0.1:8080:80"
environment:
- TZ=Europe/Paris
- CRON_MIN=*/20
volumes:
- ./data:/var/www/FreshRSS/data
- ./extensions:/var/www/FreshRSS/xExtension
networks:
- freshrss-net
freshrss-db:
image: postgres:15-alpine
container_name: freshrss-db
restart: unless-stopped
environment:
- POSTGRES_DB=freshrss
- POSTGRES_USER=freshrss_user
- POSTGRES_PASSWORD=secure_db_password_here
volumes:
- ./postgres_data:/var/lib/postgresql/data
networks:
- freshrss-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U freshrss_user -d freshrss"]
interval: 10s
timeout: 5s
retries: 5
networks:
freshrss-net:
driver: bridge
Directory Setup & Permissions
The FreshRSS container runs its internal web server (Apache) as the www-data user (UID/GID 33:33). To avoid permission errors when writing configuration files or downloading feeds, set permissions on the host directories before launching.
Execute the following commands on your VPS:
# Create directory structure
mkdir -p /opt/freshrss/data /opt/freshrss/extensions
# Set ownership to www-data (UID 33, GID 33 is standard for FreshRSS alpine/debian images)
chown -R 33:33 /opt/freshrss/data /opt/freshrss/extensions
chmod -R 755 /opt/freshrss/data /opt/freshrss/extensions
If you are using PostgreSQL (Option B), also initialize the database directory:
mkdir -p /opt/freshrss/postgres_data
# Postgres container handles its own permissions on postgres_data
To start the stack, run:
cd /opt/freshrss
docker compose up -d
Reverse Proxy Configurations
Do not expose the raw port 8080 to the public internet. Use a reverse proxy with TLS termination.
Nginx Configuration
Install Nginx on your VPS:
sudo apt update && sudo apt install nginx certbot python3-certbot-nginx -y
Create a server configuration block at /etc/nginx/sites-available/rss.example.com:
server {
listen 80;
listen [::]:80;
server_name rss.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# FreshRSS API extensions require HTTP Authentication header passthrough
proxy_set_header Authorization $http_authorization;
proxy_pass_header Authorization;
# Disable buffering to allow stream updates if configured
proxy_buffering off;
}
}
Enable the configuration and obtain an SSL certificate:
sudo ln -s /etc/nginx/sites-available/rss.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d rss.example.com --non-interactive --agree-tos -m admin@example.com
Caddy Configuration
If you prefer Caddy, add this block to your /etc/caddy/Caddyfile:
rss.example.com {
reverse_proxy 127.0.0.1:8080 {
header_up Host {host}
header_up X-Real-IP {remote}
}
}
Automating Feed Refreshes
FreshRSS requires a periodic trigger to download new posts from feeds.
Method 1: Built-in Container Cron (Easiest)
By setting the CRON_MIN=*/20 environment variable in your docker-compose.yml, FreshRSS runs a cron daemon inside the container that refreshes the feeds every 20 minutes. No host-level configuration is needed.
Method 2: Host Crontab (Recommended for Performance)
For busy instances, executing via the host crontab avoids long-running cron daemons inside the container.
First, set CRON_MIN= (empty) in your docker-compose.yml to disable the internal daemon. Then, add the following entry to your host crontab:
# Open host crontab editor
crontab -e
Add this line to run the update every 15 minutes:
*/15 * * * * docker exec -u www-data freshrss php /var/www/FreshRSS/app/actualize_script.php > /dev/null 2>&1
(If you are using PostgreSQL, replace freshrss with the container name defined in docker-compose, e.g. freshrss-app).
First-Run UI & API Configuration
- Open
https://rss.example.comin your browser. - Select your language and proceed through the environment checks.
- Database Configuration:
- SQLite: Select
SQLiteand accept the default path. - PostgreSQL: Select
PostgreSQLand input the database connection details:- Host:
freshrss-db(the service name in docker-compose) - User:
freshrss_user - Password:
secure_db_password_here - Database:
freshrss
- Host:
- Create your admin user account and set a secure password.
- Log in.
Enabling API Access for Mobile Clients (Reeder, NetNewsWire, FeedMe)
To sync your read/unread status across mobile and desktop apps:
- Go to Settings > Administrative > Authentication.
- Under API compatibility (Fever, Google Reader), check Allow API access.
- Go to Settings > Profile > API.
- Set an API password (this password is separate from your web login password).
- Open your mobile app and add a Google Reader API or Fever account:
- Endpoint URL:
https://rss.example.com/api/greader.php(for Google Reader API) - Username: Your FreshRSS admin/user username.
- Password: The API password you just set in your profile settings.