SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-07

Ubuntu 24.04 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 任务获取新文章。RSS(really simple syndication,简易信息聚合)是网站发布的一种文件格式,软件可以读取其中的文章。FreshRSS 是一个 PHP 应用,用于收集这些文件、保存文章,并提供 Web 界面和 API(application programming interface,应用程序编程接口),手机应用通过 API 与其通信。

安装过程本身并不复杂:解压发行版文件、创建数据库、编写一个虚拟主机配置,然后运行一个命令行安装程序。下面大部分内容用于处理后续最容易出错的部分,包括刷新任务、移动 API 所需的编码斜杠,以及文件所有权。

截至 July 2026,FreshRSS 1.29.1 是当前发行版,需要 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 无法启动,通常是因为其他进程已占用端口 80,sudo ss -ltnp | grep :80 可显示该进程。

FreshRSS 所需的 PHP 扩展

FreshRSS 将 libxml、cURL、JSON、PDO_MySQL、PCRE 和 ctype 视为必需扩展。此外还需要 mbstring、iconv、Zlib 和 ZipArchive;在 32 位系统上还需要 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.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 无需设置,适合单个用户使用数百个订阅源。多人共享同一实例时,MariaDB 是更好的选择,因为刷新任务和 Web 界面的并发写入不再争用单个文件锁。

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。订阅源可能包含表情符号和非拉丁文字,而旧的三字节 utf8 编码会在遇到第一个四字节字符时截断文章标题。

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 OKAllowEncodedSlashes On 看似可选,实际上不是:Google Reader API 发送的 feed 标识符包含 %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 会在浏览器打开其页面时刷新。这意味着每天访问两次的实例会显示延迟 12 小时的文章。解决方法是使用项目为此提供的脚本 app/actualize_script.php,并通过 cron 运行。

sudo crontab -u www-data -e

添加一行:

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

20 分钟是合理的最短间隔,因为该脚本拒绝在 20 分钟内重复刷新同一个订阅源。设置更短的计划只会浪费 CPU。先手动运行一次:

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(大纲处理器标记语言)是标准的订阅源列表格式,所有值得迁移的阅读器都支持该格式。首次刷新大型导入列表时速度会较慢,因为系统需要获取每个订阅源一次。因此,请在判断速度前等待第一次 cron 运行完成。

在手机上阅读

FreshRSS 支持 Google Reader API,几乎所有 RSS 应用都支持该 API。以下两项必须同时满足。在身份验证设置中,必须启用“允许 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 镜像。使用一个 compose 文件即可同时部署应用及其数据库。代价与通常相同:主机上的组件更少,但出现故障时需要排查的层次更多;要启用 TLS(传输层安全),仍然需要反向代理。如果这种方式更适合您,可参考 VPS 的 Docker Compose 基础了解文件格式;cron 配置行则变为 docker exec --user www-data freshrss php ./app/actualize_script.php

备份与升级

需要保存的状态有两部分:数据库和 /srv/freshrss/data/。使用 sudo mysqldump freshrss > freshrss.sql 导出数据库,复制 /srv/freshrss/data/,并将两者都保存到此服务器之外的位置。订阅列表也应偶尔导出为 OPML,因为该文件可以在任何 RSS 软件中重建您的阅读配置。

升级时,将新版本解压到同一目录,然后重新运行所有权设置命令。FreshRSS 会在下一次加载页面时自动执行数据库迁移。请先备份,因为如果迁移失败且数据库无法恢复,您将无法挽回数据。阅读器服务的运行风险较低。如果您正在整理值得自行托管的服务清单,它很适合作为第一个候选服务。

FAQ

为什么只有打开 FreshRSS 时,订阅源才会更新?

因为在创建调度任务前,不存在任何调度器。浏览器会话打开时,FreshRSS 会刷新订阅源;标签页关闭后则不会执行任何操作。请添加一行 cron,使用 www-data 用户调用 app/actualize_script.php,然后手动运行一次该脚本并查看输出。没有输出通常表示 cron 使用了错误的用户运行脚本,因此 PHP 无法写入 data/

我的移动应用无法连接,但网站可以正常访问。为什么?

Google Reader API 会在请求路径中包含编码后的斜杠(%2F),而 Apache 默认会拒绝这类请求。在虚拟主机中添加 AllowEncodedSlashes On,然后重新加载 Apache。打开 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/freshrsssudo chmod -R g+w /srv/freshrss/data,然后再次启动安装程序。如果之前以 root 身份运行过命令行安装程序,请在重试前删除它在 data/ 下创建的文件,因为实际问题是这些文件的所有权。

自托管 RSS 阅读器需要多少服务器资源?

很少即可。小型方案运行几百个订阅源也没有问题,因为负载只是每二十分钟进行一次短暂的 HTTP 抓取,并且清理旧文章后数据库会保持较小。磁盘占用量会随保留时间增长,因此应在归档设置中配置文章清理策略,不要永久保留所有文章。