前言

这几年伴随着 AI 和 LLM 的高速发展,RSS 订阅似乎已经不再「主流」。但是对于希望摆脱算法推荐、远离社交媒体噪音的人们来说,它仍然是一种干净、可控、私密的内容获取方式。

本着实用性为主的原则,本文介绍我的自建 RSS 服务信息流,目前体验下来,还算稳定。

整套工作流程概述如下:

  • Miniflux 提供统一的信息订阅管理及 API 接口
  • RSSHub 提供各种不支持 RSS 订阅站点的路由
  • Warp 提供本地 HTTP/Socket5 代理,解决抓取问题

等后面整理完,我会将开箱即用的 Docker Compose 部署模板及 Nginx 反向代理配置文件更新到 Git 存储库 dejavu/selfhosted

Warp 本地代理

使用 cmj2002/warp-docker 直接部署,可以在容器内为宿主机器提供一个易用的本地代理,这里我使用了 Cloudflare Zero Trust 的 Warp 网关。

我们无需暴露任何端口,容器间通信通过公用 Docker 子网更加安全,建议直接注释下面这部分

ports:
  - "1080:1080"

配置 Docker 子网

创建一个 Docker 子网,确保后面 Miniflux 和 RSSHub 容器都能访问这个网络

sudo docker network create warp-tunnel

修改 warp-docker 的 Compose 模板,加入这个 Docker 子网,然后重启服务。

services:
  warp:
    image: caomingjun/warp:slim-latest
    container_name: warp
    # ...
    # add network
    # ...
    networks:
      - warp-tunnel
    # ...
    # ...

# add external docker subnet
networks:
  warp-tunnel:
    external: true

测试下,应该能看到 warp=on

curl --socks5-hostname 127.0.0.1:1080 https://cloudflare.com/cdn-cgi/trace

Tunnel 配置

使用 Cloudflare Zero Trust 的 Warp 网关,需要在设备配置文件中对上面的 Docker 子网进行隧道分离 (Split Tunnels)。

查看 Docker 子网信息,并将 subnet 的网段添加到 Cloudflare Zero Trust 的分离隧道

sudo docker network inspect warp-tunnel

参考 使用 Miniflux + RSSHub 打造个人 RSS 阅读器 ,将 Miniflux 和 RSSHub 服务编排在一个 Compose 模板内,仅需暴露 Miniflux 的端口,其余 Docker 绑定端口可以删除(仅限子网内访问)。

将它们都加入 Warp 的子网,现在看起来应该像下面这样:

services:
  miniflux:
    image: miniflux/miniflux:latest
    container_name: miniflux
    # ...
    # ...
    ports:
      - "127.0.0.1:8080:8080"
    networks:
      - warp-tunnel

  db:
    image: postgres:17-alpine
    container_name: miniflux-db
    # ...
    # ...
    networks:
      - warp-tunnel

  rsshub:
    image: diygod/rsshub
    container_name: rsshub
    restart: unless-stopped
    # ...
    # ...
    networks:
      - warp-tunnel
    depends_on:
      - redis
      - browserless

  real-browser:
    image: ghcr.io/hyoban/puppeteer-real-browser-hono
    container_name: rsshub-real-browser
    restart: unless-stopped
    # ...
    # ...
    networks:
      - warp-tunnel

  browserless:
    image: browserless/chrome
    container_name: rsshub-browserless
    restart: unless-stopped
    # ...
    # ...
    networks:
      - warp-tunnel

  redis:
    image: redis:alpine
    container_name: rsshub-redis
    restart: unless-stopped
    # ...
    # ...
    networks:
      - warp-tunnel

networks:
  warp-tunnel:
    external: true

这样部署启动服务后,Miniflux 和 RSSHub 都可以使用 Warp 网关

设置代理

RSSHub 原生支持 HTTP 代理,环境变量新增一个 PROXY_URI

  rsshub:
    image: diygod/rsshub
    container_name: rsshub
    restart: unless-stopped
    environment:
      # ...
      # ...
      PROXY_URI: "http://warp:1080"

Miniflux 代理设置

Miniflux 可以继承 Go 的代理机制,只需设置相应的环境变量,即可让所有抓取流量统一走 Warp 网关,从而避免在每个订阅条目中手动配置代理 URL 的步骤。

  miniflux:
    image: miniflux/miniflux:latest
    container_name: miniflux
    # ...
    # ...
    ports:
      - "127.0.0.1:8080:8080"
    networks:
      - warp-tunnel
    environment:
      # ...
      # ...
      - HTTP_PROXY=http://warp:1080
      - HTTPS_PROXY=http://warp:1080

不希望所有 RSS 请求都通过 Warp 路由转发?参考 Miniflux 配置文档 ,可以通过环境变量配置 HTTP_CLIENT_PROXIESHTTP_CLIENT_PROXY,手动为特定源或默认抓取行为指定代理策略。

测试服务

改完环境变量后,现在启动所有服务

sudo docker compose up -d

登录 Miniflux 控制面板,添加订阅源,好像都没问题。嗯?为什么 RSSHub 路由全部 503 错误?

我又进几个容器查看了下日志,然后在 Miniflux 中日志发现了问题:因为以 Go 的代理机制,Miniflux 所有请求都会走 Warp 网关,这样访问 RSSHub 路由就会进入 代理循环黑洞

在 Minilfux 的模板中排除 RSSHub 主机名,最终看起来应该像这样:

    environment:
      # ...
      # ...
      - HTTP_PROXY=http://warp:1080
      - HTTPS_PROXY=http://warp:1080
      - NO_PROXY=rsshub,db,localhost,127.0.0.1

重新启动容器

sudo docker compose up -d

测试了下,比如使用 RSSHub 的 Docker 镜像更新路由

http://rsshub:1200/dockerhub/build/caomingjun/warp/slim-latest

订阅成功,RSSHub 路由已经可用了,大功告成!