FreshRSSをDockerでデプロイ:自分専用RSSリーダーをセルフホストしてニュースフィードを取り戻す

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

クイックスタート:5分でFreshRSSを起動する

自分専用のRSSリーダーを持つことは、ホームラボの小さな勝利のひとつで、毎日の生活をじわじわ改善してくれる。FreshRSSをセルフホストして2年以上になるが、もしなくなったら最も惜しいサービスだと思う。アルゴリズムなし、広告なし、フィードの制限なし――購読したコンテンツが公開されたらそのまま届くだけだ。

FreshRSSを最速で動かす手順はこちら:

mkdir -p ~/freshrss/{data,extensions}

docker run -d \
  --name freshrss \
  -p 8080:80 \
  -e TZ=Asia/Tokyo \
  -e CRON_MIN='*/15' \
  -v ~/freshrss/data:/var/www/FreshRSS/data \
  -v ~/freshrss/extensions:/var/www/FreshRSS/extensions \
  --restart unless-stopped \
  freshrss/freshrss:latest

http://<サーバーのIPアドレス>:8080 を開くとセットアップウィザードが表示される。データベースを選択し(個人利用ならSQLiteで十分)、管理者アカウントを作成すれば完了だ。

始めるにはこのコマンド1つで十分。ただし、本番環境レベルにしたい――データを永続化し、リバースプロキシを立て、全デバイスで同期させたい――なら読み続けてほしい。

詳細解説:PostgreSQLを使ったDocker Composeの設定

SQLiteは個人利用には問題ないが、フィードが数百件を超えたりマルチユーザー対応が必要になった場合は、PostgreSQLの方が賢い選択だ。実際に使いながら磨き上げたComposeファイルを紹介する:

version: '3.8'

services:
  freshrss:
    image: freshrss/freshrss:latest
    container_name: freshrss
    restart: unless-stopped
    ports:
      - '8080:80'
    environment:
      TZ: Asia/Tokyo
      CRON_MIN: '*/15'
      FRESHRSS_ENV: production
    volumes:
      - ./data:/var/www/FreshRSS/data
      - ./extensions:/var/www/FreshRSS/extensions
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    container_name: freshrss-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: freshrss
      POSTGRES_USER: freshrss
      POSTGRES_PASSWORD: your_strong_password_here
    volumes:
      - ./db:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U freshrss']
      interval: 10s
      timeout: 5s
      retries: 5
docker compose up -d

セットアップウィザードではデータベースの種類にPostgreSQLを選択し、Composeファイルに合わせた認証情報を入力する。FreshRSSは初回起動時に自動でスキーマを作成するため、追加作業は不要だ。

リバースプロキシの背後に置く

ポート8080はテスト用には十分だが、LANの外からFreshRSSにアクセスする場合はHTTPSが必要になる。Nginx Proxy ManagerやTraefikがすでにホームラボで動いているなら、rss.yourdomain.com のようなサブドメインをDockerホストのポート8080に向ければいい。

Nginx Proxy Managerなら数クリックで完了する。プロキシホストを追加し、転送先ホスト名にDockerホストのIPアドレスとポート8080を設定し、Let’s EncryptでSSLを有効化してHTTPSを強制するだけ。2分かからない。

Traefikユーザーは代わりにfreshrssサービスへ以下のラベルを追加しよう:

labels:
  - 'traefik.enable=true'
  - 'traefik.http.routers.freshrss.rule=Host(`rss.yourdomain.com`)'
  - 'traefik.http.routers.freshrss.entrypoints=websecure'
  - 'traefik.http.routers.freshrss.tls.certresolver=letsencrypt'
  - 'traefik.http.services.freshrss.loadbalancer.server.port=80'

フィード更新間隔の設定

CRON_MIN変数はFreshRSSがフィードをポーリングする頻度を制御する。*/15は15分ごとを意味し、鮮度とサーバー負荷のバランスとして妥当な設定だ。リソースが限られたVPSでは*/30に変更しても、実用上はほとんど差を感じない。

管理 → アーカイブから手動で更新をトリガーすることも、CLIから直接実行することもできる:

docker exec -it freshrss php /var/www/FreshRSS/app/actualize_script.php

APIアクセスとモバイル同期

多くのセルフホストRSSツールはウェブアクセスで止まっている。FreshRSSはそこからさらに踏み込み、Google Reader APIを実装している(さらに拡張機能経由でFever APIにも対応)。Google ReaderバックエンドをサポートするほぼすべてのRSSクライアントと互換性があり、これは驚くほど大きなエコシステムだ。

APIを有効化する

ユーザー設定 → プロフィールに移動し、APIパスワードを設定する。ログインパスワードと同じでも構わないが、別のパスワードを設定する方がすっきりする。次に管理 → 認証に移動し、APIアクセスを許可するにチェックを入れる。

APIエンドポイントは以下のようになる:

https://rss.yourdomain.com/api/greader.php

モバイルクライアントの設定

私の日常環境はiOSでNetNewsWire、macOSでReeder 5――どちらもGoogle Reader APIをネイティブサポートしている。FreshRSSのURLにユーザー名とAPIパスワードを設定するだけで、WiFiでもLTEでもほぼリアルタイムで同期される。

AndroidではFeedMeRead You(完全オープンソース)が同じエンドポイントで問題なく動作する。

既存のフィードをインポートする

Feedly、Inoreader、その他サービスからの移行は?購読リストをOPMLとしてエクスポートし、購読管理 → インポート/エクスポートからインポートすればいい。FeeldyからOPMLを読み込んで340件のフィードを8秒ほどでインポートできた――FreshRSSは微塵も動じなかった。

バックアップを自動化する

フィード、既読状態、設定、ユーザーデータはすべて./dataに保存される。シンプルな夜間スクリプトで十分だ:

#!/bin/bash
BACKUP_DIR="/mnt/nas/backups/freshrss"
DATE=$(date +%Y%m%d)
tar -czf "${BACKUP_DIR}/freshrss-${DATE}.tar.gz" ~/freshrss/data ~/freshrss/db
find "${BACKUP_DIR}" -name '*.tar.gz' -mtime +30 -delete

cron(crontab -e)に追加して午前3時に実行するよう設定する:

0 3 * * * /home/user/scripts/backup-freshrss.sh

毎日使って分かった実践的なコツ

2年間実際に運用して学んだこと――これを知らないと私と同じ壁にぶつかるはずだ。

1. フィード数に気を配る

FreshRSSは低スペックのハードウェアでも数百件のフィードを処理できる。1コア・1GB RAMのVPSで文句なく動く。本当のボトルネックは更新頻度の高いソースで、ニュースサイトによっては1日50件以上の記事を配信するものもある。購読管理でフィードごとの保存件数に上限を設けよう。私はほとんどのフィードを200件に設定し、一部の重要なものだけ無制限にしている。これでデータベースをスリムに保てる。

2. ラベル機能は過小評価されている

多くの人がFreshRSSのラベル機能を無視している。それはもったいない。後で読むDevOpsニュースレターといったラベルを作り、フィードのソースやタイトルのキーワードに基づいて自動割り当てするフィルタリングルールを設定しよう。FreshRSSが単なるパッシブなリーダーから、軽量なコンテンツキュレーションレイヤーに変わる――サードパーティのツール不要で。

3. 共有連携機能を活用する

ユーザー設定 → 共有から、Pocket、Wallabag、任意のカスタムURLへのワンクリック保存を設定できる。私はセルフホストのWallabagインスタンスに向けている。長文記事はクリック1つで保存でき、タブを行き来する必要がない。

4. フィード取得の問題をデバッグする

フィードが更新されなくなったら、購読管理でそのフィードの状態を確認しよう――エラーのあるフィードはそこにフラグが立つ。9割以上はRSS URLの変更、サイトのダウン、または認証が必要になったフィードが原因だ。コンテナ内から直接URLをテストしてみよう:

docker exec -it freshrss curl -I 'https://example.com/feed.xml'

5. メモリ使用量のチューニング

メモリが少ないVPSでは、リソース制限を追加して過剰使用を防ごう:

services:
  freshrss:
    # ... その他の設定
    deploy:
      resources:
        limits:
          memory: 256M

SQLiteを使ったFreshRSSは通常時100MB未満で動作する。PostgreSQLを加えると多少オーバーヘッドが増えるが、個人利用なら256MBを大幅に下回るはずだ。

6. 入れる価値のある拡張機能

./extensionsボリュームが存在する理由がある。実際に毎日使っている3つを紹介する:

  • xExtension-CustomCSS — コアファイルに触れずにUIを調整できる
  • cn-metrics — 中国語の技術系フィードをフォローしている場合に便利
  • Fever API拡張機能 — ReederのFeverプロトコル互換を有効化する

拡張機能を~/freshrss/extensions/に配置し、管理 → 拡張機能から有効化しよう。

7. イメージを最新の状態に保つ

FreshRSSは定期的にアップデートをリリースしている。Docker Composeでのアップグレード手順はコマンド2つだけ:

docker compose pull
docker compose up -d

データベースのマイグレーションは起動時に自動で実行される。それでも、メジャーバージョンをまたぐ場合は事前にバックアップを取っておこう。30秒で完了するし、何か問題が起きたときに必ず役に立つ。

FreshRSSを毎日2年以上運用してきて、今やほとんど意識しないインフラになった――これはセルフホストサービスに贈れる最高の賛辞だと思う。軽量で、APIサポートが充実していて、試したモバイルクライアントすべてと互換性がある。ホームラボを構築しているなら、自分でコントロールできるRSSリーダーは持つ価値がある。FreshRSSは迷わず勧められる一択だ。

Share: