SSD Nodes Learn 8GB 内存 — 每年 $66
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-01

在 Ubuntu VPS 上自托管安装 FreshRSS

本指南在 Ubuntu 24.04 VPS 上安装 FreshRSS 1.29.1,涵盖 Apache、PHP 8.3、MariaDB、发行版压缩包、虚拟主机、cron 刷新任务和移动 API 配置。

您要构建的内容

自托管 RSS 阅读器是在您拥有的服务器上运行的 feed 阅读器。因此,没有人可以将其关闭,也无法更改它向您显示的内容。本指南将在 Ubuntu 24.04 VPS 上部署 FreshRSS:由 Apache 处理前端请求,PHP 负责后端,MariaDB 用于存储,并通过一个 cron 任务获取新文章。RSS(really simple syndication,简易信息聚合)是网站发布的一种文件格式,软件可以读取其中的文章。FreshRSS 是一个 PHP 应用程序,用于收集这些文件、保存文章,并提供 Web 界面和 API(application programming interface,应用程序编程接口),手机应用通过 API 与其通信。

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

截至 2026 年 7 月,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 指向该目录。将应用程序目录与文档根目录分开后,只有 public 目录可以通过 HTTP 访问。

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 通知输出到页面中。

加载 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 会在浏览器会话打开时刷新订阅源,标签页关闭后则不会执行任何操作。添加以 www-data 用户身份调用 app/actualize_script.php 的 cron 行,然后手动运行一次脚本并查看其输出。通常没有输出表示 cron 使用了错误的用户运行脚本,因此 PHP 无法写入 data/

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

Google Reader API 会在请求路径中使用编码斜杠(%2F),而 Apache 默认会拒绝这些斜杠。在虚拟主机中添加 AllowEncodedSlashes On,然后重新加载 Apache。打开 https://rss.example.com/api/ 并运行“检查完整服务器配置”来确认修复结果;结果应报告 PASS。另外,请确认已在个人资料中设置 API 密码,因为它与登录密码分开。

应该使用 SQLite 还是 MariaDB?

单用户使用 SQLite,因为无需安装其他组件,也无需管理密码。当实例上有多个用户阅读,或订阅源超过几百个时,使用 MariaDB。原因是刷新任务和 Web 界面会同时写入数据,单个文件锁会成为限制。之后可以通过导出和导入命令在两者之间迁移,因此这不是永久性决定。

安装程序写入配置时失败。原因是什么?

PHP 在 Apache 下以 www-data 身份运行,而该用户无法写入 root 所有的目录。重新运行 sudo chown -R www-data:www-data /srv/freshrsssudo chmod -R g+w /srv/freshrss/data,然后再次启动安装程序。如果之前以 root 身份运行过命令行安装程序,请删除其在 data/ 下创建的文件后再重试,因为实际问题是这些文件的所有权。

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

很少即可。小型套餐运行几百个订阅源也足够,因为负载是每 20 分钟进行一次持续时间较短的 HTTP 获取操作,并且清理旧文章后数据库会保持较小。磁盘占用量会随着保留时间增长,因此应在归档设置中配置文章清理策略,而不是永久保留所有文章。

#freshrss#rss#自托管#php#apache