在OCI ARM实例上使用Docker结合Traefik快速部署FreshRSS和RSSHub服务
文章目录
背景
很长一段时间内,都是在某乎上阅读技术类文章。遗憾的是,某乎的算法似乎总喜欢推送一些猎奇类的主题给到自己,加之平台广告实在太多,最终果断删了App,于是世界瞬间清净了。后来阅读的主要方式就变成了刷独立博客,比较笨拙,都是在手机浏览器里浏览,等标签页关了也就忘了。前两天在iPad上下载了Reeder 5作为RSS阅读器,发现界面还不错,于是决定自建RSS服务,方便日常的使用和管理,也提升一下阅读体验。
果然,好习惯的养成都是被免费互联网服务给逼上self-host这条路的。不得不感慨一句,免费的才是最贵的啊!
基本概念
RSS全称简易信息聚合(RDF Site Summary 或 Really Simple Syndication),是一种用 XML 编写的文本格式,用于在互联网上以完全自动化的方式发布新闻标题和内容。RSS属于消息来源(web/news feed)格式规范的一种,可以聚合信源网站的内容更新,并自动通知用户(订阅者)。
FreshRSS 是一个基于PHP语言的自托管 RSS 源聚合器。具备轻量、易于使用、功能强大且可定制等特点。功能十分丰富且强大,支持多用户,且具有匿名阅读模式。同时,支持自定义标签,并提供基于 Google Reader API (推荐)和 Fever API (功能和效率部分受限)的应用程序接口和命令行界面。
RSSHub 是一款开源、易用且可扩展的 RSS 源聚合器,它能从几乎所有内容生成 RSS 源。RSSHub 提供从各种来源聚合的数百万条内容,并可与浏览器扩展程序 RSSHub Radar 和移动辅助应用程序 RSSBud(iOS)和 RSSAid(Android)一起使用。
简单来说,我们可以通过RSSHub将任何不支持RSS的内容都聚合为RSS源,再添加进FreshRSS管理。之后就可以借助FreshRSS的GReader API将内容导入客户端应用程序阅读,从而最终实现万物皆可读的效果。主要的优势在于,不必再去忍受那些莫名其妙的算法了,传统,但是有用。
先决条件
- 已拥有云服务实例(本文基于Oracle Cloud Infrastructures的ARM实例实践)
- 已部署Docker及Docker Compose
- 已部署Traefik
部署步骤
1. 部署思路
FreshRSS官方的镜像里提示自身支持ARM架构的设备,甚至能在树莓派( Raspberry P 1)上运行。但笔者在实际构建过程中却发现,如果使用官方镜像image: freshrss/freshrss
,在甲骨文OCI的ARM实例上freshrss服务会无限exit,无法正常运行。
不过,好在Linuxserver团队也提供了FreshRSS镜像,使用的是image: lscr.io/linuxserver/freshrss
,为arm64架构的设备提供完美支持。
对于RSSHub则使用官方提供的docker-compose.yml示例文件进行部署即可。考虑到我们将主要是在服务器单机上配合FreshRSS使用,因此将其与FreshRSS写在同一个docker-compose.yml文件中。
当使用Traefik进行反代时,我们为FreshRSS配置一下域名,RSSHub则仅定义清楚hostname即可,将服务加入同一个网络,后续即可直接使用hostname来唤起RSSHub的功能。
2. 配置文件示例
完整的docker-compose.yml文件如下,请提前在域名服务商处将rss.yourdomain.com
指向您的云实例IP地址:
version: "3"
services:
freshrss-db:
image: postgres:latest
container_name: freshrss-db
hostname: freshrss-db
restart: always
volumes:
- freshrss-db:/var/lib/postgresql/data
environment:
POSTGRES_USER: username # 不建议明文,可以使用docker secrets配置
POSTGRES_PASSWORD: password # 不建议明文,可以使用docker secrets配置
POSTGRES_DB: database_name # 不建议明文,可以使用docker secrets配置
networks:
- proxy
freshrss-app:
image: ghcr.io/linuxserver/freshrss
container_name: freshrss-app
hostname: freshrss-app
restart: unless-stopped
logging:
options:
max-size: 10m
ports:
- "39954:80" # 映射端口
depends_on:
- freshrss-db
- rsshub
volumes:
- ./config:/config # 插件目录/config/www/FreshRSS/extensions,用于后续安装插件
environment:
CRON_MIN: '*/45' # RSS 刷新周期,单位为分钟,*/45 表示每 45 分钟刷新一次
TZ: Asia/Shanghai # 时区
TRUSTED_PROXY: 172.16.0.1/12 192.168.0.1/16
labels:
- traefik.enable=true
- traefik.docker.network=proxy
- traefik.http.routers.freshrss.entrypoints=websecure
- traefik.http.routers.freshrss.rule=Host(`rss.yourdomain.com`)
- traefik.http.routers.freshrss.middlewares=default@file
- traefik.http.routers.freshrss.middlewares=error-pages
networks:
- proxy
rsshub:
# two ways to enable puppeteer:
# * comment out marked lines, then use this image instead: diygod/rsshub:chromium-bundled
# * (consumes more disk space and memory) leave everything unchange
image: diygod/rsshub
container_name: rsshub
hostname: rsshub
restart: always
ports:
- '1200:1200'
environment:
NODE_ENV: production
CACHE_TYPE: redis
REDIS_URL: 'redis://redis:6379/'
PUPPETEER_WS_ENDPOINT: 'ws://browserless:3000' # marked
PROXY_URI: 'socks5h://warp-socks:9091'
depends_on:
- redis
- browserless # marked
networks:
- proxy
browserless: # marked
image: browserless/chrome # marked
restart: always # marked
ulimits: # marked
core: # marked
hard: 0 # marked
soft: 0 # marked
networks:
- proxy
redis:
image: redis:alpine
restart: always
volumes:
- redis-data:/data
networks:
- proxy
warp-socks:
image: monius/docker-warp-socks:latest
privileged: true
volumes:
- /lib/modules:/lib/modules
cap_add:
- NET_ADMIN
- SYS_ADMIN
sysctls:
net.ipv6.conf.all.disable_ipv6: 0
net.ipv4.conf.all.src_valid_mark: 1
healthcheck:
test: ["CMD", "curl", "-f", "https://www.cloudflare.com/cdn-cgi/trace"]
interval: 30s
timeout: 10s
retries: 5
networks:
- proxy
volumes:
freshrss-db:
redis-data:
config:
networks:
proxy:
external: true
3. 开启服务
现在,让我们在终端中开启服务:
# 首次开启服务请避免加上 -d
sudo docker compose up
服务全部正常运行,让服务在后台常驻:
sudo docker compose down && sudo docker compose up -d
4. 访问URL完成FreshRSS前端配置
在浏览器中打开前面在docker-compose.yml配置文件中定义的host网址rss.yourdomain.com
。首次访问会自动触发FreshRSS的配置步骤。
配置相对比较简单,唯一需要注意的地方在第3步,数据库类型选择我们在docker-compose.yml配置文件中构建的PostgreSQL
数据库,Host填写我们在配置文件中为数据库服务定义的hostname名称freshrss-db
。数据库的用户名、密码、数据库名则按实际配置时的填写即可。
下图为第3步的示例,其中Host是笔者为了测试而写的值,实际并不可行,要改成docker中定义的hostname:freshrss-db
前往右上角系统设置页面(Authentication),开启API访问:
前往资料页面(Profile),设置API密码:
5. 安装FreshRSS插件
FreshRSS具有极其丰富的插件,前往设置的插件部分可以查看可用的社区插件列表:
插件的安装其实也非常简单。虽然不能在前端页面上直接安装,但操作起来也算不上复杂。我们以 LaTeX support 插件为例进行示范。
首先,我们前往extensions文件夹:
cd src/apps/rss.example.com/config/www/freshrss/extensions
然后,下载GitHub上 LaTeX support 的zip扩展包
sudo wget https://github.com/aledeg/xExtension-LatexSupport/archive/refs/heads/main.zip
如图:
接下来解压得到的zip包:
sudo unzip main.zip && sudo rm main.zip
刷新一下扩展页面吧,猜猜发现了什么?
还不快试试其他插件,开心地玩耍吧!不过也要注意,有些插件是需要安装额外的依赖服务的,还请仔细阅读插件GitHub页面的介绍。
6. RSSHub的使用
主要参考官方文档:Generate an RSS Feed
以生成bilibili用户bangumi为例,来说明如何配置自托管RSSHub生成自定义Feed。
官方示例的Feed生成逻辑为:RSSHub服务地址
+目标服务路径
+目标ID
,譬如 https://rsshub.app/bilibili/bangumi/media/9192
因此,如果我们自托管的RSSHub需要跟踪bangumi的番剧,需要将Feed写成这样:
http://rsshub:1200/bilibili/bangumi/media/9192
注:URL中的rsshub为前面配置docker-compose.yml文件时定义的hostname
官方提供的抓取规则说明如下:
路径规则: /bilibili/bangumi/media/:mediaid
参数:
mediaid为必须值 - 番剧媒体 id, 番剧主页 URL 中获取
接下来我们将该自定义Feed添加进FreshRSS中。
7. 在FreshRSS中添加RSSHub源
添加自定义RSSHub的Feed源:
添加成功:
抓取结果:
8. 配置客户端访问
最后就是在客户端配置FreshRSS的访问了,笔者使用的是iPad端的Reeder 5作为示例。如果您希望使用免费的RSS阅读器,NetNewsWire也不失为一个不错的选择。
当首次进入Reeder 5,选取Self-Host的FreshRSS服务时,软件会提示输入Server、Username以及Password。当按照要求输入之后,点击Sign in却始终提示登录错误,令笔者无比头疼,以为买下Reeder 5的那4.99刀就此打了水漂。
搜索一圈,发现GitHub上很久之前已经有人报过issue: Reeder 5 iOS unable to login to FreshRSS?),但处于未解决的状态。好在机智的笔者,终于看清了问题的本质,探寻到了问题的真相,于是随手一个comment解救万民于水火(此处应有掌声👏👏👏):
简单来讲,要解决Reeder 5登录失败的问题,需要注意将Server处的URL由http://
改为https://
。Reeder 5在自动转换我们的API URL的时候,会把 https://rss.example.com/api/
自动转换为 http://rss.example.com/api/greader.php
,从而导致登录一直失败。考虑到Reeder 5的作者已经好几个月没有更新了,未来这个问题是否会修复也是个未知数。
总结
这次在机缘巧合之下遇到FreshRSS这款工具,坦白讲,真正使用之后还是感觉非常惊艳的,用户体验远超预期。在算法的世界,我们要珍惜还在默默写着独立博客的原创作者(比如笔者,此处掌声👏),更加要珍惜的是独立阅读与思考的能力。
另外就是关于RSSHub,笔者在实践过程中,发现部分社交服务平台(如X)似乎已经屏蔽了RSSHub,即便使用自托管的方案也不行。如果大家遇到有些始终无法成功添加的自定义Feed,也不必太过于纠结。
最后,鼓励大家都尝试使用FreshRSS和RSSHub,确实非常实用。
最后的最后,感谢Oracle Cloud Infrastructures提供的云计算实例,如果没有OCI,我们开发者在尝试新技术和新产品时,将不得不面对高昂的基础设施成本。正是甲骨文的善举,令技术可以造福更多人群。致谢!