Ubuntu 24.04 VPS 部署 FreshRSS 自托管教程
在 Ubuntu 24.04 上部署 FreshRSS 详细指南。涵盖 LAMP 堆栈配置、PHP 扩展安装、虚拟主机设置及 Cron 自动刷新任务。解决移动端 API 访问及文件权限常见问题,确保在 PHP 8.3 环境下稳定运行自托管 RSS 阅读器。
构建内容
自托管 RSS 阅读器是在您拥有的服务器上运行的订阅源阅读器,因此没有其他人可以将其关闭,也不能更改它向您显示的内容。本指南将在 Ubuntu 24.04 VPS 上部署 FreshRSS:前端使用 Apache,后端使用 PHP,使用 MariaDB 存储数据,并通过一个 cron 任务获取新文章。RSS(really simple syndication,简易信息聚合)是网站发布的一种文件格式,软件可以读取其中的文章。FreshRSS 是一个 PHP 应用,用于收集这些文件、保存文章,并提供 Web 界面和 API(application programming interface,应用程序编程接口),手机应用通过 API 与其通信。
安装过程很简单:解压发行版本、创建数据库、编写一个虚拟主机配置、运行命令行安装程序,然后使用 cli/create-user.php 创建账户。下面的大部分内容用于处理安装后最容易出错的部分,包括刷新任务、移动端 API 所需的编码斜杠,以及文件所有权。
截至 October 29, 2026,FreshRSS 1.30.4 是当前版本,于 October 21, 2026 发布,需要 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 无法启动,通常是因为其他进程已占用端口 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.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 文件中。添加用户不会将所有写入操作放入同一个共享 SQLite 文件。本指南使用 MariaDB 作为 LAMP 堆栈的一部分。
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 编码无法存储四字节字符。在 MariaDB 默认的严格模式下,不支持的字符会导致错误;是否截断取决于 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 apache2configtest 应输出 Syntax OK。AllowEncodedSlashes 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 不会安排订阅源抓取;如果没有调度器,请使用导航菜单中的更新链接手动抓取文章。解决方法是使用项目为此提供的脚本 app/actualize_script.php,并通过 cron 运行。
sudo crontab -u www-data -e添加一行:
*/20 * * * * php /srv/freshrss/app/actualize_script.php > /tmp/FreshRSS.log 2>&1每二十分钟运行一次是合理的调度方式,但每个订阅源自身的刷新间隔仍然有效:默认间隔为一小时,单个订阅源支持最低十五分钟的间隔。先手动运行一次:
sudo -u www-data php /srv/freshrss/app/actualize_script.php正常输出会报告本次刷新运行,并在结束时不出现 PHP 错误;添加或更新文章时会显示订阅源名称。如果完全没有输出,请检查 PHP 的错误输出和 FreshRSS 日志;仅凭没有输出不能确定原因是 cron 用户。data/ 出现权限错误时,应检查其所有者和写权限。
添加第一个订阅源
点击界面左上角的加号按钮,粘贴网站地址,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,因为支持 OPML 的其他阅读器可以通过该文件导入你的订阅源列表。但该文件不会保留 FreshRSS 特有的设置,例如刷新频率、凭据、用户代理或 XPath 网页抓取规则;如需同时保留这些设置,请使用 SQLite 导出。
升级时,将较新的版本解压到同一目录,然后重新运行所有权设置命令。按照项目规定的逐版本升级路径操作,并在每一步之后验证 FreshRSS。FreshRSS 会在下一次加载页面时自动执行数据库迁移。务必先备份,因为如果数据库迁移失败且数据库无法恢复,就无法挽回。若你是从较旧的 tarball(例如 1.29.1)安装的,请升级到 1.30.4:1.30.x 安全版本在身份验证设置发生变化时加入了会话 ID 轮换,并限制了 ZIP 导入范围;1.30.4 还更新了备用 Alpine Docker 镜像,以修复严重的 PHP 漏洞。阅读器服务的运行风险较低。如果你正在整理值得自行托管的服务清单,它适合作为首个候选项。
FAQ
为什么只有打开 FreshRSS 时,订阅源才会更新?
打开页面不会安排订阅源抓取;没有调度程序时,请使用更新链接手动刷新。添加一条以 www-data 用户身份调用 app/actualize_script.php 的 cron 配置,然后手动运行一次该脚本并查看输出。如果没有输出,请检查 PHP 的错误输出和 FreshRSS 日志,然后确认 cron 用户对 data/ 具有写入权限。
移动应用无法连接,但网站可以正常访问。为什么?
Google Reader API 会在请求路径中包含编码后的斜杠(%2F),而 Apache 默认会拒绝这类请求。在虚拟主机配置中添加 AllowEncodedSlashes On,然后重新加载 Apache。打开 https://rss.example.com/api/ 以确认修复结果,自动配置检查应报告 PASS。还要确认已在个人资料中设置 API 密码,因为它与登录密码分开。
应该使用 SQLite 还是 MariaDB?
SQLite 需要 php-sqlite3 扩展,但不需要管理数据库服务器或数据库密码。每个用户都有单独的 SQLite 数据库文件,因此添加第二个用户不会在一个共享文件上产生竞争,也不需要 MariaDB。如果希望在 LAMP 技术栈中使用数据库服务器,请选择 MariaDB。之后仍可通过导出和导入命令在两者之间迁移,因此这不是永久性决定。
安装程序写入配置时失败。哪里出了问题?
在 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 设计为可在配置不高的硬件上运行,但资源使用量取决于订阅源数量、文章大小和保留设置。磁盘占用会随保留内容增加,因此应在归档设置中配置文章清理策略,而不是永久保留所有内容。