Ubuntu VPSにFreshRSSをインストールする方法
Ubuntu 24.04 VPSにFreshRSS 1.29.1を構築します。Apache、PHP 8.3、MariaDBの設定から、リリース展開、cron更新、モバイルアプリAPI用の設定まで、実際の手順を紹介します。
構築するもの
自己ホスト型 RSS リーダーは、自分が所有するサーバー上で動作するフィードリーダーです。そのため、第三者に停止されたり、表示内容を変更されたりすることがありません。このガイドでは、Ubuntu 24.04 VPS に FreshRSS を構築します。前段に Apache、後段に PHP、データ保存に MariaDB を使用し、新しい記事を取得する cron ジョブを 1 つ設定します。RSS (really simple syndication) は、サイトが記事をソフトウェアで読み取れるように公開するファイル形式です。FreshRSS は、それらのファイルを収集して記事を保存し、Web インターフェースと、スマートフォンアプリが通信する API (application programming interface) を提供する PHP アプリケーションです。
インストール自体は小規模です。リリースを展開し、データベースを作成し、バーチャルホストを 1 つ記述して、コマンドラインインストーラーを 1 回実行します。以下で多くの作業を割いているのは、その後に問題が発生しやすい部分です。具体的には、更新ジョブ、モバイル API 用のエンコードされたスラッシュ、ファイルの所有権です。
FreshRSS 1.29.1 は 2026 年 7 月時点の最新リリースで、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 mariadbsystemctl 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 apache2php -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.29.1.tar.gz
tar xzf 1.29.1.tar.gz
sudo mv FreshRSS-1.29.1 /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 はセットアップが不要で、数百件程度のフィードを1人で利用する場合に適しています。複数人でインスタンスを共有する場合は、MariaDB の方が適しています。更新ジョブと Web インターフェースからの同時書き込みが、1つのファイルロックを奪い合わなくなるためです。
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;"utf8 ではなく utf8mb4 を使用してください。フィードには絵文字や非ラテン文字のスクリプトが含まれます。古い3バイトの utf8 エンコーディングでは、4バイト文字が最初に現れた位置で記事タイトルが切り詰められます。
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 apache2configtest の出力には 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 はブラウザーで開いている間だけ更新されるため、1 日に 2 回アクセスするインスタンスでは、12 時間前の記事が表示されます。これを解決するには、プロジェクトがこの用途向けに提供しているスクリプト 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 分以上にするのが適切です。このスクリプトは、同じフィードを 20 分以内に再度更新しないため、それより短いスケジュールでは CPU を消費するだけです。まず手動で 1 回実行します。
sudo -u www-data php /srv/freshrss/app/actualize_script.php正常に実行されると、取得した各フィードの名前が出力され、PHP エラーなしで終了します。何も出力されない場合は cron の実行ユーザーが誤っています。data/ で権限エラーが出る場合は、chmod -R g+w の手順がスキップされています。
最初のフィードを追加する
インターフェース左上のプラスボタンを使用し、サイトのアドレスを貼り付けると、FreshRSS がフィードのリンクを自動的に検出します。フィードを公開していることを明示していないサイトでも、通常は /feed、/rss、/atom.xml のいずれかでフィードを提供しています。カテゴリはフォルダーで、フィードをカテゴリ間で移動するにはドラッグします。
別のリーダーから移行する場合は、そこで OPML ファイルをエクスポートし、購読管理ページからインポートします。OPML(outline processor markup language)はフィードリストの標準形式であり、移行先として適切なリーダーであれば対応しています。大量にインポートした場合、最初の更新はすべてのフィードを 1 回ずつ取得するため時間がかかります。速度を判断する前に、最初の cron 実行が完了するまで待ってください。
スマートフォンで読む
FreshRSS は Google Reader API に対応しており、ほぼすべての RSS アプリで利用できます。2 つの条件を満たす必要があります。認証設定で「API アクセスを許可」が有効になっている必要があります。これは、上記の --api-enabled フラグですでに設定されています。プロフィールでは、API パスワード欄に値を設定する必要があります。スマートフォンは紛失しやすいため、このパスワードはログインパスワードとは意図的に分けられています。
https://rss.example.com/api/ にアクセスし、「サーバー設定全体を確認」を選択します。正常な構成では PASS が返ります。ここで失敗する場合、ほとんどは AllowEncodedSlashes On 行がないことが原因です。アプリでは、サーバーアドレスに https://rss.example.com/api/greader.php、ユーザー名に FreshRSS のユーザー名、パスワードに API パスワードを指定します。
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 としてエクスポートする価値があります。このファイルがあれば、どの RSS ソフトウェアでも読書環境を再構築できます。
アップグレードでは、同じディレクトリに新しいリリースを展開し、所有者設定のコマンドを再実行します。FreshRSS は、次回のページ読み込み時にデータベースのマイグレーションを自動的に適用します。先にバックアップしてください。復元できないデータベースでマイグレーションに失敗すると、復旧できません。リーダーは低リスクで運用できるサービスであり、セルフホストする価値があるものの一覧を検討する際の最初の候補に適しています。
FAQ
フィードは FreshRSS を開いたときにしか更新されません。なぜですか?
スケジューラーを作成するまで、フィードを定期的に更新する仕組みがないためです。FreshRSS はブラウザーセッションが開いている間はフィードを更新しますが、タブを閉じると何もしません。www-data ユーザーとして app/actualize_script.php を呼び出す cron の行を追加し、その後スクリプトを一度手動で実行して出力を確認してください。何も出力されない場合は、cron が誤ったユーザーで実行されており、PHP が data/ に書き込めないことが原因である場合が多いです。
モバイルアプリから接続できませんが、Web サイトは動作します。なぜですか?
Google Reader API はリクエストパスにエンコードされたスラッシュ(%2F)を含めますが、Apache はデフォルトでこれを拒否します。VirtualHost 内に AllowEncodedSlashes On を追加して、Apache を reload してください。https://rss.example.com/api/ を開いて「Check full server configuration」を実行し、PASS と表示されることを確認します。また、API パスワードがプロフィールで設定されていることも確認してください。これはログインパスワードとは別です。
SQLite と MariaDB のどちらを使うべきですか?
単一ユーザーであれば SQLite を使用してください。インストールが不要で、管理するパスワードもないためです。インスタンスを複数人で利用する場合、またはフィード数が数百を超える場合は MariaDB を使用してください。更新ジョブと Web インターフェースが同時に書き込むため、単一ファイルのロックが制限要因になるためです。後からエクスポートおよびインポートコマンドで移行できるため、永久的な選択ではありません。
インストーラーが設定を書き込むときに失敗します。何が問題ですか?
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 リーダーには、どの程度のサーバーが必要ですか?
ごくわずかです。小規模なプランでも数百のフィードを無理なく処理できます。20 分ごとに短時間の HTTP 取得が発生するだけで、古い記事を削除すればデータベースも小さいまま維持できるためです。ディスク使用量は保持期間に応じて増加するため、すべてを永久に保持するのではなく、アーカイブ設定で記事の削除ポリシーを設定してください。