前言 —— 在 2019 年,我为什么还需要 RSS?

在社交媒体、推荐算法大行其道的今天,RSS 作为一种稍显「落后」的阅读方式已然式微。然而,相比 Twitter 等平台几乎实时的信息传递与「刷不完」的信息流,RSS 真的就一无是处了吗?我认为不是。RSS 作为一种阅读方式,拥有以下难以取代的优点:

另外,与 Twitter 等社交媒体相比,RSS 还有一个最大的好处 —— 提供了从 信息筛选文章阅读完整 体验。你在 Twitter 上能看到的,往往只是一篇文章的标题和链接,如果你想要继续阅读,就必须跳转到原网页,这样的体验是 割裂 的。而 RSS 则不同,你不必再跳转到浏览器中,甚至可以自定义文章的呈现效果(字体、字号、明暗模式等)。这种完整的阅读体验也是我选择 RSS 的重要原因。

为什么是 Tiny Tiny RSS?

在真正考虑搭建自己的 RSS 服务之前,我也尝试过一些主流的 RSS 服务,比如 FeedlyInoreader。诚然,这些服务都算得上「好用」,但总有这样或那样功能上的限制。如果要解除限制,就必须订阅收费服务。从少数派上 这篇文章 整理的内容来看,Feedly (\$65/年)、Inoreader (\$15/30/50/年) 的年费都算得上是一笔不小的开销。

仅仅为了实现 RSS 这一并不算复杂的需求,而花费大量金钱,未免让人觉得有些不值。相比之下,VPS 的价格与上述服务相差无几,还能实现许多 RSS 之外的功能(搭梯子、建站等等),所以购买 VPS 再搭建自己的 RSS 服务无疑是一个不错的选择。加上我本来也一直在续费 VPS,正好借此机会让手上的服务器发挥梯子之外的价值。

确定了自己搭 RSS 服务之后,剩下的就是选择一个开源的解决方案。这里我选择了 Tiny Tiny RSS,主要是受少数派上 这篇文章 的影响,后文也有不少设置会参考这篇文章的内容。

开始前的准备

废话了这么多,终于到了开始搭建的环节。在此之前你需要准备:

安装 Nginx Proxy & Nginx SSL Support

这一部分请参考 HyperApp 官方文档(网站被墙,可能需要梯子)。确保 Nginx Proxy 和 Nginx SSL Support 已经正确安装并运行后继续下一步。如果你之前 编辑 了 ufw 的 after.rules 以解决 ufw 对 Docker 容器无效的问题,记得允许外部网络访问 Nginx Proxy 发布的端口:

ufw route allow from any to any port 80

ufw route allow from any to any port 443

创建 TTRSS 容器网络

为了让 Tiny Tiny RSS 容器能够访问到 PostgreSQL 数据库,我们不妨创建一个专有的 ttrss-network 容器网络[1]。ssh 到服务器上,随后执行:

docker network create ttrss-network

安装 PostgreSQL

在安装 Tiny Tiny RSS 之前,我们需要先安装数据库来存储 RSS 服务运行的记录。这里我们采用 Tiny Tiny RSS 推荐的 PostgreSQL 作为数据库。

转到 HyperApp 的商店中,选择 Docker Image 并选择你的服务器,进入配置页面,然后按以下配置填写[2]

项目内容
Imagepostgres:alpine
Options--restart unless-stopped -v /srv/docker/postgres/data:/var/lib/postgresql/data -e POSTGRES_PASSWORD=<数据库密码> --network=ttrss-network --network-alias=postgres
Command(留空)
Args(留空)

# 请自行设置数据库密码

点击保存,然后在应用页面找到刚刚添加的 PostgreSQL,将其安装在你的服务器上。

安装 Tiny Tiny RSS

转到 HyperApp 的商店中,选择 Docker Image 并选择你的服务器,进入配置页面,然后按以下配置填写:

项目内容
Imagewangqiru/ttrss
Options--restart unless-stopped --expose 80 -v /srv/docker/ttrss/feed-icons:/var/www/feed-icons -e SELF_URL_PATH=https://<你的域名> -e DB_HOST=postgres -e DB_PORT=5432 -e DB_USER=postgres -e DB_PASS=<数据库密码> --network=ttrss-network
Command(留空)
Args(留空)

注意其中的 SELF_URL_PATH 后要改为 https://你的域名,数据库密码即为上面设置的密码。

点击下方的 Show Nginx and SSL options,然后按以下配置填写:

项目内容
Domain与你上面SELF_URL_PATH中的域名一致,如rss.example.com
Port80
HTTPSRedirect http to https
SSL-Domain(自动填写,应该与上面的Domain一致)
Email用来管理域名证书的邮箱

点击保存,然后在应用页面找到刚刚添加的 Tiny Tiny RSS 服务,将其安装在你的服务器上。

需要注意的是,Options 中的 -v /srv/docker/ttrss/feed-icons:/var/www/feed-icons 用于持久化订阅源网站 icon,参考 Tiny Tiny RSS:部署中的普遍问题与注意事项总结。安装后务必执行 sudo chmod -R 777 /srv/docker/ttrss/feed-icons 赋予正确的文件权限。

为了让处于 Docker 默认 bridge 网络的 Nginx Proxy 能与 Tiny Tiny RSS 通信,我们还需要将 TTRSS 容器连接到 bridge 网络上。ssh 到你的服务器,随后执行:

docker container ls | grep wangqiru/ttrss | awk '{print $1}' | xargs docker network connect bridge

然后重启 TTRSS 容器:

docker container ls | grep wangqiru/ttrss | awk '{print $1}' | xargs docker restart

开始使用 Tiny Tiny RSS

稍等片刻,你的 TTRSS 服务应该就跑起来了。此时,访问你在上一步中设置的域名,看到以下画面则表示配置成功:

使用默认账号 admin 和默认密码 password 即可登录。登录后请第一时间修改密码,有条件的话还可以使用 TOTP 验证码进一步增加登录安全性。

有关登录后的初次配置、导入并管理订阅与过滤器等内容,你可以参考少数派上 这篇文章 的第 2 部分。我在这里只提几个比较重要的地方:

另外,为了进一步自定义外观,我在参考 @SpencerWoo 大佬的 Tiny Tiny RSS Black (Pink) Theme 的基础上,写了一份优化 Feedly 主题效果的 CSS。你可以在 这里 (Gist) 查看,将 CSS 内容复制到 Preferences > General > Theme > Customize 中即可应用。

使用 Mercury 实现文章全文输出

某些 RSS 订阅源只会给出文章前两三段的内容,查看全文还得跳转到网站才行,这显然会破坏 RSS 完整的阅读体验。许多付费的 RSS 服务也将全文输出作为一大卖点。而对于我们自建的 Tiny Tiny RSS,我们可以使用 Mercury 实现文章全文输出。

我们还是先使用 HyperApp 创建 Mercury Parser API 的 docker 容器。转到 HyperApp 的商店中,选择 Docker Image 并选择你的服务器,进入配置页面,然后按以下配置填写:

项目内容
Imagewangqiru/mercury-parser-api
Options--restart unless-stopped --expose 3000 --network=ttrss-network --network-alias=mercury-parser-api
Command(留空)
Args(留空)

点击保存,然后在应用页面找到刚刚添加的 Mercury 插件,将其安装在你的服务器上。

随后,我们登录 TTRSS 的网页,在 Preferences > Plugins 中勾选 mercury_fulltext 一项,并点击下方的 Enable selected plugins 启用插件。

之后转到 Feeds > Mercury Fulltext settings,填入 mercury-parser-api:3000 并保存。

如果你需要为某个订阅源启用 Mercury 全文输出,只需要在 Feed单击该订阅源 > Plugins,勾上 Get fulltext via Mercury Parser 后保存即可。

这样就实现了在任何客户端上,都能直接浏览 RSS 的文章全文。

使用 Fever 让更多客户端支持 Tiny Tiny RSS

借助 Fever 模拟插件,我们可以让 iOS 上的 Reeder 等客户端支持 Tiny Tiny RSS。

首先确认你已经 打开 了 Tiny Tiny RSS 的 API 访问。随后在 Preferences > Plugins 中勾选 fever 一项,并点击下方的 Enable selected plugins 启用插件。

刷新页面,在 Preferences 下就会出现一个名叫 Fever Emulation 的板块。点击进入,并在这里为 Fever 插件设置一个登录密码。

# 此处的登录密码 不是 Tiny Tiny RSS 网页的登录密码。当然你可以把二者设置得一样。

Reeder 客户端设置

Reeder 是 iOS / macOS 平台上一款设计出色的 RSS 阅读器,兼容 Fever API。尽管它在 iOS 平台还有另一个竞争对手:Unread,但 Unread 对于使用 Docker 部署的 TTRSS 服务的支持似乎有一些问题,会出现 无法将文章标记为已读 的严重 bug。所以在这里我建议使用 Reeder,况且 Reeder 还要便宜 5 刀呢。

我们在 Reeder app 中选择 Add account > Fever,然后按以下配置填写:

项目内容
Serverhttps://你的域名/plugins/fever/,如https://rss.example.com/plugins/fever/
Emailadmin
Password为 Fever 插件 设置 的密码

填好后点击 Sign in,在详细配置中建议关闭 Refresh on server 节省服务器资源,随后回到文章列表,下拉刷新,便可以使用 Reeder 阅读你的 RSS 订阅内容了。

借助 IFTTT & Telegram 实现 RSS 更新推送

尽管 Reeder 拥有极佳的阅读体验,但相比各类付费 RSS 服务,自建 Tiny Tiny RSS + Reeder 还是有一个短板 —— 不能推送 RSS 订阅源的 更新通知。另外,Reeder 自带的后台应用刷新,不仅要求 app 常驻在最近应用中,而且还只能以角标形式显示未读文章数,不能推送详细的文章信息,仍然不够方便。下文中借助 RSSHub 订阅的一些内容(比如视频更新、推文等)在 Reeder 中查看,也显得有些不合适。所以,我们不妨借助 IFTTT & Telegram 来实现 RSS 更新自动推送。

首先,我们需要使用 Tiny Tiny RSS 中的一个过滤器功能:发布到 RSS 源。它可以将你指定的一些 RSS 订阅源更新自动发布到一个 RSS 源中。打开 Preferences > Filters,选择 Create filter。在 Match 中填入过滤参数(支持正则表达式);如果你想要推送所有的订阅源更新,则填入 .*field 中选择 Link in All feeds 即可。在 Apply actions 中选择 Publish article,随后保存规则。

这时我们的自动发布功能就配置完毕了。转到 Preferences > Feeds > Published & shared articles / Generated feeds 下,点击 Display URL 就能获得我们自动发布到的 RSS 地址了。记得 Copy 下来稍后要用。

下面配置 IFTTT。打开 IFTTT - My Applets,登录账号,点击 New Applet。

点击 Create action > Finish,完成设置。这样之后的 RSS 更新就会通过 IFTTT 推送到你的 Telegram 上了。记得要给 @IFTTT 通知权限。

另外,欢迎订阅咱的 Telegram 频道,这里有咱订阅的所有 RSS 源更新(逃

安装并使用 RSSHub

RSSHub 是一个轻量、易于扩展的 RSS 生成器,可以给任何奇奇怪怪的内容生成 RSS 订阅源。

借助 RSSHub,我们可以订阅普通 RSS 订阅不到的内容,比如 B 站 UP 主更新、Telegram 频道更新,等等。我们依旧使用 HyperApp 部署 RSSHub 的 Docker 容器。转到 HyperApp 的商店中,选择 Docker Image 并选择你的服务器,进入配置页面,然后按以下配置填写:

项目内容
Imagediygod/rsshub
Options--restart unless-stopped --expose 1200 -e CACHE_EXPIRE=1200 -e CACHE_CONTENT_EXPIRE=1800 -e DEBUG_INFO=false
Command(留空)
Args(留空)

其中 CACHE_EXPIRE 后的数值是路由缓存过期时间,CACHE_CONTENT_EXPIRE 后的数值是内容缓存过期时间,单位均为秒。

如果你不希望任何人都能访问到你的 RSSHub 服务,那么你可以在 Options 末尾添加访问控制选项:-e WHITELIST=<你的服务器 IP> -e ACCESS_KEY=<访问密钥>。这样,就只有你的 TTRSS 服务器或是有正确访问密钥的用户才能使用你的 RSSHub 服务了[3]

如果你想用 Nginx 反代 RSSHub 服务,则点击下方的 Show Nginx and SSL options,然后按以下配置填写:

项目内容
Domain你为 RSSHub 设置的域名(注意不是 Tiny Tiny RSS 的域名)
Port1200
HTTPSRedirect http to https
SSL-Domain(自动填写,应该与上面的Domain一致)
Email用来管理域名证书的邮箱

点击保存,然后在应用页面找到刚刚添加的 RSSHub,将其安装在你的服务器上。

此时我们打开浏览器,访问 https://你为RSSHub设置的域名,出现以下提示则代表 RSSHub 配置成功:

然后你就可以在 Tiny Tiny RSS 中添加 RSSHub 支持的订阅源了,订阅源地址为 https://你为RSSHub设置的域名/路由参数,相关路由参数请参考 RSSHub 官方文档

RSSHub 中部分 RSS 模块的配置

有部分服务(Youtube,Twitter 等)需要在配置 RSSHub 时填入相关参数才能订阅 RSS,具体的服务列表和参数类型你可以参考 RSSHub 官方文档。下面以 Youtube 为例解释一下如何配置。

根据 RSSHub 的 官方文档,我们需要提供 YouTube API Key。打开 Google 的 API 申请页面,点击左边的 Library > 搜索 “Youtube” > 选择 YouTube Data API v3 > Manage > Create credentials > 选择 API, Web server 和 Public data 三项,随后就可以在 Credentials 一栏中找到可用的 API Key 了。

获得 API Key 后,我们回到 HyperApp 中,修改 RSSHub 的设置:

项目内容
Imagediygod/rsshub
Options--restart unless-stopped --expose 1200 -e CACHE_EXPIRE=1200 -e CACHE_CONTENT_EXPIRE=1800 -e DEBUG_INFO=false -e YOUTUBE_KEY=<你的 API Key>
Command(留空)
Args(留空)

# 其实就是在 Options 末尾加上环境变量

点击保存,然后在应用页面找到 RSSHub,选择 Update config 更新配置。

小结

本文是这个 Blog 建立以来最长的一篇文章。由于使用了 Docker 和 HyperApp 等自动化工具,实际操作起来并不算复杂,半小时左右就能搞定。不过我在配置中也踩了不少的坑,浪费了不少的时间,比如上文提到的 Docker network 不能连接 TTRSS 与 PostgreSQL、Unread 无法标记文章已读等问题……说到这里,我想再次摘录少数派 这篇文章 中的一段内容:

当然,一旦涉及到这种 DIY 操作,总是要回应的质疑是:这么做值得吗?毕竟,「RSS 已死」不是什么新鲜论调了。这么说的人中,有的是 RSS 曾经的忠实用户,感慨曾经活跃的第三方软件和服务逐渐冷却;有的是新世代新闻、阅读服务的开发者,鄙弃 RSS 的老旧和刻板。

值得与否我不知道,但我清楚的是:如果你像我一样讨厌推荐算法与无尽的信息流,RSS 不失为一个很好的选择。而有句话叫「工欲善其事,必先利其器」,那么,花上几小时的时间配置自己的 RSS 服务,也是有用且有必要的事情。

↩︎ 注

  1. 这里参考了 使用 HyperApp 搭建 Tiny Tiny RSS。不过,由于 HyperApp 无法自定义容器名,而该文章中也没有设置 postgres 容器的 network-alias,因此按照该文的方法会导致 TTRSS 无法连接到 postgres 数据库。

  2. 这里我们使用 docker run--network-alias 参数指定了 postgres 容器的网络别名,解决了上述问题,使 TTRSS 能够通过 postgres 这一别名连接到 postgres 数据库。更多信息参见 Docker Documentation - Container networking

  3. 更多信息参见 RSSHub 文档 - 访问控制配置