SSD Nodes Learn Hosting plans →
ガイド Matt Connor著者 Matt Connor

Ubuntu VPSにFreshRSSをインストールする方法

Ubuntu 24.04 VPSにFreshRSS 1.30.1を構築します。Apache、PHP 8.3、MariaDBの設定からrelease展開、cron更新、モバイルAPI用のencoded slashまで解説します。

構築するもの

セルフホスト型 RSS リーダーは、自分が所有するサーバー上で動作するフィードリーダーです。そのため、第三者に停止されたり、表示内容を変更されたりすることがありません。このガイドでは、Ubuntu 24.04 VPS に FreshRSS を構築します。前段に Apache、後段に PHP、データ保存に MariaDB を使用し、新しい記事を取得する cron ジョブを 1 つ設定します。RSS(Really Simple Syndication)は、ソフトウェアが記事を読み取れるようにサイトが公開するファイル形式です。FreshRSS は、それらのファイルを収集して記事を保存し、Web インターフェースと、スマートフォンアプリが利用する API(Application Programming Interface)を提供する PHP アプリケーションです。

インストール自体は小規模です。リリースを展開し、データベースを作成し、1 つの virtual host を記述し、コマンドラインインストーラーを実行して、cli/create-user.php でアカウントを作成します。以下で主に扱うのは、その後に問題になりやすい部分です。具体的には、更新ジョブ、モバイル API で必要なエンコード済みスラッシュ、ファイル所有権です。

2026 年 10 月 21 日に公開された FreshRSS 1.30.4 は、2026 年 10 月 29 日時点の現行リリースです。PHP 8.1 以降が必要です。Ubuntu 24.04 には PHP 8.3 が含まれているため、ディストリビューションのパッケージで十分です。サードパーティの PHP リポジトリは必要ありません。

動作する LAMP スタックから始める

FreshRSS は一般的な PHP アプリケーションです。そのため、他の PHP アプリケーションと同じ基盤が必要です。まだ基盤を構築していない場合は、先に Ubuntu 24.04 での LAMP スタック構築 に従ってから、ここに戻ってください。要点は次のとおりです。

sudo apt update
sudo apt install -y apache2 mariadb-server php libapache2-mod-php
sudo systemctl enable --now apache2 mariadb

systemctl status apache2 の結果が active (running) になることを確認します。Apache が起動しない場合は、別のプロセスがすでに port 80 を使用していることが一般的な原因です。sudo ss -ltnp | grep :80 でそのプロセスを特定できます。

FreshRSS に必要な PHP 拡張機能

FreshRSS では、libxml、cURL、JSON、PDO_MySQL、PCRE、ctype が必須です。mbstring、iconv、Zlib、ZipArchive も必要で、32 bit システムでは GMP も必要です。Ubuntu では、これらをディストリビューションのパッケージとしてインストールできます。

sudo apt install -y php-curl php-mbstring php-xml php-zip php-mysql php-intl php-gmp
sudo systemctl restart apache2

php -mで、PHP が実際に読み込んでいる拡張機能を確認します。拡張機能が不足していても、インストーラーは起動します。要件画面で拡張機能名を赤字で示して停止するため、問題の発見場所としては分かりにくくなります。そこで、ここで確認しておきます。Apache の再起動も必要です。libapache2-mod-phpは PHP を Apache プロセス内で実行するため、新しくインストールした拡張機能は、Apache を再起動するまで Web サーバーから認識されません。

リリースをダウンロードする

FreshRSS はデフォルトの Web ルートの外にインストールし、Apache から参照できるようにします。アプリケーションのディレクトリをドキュメントルートから分離すると、HTTP 経由で到達できるのは public フォルダーだけになります。

cd /tmp
curl -fsSLO https://github.com/FreshRSS/FreshRSS/archive/refs/tags/1.30.4.tar.gz
tar xzf 1.30.4.tar.gz
sudo mv FreshRSS-1.30.4 /srv/freshrss

次に権限を設定します。FreshRSS のドキュメントでは、この設定が厳密に指定されています。Web サーバーのユーザーがツリー全体を所有し、グループにはすべてのファイルの読み取り権限を付与します。また、グループには ./data/ への書き込み権限を付与します。

sudo chown -R www-data:www-data /srv/freshrss
sudo chmod -R g+r /srv/freshrss
sudo chmod -R g+w /srv/freshrss/data

この設定を省略すると、インストーラーが設定を書き込む際に失敗します。PHP は www-data として実行され、www-data は root が所有するディレクトリに書き込めないためです。

データベースを作成する

FreshRSS は SQLite、MariaDB、MySQL、PostgreSQL をサポートしています。SQLite では php-sqlite3 拡張機能が必要ですが、データベースサーバーの設定は不要です。また、各ユーザーのデータは個別の data/users/_user_/db.sqlite ファイルに保存されます。ユーザーを追加しても、書き込みが1つの共有 SQLite ファイルに集約されるわけではありません。このガイドでは、LAMP スタックの一部として MariaDB を使用します。

sudo mariadb -e "CREATE DATABASE freshrss CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
sudo mariadb -e "CREATE USER 'freshrss'@'localhost' IDENTIFIED BY 'ReplaceThisPassword';"
sudo mariadb -e "GRANT ALL PRIVILEGES ON freshrss.* TO 'freshrss'@'localhost';"
sudo mariadb -e "FLUSH PRIVILEGES;"

utf8mb4 を使用し、utf8 は使用しないでください。フィードには絵文字や非ラテン文字のスクリプトが含まれます。従来の3バイトの utf8 エンコーディングでは、4バイト文字を保存できません。サポートされていない文字があると、MariaDB のデフォルトの strict モードではエラーになります。切り捨ての動作は、SQL モードと IGNORE などのステートメントオプションによって異なります。

Apache のバーチャルホスト

公開ディレクトリはツリーの最上位ではなく、p/ です。データベースパスワードを含む設定ファイルなど、それ以外のファイルはすべてドキュメントルートより上位に配置されるため、Apache が公開することはありません。

<VirtualHost *:80>
	ServerName rss.example.com
	DocumentRoot /srv/freshrss/p/

	<Directory /srv/freshrss/p>
		AllowOverride AuthConfig FileInfo Indexes Limit
		Require all granted
	</Directory>

	ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log
	CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined

	AllowEncodedSlashes On
</VirtualHost>

/etc/apache2/sites-available/freshrss.conf として保存し、有効化します。

sudo a2enmod rewrite
sudo a2ensite freshrss
sudo a2dissite 000-default
sudo apache2ctl configtest
sudo systemctl reload apache2

configtest の出力には Syntax OK と表示されるはずです。AllowEncodedSlashes On は任意に見えますが、必須です。Google Reader API は %2F を含むフィード識別子を送信します。このディレクティブがないと Apache が識別子を拒否するため、Web インターフェースは正常に動作しても、モバイルアプリは同期に失敗します。

ログインする前に HTTPS を追加する

このサイトにパスワードを入力する前に、まず証明書を取得します。サーバーを指す A レコードを設定し、Ubuntu の Apache 向け Certbot 設定に従って sudo certbot --apache -d rss.example.com を実行します。Certbot は 443 番ポート用に仮想ホストを書き換え、リダイレクトも追加します。curl -I https://rss.example.com/ で確認します。200 が返るか、ログインページへのリダイレクトが返れば正常です。

コマンドラインからインストーラーを実行する

FreshRSS にはブラウザー用インストーラーもありますが、コマンドライン版は繰り返し実行でき、選択した内容を正確に記録として残せます。

sudo -u www-data php /srv/freshrss/cli/do-install.php \
  --default-user admin --auth-type form --environment production \
  --base-url https://rss.example.com --language en --api-enabled \
  --db-type mysql --db-host localhost --db-user freshrss \
  --db-password 'ReplaceThisPassword' --db-base freshrss
sudo -u www-data php /srv/freshrss/cli/create-user.php \
  --user admin --password 'a-long-passphrase' --api-password 'a-different-passphrase'

どちらも www-data として実行します。root として実行すると、root が所有する設定ファイルが作成され、その後 Web インターフェースから設定を保存できなくなります。--environment production も重要です。開発用設定では、PHP の notice がページ内に表示されるためです。

https://rss.example.com/ を読み込み、admin としてログインします。

フィードが自動更新されない理由

明示的に設定しない限り、フィードを取得する処理は実行されません。FreshRSS を開いてもフィード取得はスケジュールされません。スケジューラーがない場合は、ナビゲーションメニューの更新リンクを使って記事を手動で取得します。解決策は、プロジェクトがこの用途向けに提供している app/actualize_script.php スクリプトを cron から実行することです。

sudo crontab -u www-data -e

次の 1 行を追加します。

*/20 * * * * php /srv/freshrss/app/actualize_script.php > /tmp/FreshRSS.log 2>&1

20 分間隔は妥当な設定です。ただし、各フィードの更新間隔も適用されます。デフォルトは 1 時間で、個別のフィードでは 15 分間隔まで設定できます。まず手動で 1 回実行します。

sudo -u www-data php /srv/freshrss/app/actualize_script.php

正常な出力では、更新処理の実行が報告され、PHP エラーなしで終了します。記事が追加または更新されると、フィード名が表示されます。何も出力されない場合は、PHP のエラー出力と FreshRSS のログを確認します。無出力だけでは、原因が cron ユーザーにあるとは判断できません。data/ で権限エラーが発生する場合は、所有者と書き込み権限を確認します。

最初のフィードを追加する

インターフェース左上のプラスボタンを使用し、サイトのアドレスを貼り付けると、FreshRSS がフィードのリンクを自動的に検出します。フィードを公開していることを明示していないサイトでも、通常は /feed、/rss、/atom.xml のいずれかでフィードを提供しています。カテゴリはフォルダーで、フィードをカテゴリ間で移動するにはドラッグします。

別のリーダーから移行する場合は、そこで OPML ファイルをエクスポートし、購読管理ページからインポートします。OPML(outline processor markup language)はフィードリストの標準形式であり、移行先として適切なリーダーであれば対応しています。大量にインポートした場合、最初の更新はすべてのフィードを 1 回ずつ取得するため時間がかかります。速度を判断する前に、最初の cron 実行が完了するまで待ってください。

スマートフォンで読む

FreshRSS は、多くの RSS アプリが対応している Google Reader API を利用できます。2 つの条件を満たす必要があります。認証設定で「API access を許可」が有効になっている必要があります。これは、上記の --api-enabled フラグです。プロフィールでは、API password フィールドに値を設定する必要があります。スマートフォンは紛失しやすいため、これはログインパスワードとは意図的に分けられています。

https://rss.example.com/api/ にアクセスすると、サーバー設定を自動的に確認できます。正常な構成では PASS が返ります。チェックに失敗した場合は、仮想ホストの AllowEncodedSlashes On 設定と表示されたエラーを確認してください。アプリでは、サーバーアドレスに https://rss.example.com/api/greader.php、ユーザー名に FreshRSS のユーザー名、パスワードに API password を指定します。

Docker の代替手段

PHP と Apache を手作業で管理したくない場合、プロジェクトは公式の freshrss/freshrss イメージを公開しています。1 つの compose ファイルで、アプリケーションとデータベースをまとめて構成できます。一般的なトレードオフもあります。ホスト上の構成要素は減りますが、障害発生時に切り分ける層が 1 つ増えます。また、TLS(トランスポート層セキュリティ)には引き続きリバースプロキシが必要です。この方法が適している場合は、VPS 向け Docker Compose の基本でファイル形式を確認できます。cron の行は docker exec --user www-data freshrss php ./app/actualize_script.php になります。

バックアップとアップグレード

状態を保持するものは、データベースと /srv/freshrss/data/ の2つです。前者は sudo mysqldump freshrss > freshrss.sql でダンプし、後者はコピーして、どちらもこのサーバー以外の場所に保管します。購読リストは、定期的に OPML エクスポートを作成する価値もあります。このファイルを使うと、フィードリストを OPML に対応する他のリーダーへ移行できます。ただし、更新頻度、認証情報、ユーザーエージェント、XPath の Web スクレイピングルールなど、FreshRSS 固有の設定は保持されません。これらも保持するには、SQLite エクスポートを使用します。

アップグレードでは、同じディレクトリに新しいリリースを展開し、所有者を設定するコマンドを再実行します。プロジェクトが定めるバージョンごとのアップグレード手順に従い、各ステップの後に FreshRSS が正常に動作することを確認します。FreshRSS は、次回のページ読み込み時に独自のデータベースマイグレーションを適用します。先にバックアップを作成してください。復元できないデータベースでマイグレーションに失敗すると、復旧できません。1.29.1 などの古い tarball からインストールした場合は、1.30.4 に移行します。1.30.x のセキュリティリリースには、認証情報の変更時にセッション ID をローテーションする機能と、ZIP インポートに対する制限が含まれます。さらに 1.30.4 では、深刻な PHP の脆弱性に対応するため、代替の Alpine Docker イメージも更新されています。リーダーは低リスクで運用できるサービスであり、セルフホストする価値があるものの一覧に取り組む場合の最初の候補として適しています。

FAQ

FreshRSS を開いたときにしかフィードが更新されないのはなぜですか?

ページを開いても、フィード取得はスケジュールされません。スケジューラーがない場合は、更新リンクを使って手動で更新してください。www-data ユーザーとして app/actualize_script.php を呼び出す cron の行を追加し、その後にスクリプトを手動で 1 回実行して出力を確認します。何も出力されない場合は、PHP のエラー出力と FreshRSS のログを確認し、cron ユーザーに data/ への書き込み権限があることを確認してください。

モバイルアプリは接続できませんが、Web サイトは使えます。なぜですか?

Google Reader API は、リクエストパス内にエンコードされたスラッシュ(%2F)を使用します。Apache はデフォルトではこれを拒否します。仮想ホストの設定に AllowEncodedSlashes On を追加し、Apache を reload してください。https://rss.example.com/api/ を開いて修正を確認します。自動設定チェックで PASS と報告されるはずです。また、API パスワードがプロフィールに設定されていることも確認してください。API パスワードはログインパスワードとは別です。

SQLite と MariaDB のどちらを使用すべきですか?

SQLite には php-sqlite3 拡張機能が必要ですが、管理するデータベースサーバーやデータベースパスワードは必要ありません。ユーザーごとに個別の SQLite データベースファイルが作成されるため、2 人目のユーザーを追加しても、1 つの共有ファイルで競合したり、MariaDB が必要になったりしません。LAMP スタックのデータベースサーバーを使用したい場合は、MariaDB を選択してください。後から export コマンドと import コマンドで移行できるため、永続的な選択ではありません。

インストーラーが設定を書き込むときに失敗します。何が問題ですか?

Apache では PHP が www-data として実行されます。このユーザーは、root が所有するディレクトリに書き込めません。sudo chown -R www-data:www-data /srv/freshrss と sudo chmod -R g+w /srv/freshrss/data を再実行し、その後にインストーラーをもう一度起動してください。すでに root としてコマンドラインインストーラーを実行した場合は、再試行する前に data/ 配下で作成されたファイルの所有者を修正してください。

自己ホスト型 RSS リーダーには、どの程度のサーバーが必要ですか?

必要なリソースはごくわずかです。FreshRSS は比較的低性能なハードウェアでも動作するように設計されています。ただし、リソース使用量はフィード数、記事のサイズ、保持設定によって変わります。保持期間が長いほどディスク使用量は増えるため、すべての記事を永久に保持するのではなく、アーカイブ設定で記事の削除ポリシーを設定してください。

この記事は役に立ちましたか?