在OCI ARM实例上使用Docker结合Traefik快速部署FreshRSS和RSSHub服务

 · 6 分钟阅读
 · 教授
文章目录

背景


很长一段时间内,都是在某乎上阅读技术类文章。遗憾的是,某乎的算法似乎总喜欢推送一些猎奇类的主题给到自己,加之平台广告实在太多,最终果断删了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 image.png

前往右上角系统设置页面(Authentication),开启API访问: image.png

前往资料页面(Profile),设置API密码: Screenshot 2023-08-30 at 9.01.22 PM.png

5. 安装FreshRSS插件

FreshRSS具有极其丰富的插件,前往设置的插件部分可以查看可用的社区插件列表: Screenshot 2023-08-30 at 9.04.42 PM.png

插件的安装其实也非常简单。虽然不能在前端页面上直接安装,但操作起来也算不上复杂。我们以 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

如图: image.png

接下来解压得到的zip包:

sudo unzip main.zip && sudo rm main.zip

刷新一下扩展页面吧,猜猜发现了什么? image.png

还不快试试其他插件,开心地玩耍吧!不过也要注意,有些插件是需要安装额外的依赖服务的,还请仔细阅读插件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源: image.png

添加成功: Screenshot 2023-08-30 at 11.04.26 PM.png

抓取结果: image.png

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解救万民于水火(此处应有掌声👏👏👏): image.png

简单来讲,要解决Reeder 5登录失败的问题,需要注意将Server处的URL由http://改为https://。Reeder 5在自动转换我们的API URL的时候,会把 https://rss.example.com/api/ 自动转换为 http://rss.example.com/api/greader.php ,从而导致登录一直失败。考虑到Reeder 5的作者已经好几个月没有更新了,未来这个问题是否会修复也是个未知数。

IMG_0330.PNG

总结


这次在机缘巧合之下遇到FreshRSS这款工具,坦白讲,真正使用之后还是感觉非常惊艳的,用户体验远超预期。在算法的世界,我们要珍惜还在默默写着独立博客的原创作者(比如笔者,此处掌声👏),更加要珍惜的是独立阅读与思考的能力。

另外就是关于RSSHub,笔者在实践过程中,发现部分社交服务平台(如X)似乎已经屏蔽了RSSHub,即便使用自托管的方案也不行。如果大家遇到有些始终无法成功添加的自定义Feed,也不必太过于纠结。

最后,鼓励大家都尝试使用FreshRSS和RSSHub,确实非常实用。

最后的最后,感谢Oracle Cloud Infrastructures提供的云计算实例,如果没有OCI,我们开发者在尝试新技术和新产品时,将不得不面对高昂的基础设施成本。正是甲骨文的善举,令技术可以造福更多人群。致谢!

参考资料


  1. FreshRSS
  2. RSSHub
  3. freshrss/freshrss
  4. linuxserver/freshrss
  5. Routes
  6. Reeder 5 iOS unable to login to FreshRSS?