FreshRSS Feed Reader Installation

FreshRSS is a lightweight, self-hosted RSS and Atom feed aggregator that lets you follow hundreds of news sources and blogs without relying on Google Reader alternatives or commercial services. With a Fever and Google Reader-compatible API, it integrates with popular mobile RSS apps, and its multi-user support with per-user feed configurations makes it suitable for both personal and family server deployments.

Prerequisites

  • Ubuntu 20.04+, Debian 11+, or CentOS/Rocky 8+
  • PHP 8.1+ with required extensions
  • A web server (Apache or Nginx)
  • MySQL/MariaDB or SQLite (SQLite works for single-user setups)
  • Root or sudo access

Installing FreshRSS

Method 1: Docker (recommended):

# Create FreshRSS directory
sudo mkdir -p /opt/freshrss/{data,extensions}

# Run with Docker
docker run -d \
  --name freshrss \
  -p 8080:80 \
  -e TZ=America/New_York \
  -e CRON_MIN="*/10" \
  -v /opt/freshrss/data:/var/www/FreshRSS/data \
  -v /opt/freshrss/extensions:/var/www/FreshRSS/extensions \
  --restart unless-stopped \
  freshrss/freshrss

# With Docker Compose for MySQL backend:
sudo tee /opt/freshrss/docker-compose.yml <<'EOF'
version: '3.8'

services:
  freshrss-app:
    image: freshrss/freshrss:latest
    restart: unless-stopped
    ports:
      - "8080:80"
    environment:
      TZ: America/New_York
      CRON_MIN: "*/10"
      FRESHRSS_ENV: production
    volumes:
      - /opt/freshrss/data:/var/www/FreshRSS/data
      - /opt/freshrss/extensions:/var/www/FreshRSS/extensions
    depends_on:
      - freshrss-db

  freshrss-db:
    image: mariadb:11
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: root-password
      MYSQL_DATABASE: freshrss
      MYSQL_USER: freshrss
      MYSQL_PASSWORD: db-password
    volumes:
      - /opt/freshrss/db:/var/lib/mysql
EOF

cd /opt/freshrss && sudo docker compose up -d

Method 2: Manual installation with Nginx:

# Install dependencies
sudo apt install -y nginx php8.1-fpm php8.1-curl php8.1-xml \
  php8.1-mbstring php8.1-zip php8.1-intl \
  php8.1-mysql php8.1-sqlite3

# Download FreshRSS
cd /var/www
sudo git clone https://github.com/FreshRSS/FreshRSS.git
sudo chown -R www-data:www-data FreshRSS/

# Set correct permissions
sudo chmod -R 755 /var/www/FreshRSS/
sudo chmod -R 775 /var/www/FreshRSS/data/

Configure Nginx for FreshRSS:

# /etc/nginx/sites-available/freshrss
server {
    listen 80;
    server_name rss.example.com;
    root /var/www/FreshRSS/p/;

    location / {
        try_files $uri $uri/ index.php;
        index index.php index.html;
    }

    location ~ ^.+\.php {
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Initial Setup

Web wizard:

  1. Navigate to http://your-server:8080 (Docker) or http://rss.example.com
  2. Select language
  3. Choose database: MySQL (production) or SQLite (testing)
  4. For MySQL, enter:
    • Host: freshrss-db (Docker) or localhost
    • Database: freshrss
    • Username/password from docker-compose.yml
  5. Create admin account
  6. Complete setup

Configure refresh schedule:

# Docker automatically sets up cron via CRON_MIN env variable
# For manual install, add cron job:
sudo -u www-data crontab -e
# Add:
# */10 * * * * php /var/www/FreshRSS/app/actualize_script.php > /dev/null 2>&1

Feed Management

Add feeds via the web interface:

  1. Click + Add a feed (left sidebar)
  2. Paste the RSS/Atom URL
  3. Click Add — FreshRSS fetches and shows a preview
  4. Assign to a category and click Add this feed

Import OPML feed list:

  1. Go to Settings > Import/Export
  2. Click Choose File and select your OPML file
  3. Click Import

Export your feeds as OPML:

# Via CLI
sudo docker compose exec freshrss-app \
  php /var/www/FreshRSS/cli/export-opml.php \
  --user admin > /opt/freshrss/backup/feeds-backup.opml

Extensions

FreshRSS supports extensions for customization:

# Available extensions: https://github.com/FreshRSS/Extensions
# Install an extension by placing it in the extensions directory

# Example: Install the Reading Time extension
cd /opt/freshrss/extensions
sudo git clone https://github.com/FreshRSS/Extensions.git /tmp/freshrss-extensions
sudo cp -r /tmp/freshrss-extensions/xExtension-ReadingTime ./

# Enable in web UI: Settings > Extensions > Reading Time > Enable

Popular extensions:

  • xExtension-ReadingTime: Estimated reading time per article
  • xExtension-CustomCSS: Apply custom CSS to the UI
  • xExtension-TwitterTimeline: Twitter integration
  • xExtension-GoogleCachedImages: Load images via Google Cache

API Access for Mobile Apps

Enable API access:

  1. Go to Settings > Authentication
  2. Check Allow API access
  3. Set an API password (can differ from your login password)

Compatible mobile apps:

AppPlatformAPI Type
Reeder 5iOS/macOSFever API
NetNewsWireiOS/macOSFever API
FeedMeAndroidGoogle Reader API
Fluent ReaderCross-platformFever API
ReadYouAndroidGoogle Reader API

Configure Fever API in mobile apps:

Server URL: https://rss.example.com/api/fever.php
Username:   your-username
Password:   your-API-password (not login password)

Configure Google Reader API:

Server URL: https://rss.example.com/api/greader.php
Username:   your-username
Password:   your-API-password

Test the API:

# Test Fever API
curl -d "api_key=$(echo -n 'username:apipassword' | md5sum | cut -c1-32)" \
  "https://rss.example.com/api/fever.php?api"

# Test Google Reader API
curl "https://rss.example.com/api/greader.php/accounts/ClientLogin" \
  -d "[email protected]&Passwd=apipassword"

User Management

Create additional users:

# Via CLI (Docker)
sudo docker compose exec freshrss-app \
  php /var/www/FreshRSS/cli/create-user.php \
  --user reader1 \
  --password "user-password" \
  --email "[email protected]"

# List all users
sudo docker compose exec freshrss-app \
  php /var/www/FreshRSS/cli/list-users.php

# Delete a user
sudo docker compose exec freshrss-app \
  php /var/www/FreshRSS/cli/delete-user.php \
  --user reader1

Database Optimization

MySQL optimization for large feed lists:

-- Connect to the database
sudo docker compose exec freshrss-db \
  mysql -u freshrss -p freshrss

-- Optimize tables periodically
OPTIMIZE TABLE freshrss_default_entrytmp;
OPTIMIZE TABLE freshrss_default_entry;

-- Check table sizes
SELECT table_name,
  ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb
FROM information_schema.tables
WHERE table_schema = 'freshrss'
ORDER BY size_mb DESC;

Configure article retention:

  1. Go to Settings > Archival
  2. Set Maximum number of articles to keep per feed: e.g., 500
  3. Set Number of days of articles to keep: e.g., 90
  4. This prevents unbounded database growth

Troubleshooting

Feeds not refreshing automatically:

# Check cron is running in the Docker container
sudo docker compose logs freshrss-app | grep cron

# Force a manual refresh
sudo docker compose exec freshrss-app \
  php /var/www/FreshRSS/app/actualize_script.php

# Check error logs
sudo docker compose exec freshrss-app \
  cat /var/www/FreshRSS/data/users/admin/log.txt

API authentication failing:

# Verify API access is enabled in Settings > Authentication
# Check the API password (separate from login password)

# Test with verbose output
curl -v -d "api_key=$(echo -n 'user:apipassword' | md5sum | cut -c1-32)" \
  "http://localhost:8080/api/fever.php?api"

Slow page loads with many feeds:

# Check database query performance
# Enable MySQL slow query log
sudo docker compose exec freshrss-db \
  mysql -u root -p -e "SET GLOBAL slow_query_log=1; SET GLOBAL long_query_time=1;"

# Add database indexes (FreshRSS does this automatically on updates)
# But can manually trigger:
sudo docker compose exec freshrss-app \
  php /var/www/FreshRSS/cli/update-user.php --user admin

Conclusion

FreshRSS provides a capable, resource-efficient RSS aggregator that consolidates hundreds of news feeds into a single interface accessible from any device, with API compatibility that works with all major mobile RSS clients. Its multi-user support, extension ecosystem, and configurable article retention make it a practical long-term self-hosting choice for replacing commercial feed readers without the ongoing subscription costs.