RSSHub 自建订阅不更新?从 VPS 部署到路由排障逐层检查

从路由选择、VPS 部署到 Folo 订阅,把服务健康、上游请求、缓存和阅读器刷新分开排查。

·14 minDockerVPSRSSHub
把应用部署到土耳其|BRNCHOST · 土耳其 VDS
云服务器,积分可续期|雨云 · 国内外节点 · 积分兑换权益
低价年付,大流量 VPS|RackNerd · SSD 存储 · 1Gbps 端口
香港轻量,搭个小站|晚安云 · 香港云服务器
香港 VPS,大带宽可选|野草云 · BGP 直连
大陆访问,精品线路|搬瓦工 · CN2 GIA / CTGNet 套餐
资料归档,交给 AI 整理|WorkBuddy · 本地文件处理
建站起步,先看应用镜像|腾讯云 · 轻量应用服务器
CN2 GIA,中国方向优化|DMIT · Premium 网络
双 ISP 原生住宅 IP|丽萨主机 · 美国 9929 精品线路
高频 CPU,多地部署|Evoxt · 云服务器 · 每周异地备份
京东云轻量云主机:129元/年,新人专享,限购1台

订阅里最让人拿不准的情况,是没有报错,也没有新文章。你打开原网站,明明看到了更新;回到阅读器,最后一条却停在几天前。换一个公共 RSSHub 地址有时能恢复,有时仍然没用。

把 RSSHub 部署到自己的 VPS,能让这件事变得更可查:容器日志、路由参数、上游返回和缓存都在自己手里。不过,自建只解决了实例这一层的控制权,不会让目标网站的限制消失。与其先堆硬件,不如先把“一条订阅怎样到达阅读器”弄明白。

本文从选路由开始,给出 VPS 部署配置,再按实际链路拆开排障。适合已经在用 Folo 或其他 RSS 阅读器、准备把常用订阅迁到自建实例的人。

先确认你拿到的是哪一种地址

一个页面的网址、一条 RSSHub 路由和一个可订阅的 Feed 地址,是三种东西。

网页地址通常给人看,里面有导航、脚本和页面布局。RSSHub 路由描述如何从某个站点提取内容,例如 GitHub Issues 路由 /github/issue/DIYgod/RSSHub/open。把它接到你自己的 RSSHub 域名后面,再加上必要的访问参数,才是阅读器要请求的地址。

网站本来就有 RSS 或 Atom 时,通常先用原生源。GitHub 仓库发布记录可以直接订阅 https://github.com/DIYgod/RSSHub/releases.atom;它与 Issues 是两种不同内容。不要看见“GitHub”就随手拼一个路径,也不要把发布记录的原生 Atom 当成 RSSHub 是否工作正常的测试。

RSSHub Radar 可以帮助发现网页附近的订阅入口,但找到路由不代表当前一定可用。添加前仍要阅读路由参数、登录要求、浏览器依赖与已知限制。某个平台有一条路由,也不等于它的所有页面和账号类型都已覆盖。

用一条可解释的路由起步

这里选用 RSSHub 项目自身的 GitHub Issues,路径为:

/github/issue/DIYgod/RSSHub/open

其中 DIYgod 是用户或组织名,RSSHub 是仓库名,open 表示打开状态的问题。当前官方路由会请求 GitHub API,再把结果整理成 Feed,并过滤返回列表中的 Pull Request 项目。

这个例子容易看懂,也容易回到源站核对。但匿名 GitHub API 有请求限制,VPS 出口也可能被其他用户共享,因此它不是永不失败的基准。需要令牌时,应按当前 RSSHub 配置填写 GITHUB_ACCESS_TOKEN,并只授予实际需要的权限。令牌不要放进公开的 Compose 文件或文章截图。

先确定三条你真正想看的源,再选服务器:一条原生 Feed 用来确认阅读器本身,一条简单 RSSHub 路由用来确认服务链路,另一条是你实际需要、可能带登录或浏览器依赖的路由。这样出问题时有对照,不会所有东西一起失灵又无从下手。

选 VPS,要看它到源站的这一段

RSSHub 抓取网页时使用服务器的网络,阅读器连接的是你的服务入口。这是两段不同的连接。你访问 VPS 很快,不代表 VPS 访问目标网站也快;某个地区到你家的延迟更低,也不能证明该地区的机房 IP 更容易被源站接受。

有现成 VPS,可以先用它验证目标域名的 DNS、TLS 与 HTTP 返回。尚未购买时,就把机房、出口、流量和退换条件列进比较表。不要为了理论上的低延迟,忽视你最想订阅的源根本无法访问。

高防 / BGP,按需选线路|雨云云服务器 · 依地区与套餐提供

想给订阅单独留一个环境,可以从 雨云云服务器 查看当前可选方案。普通个人使用先关注 Linux、Docker、内存和流量;如果要跑需要浏览器的路由,再往上留资源。先让几条常用源跑顺,之后按实际占用升级,比开局就买很大的配置更容易判断钱花在哪里。

这里不列固定优惠价,也不把某个套餐与“所有路由稳定可用”绑定。活动与库存会变,源站对网络的要求也会变,下单前以当前页面和实际测试为准。

先把最小服务链路搭起来

下面面向已有 Docker Engine 与 Compose 插件的 Linux VPS。Caddy 运行在宿主机;如果由 1Panel 或其他面板管理反向代理,使用它现有的入口,避免再装一个服务抢占 80、443。

mkdir -p ~/services/rsshub
cd ~/services/rsshub
umask 077
printf 'RSSHUB_ACCESS_KEY=%s\n' "$(openssl rand -hex 32)" > .env
chmod 600 .env

新目录首次执行即可,已有 .env 时不要覆盖。保存下面的 compose.yaml:

name: rsshub
services:
  rsshub:
    image: ${RSSHUB_IMAGE:-diygod/rsshub:latest}
    restart: unless-stopped
    ports:
      - "127.0.0.1:1200:1200"
    environment:
      NODE_ENV: production
      CACHE_TYPE: redis
      REDIS_URL: redis://redis:6379/
      CACHE_EXPIRE: "900"
      ACCESS_KEY: ${RSSHUB_ACCESS_KEY:?Set RSSHUB_ACCESS_KEY in .env}
    depends_on:
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "curl -fsS --get --data-urlencode key=\"$$ACCESS_KEY\" http://127.0.0.1:1200/healthz >/dev/null"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 3
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
volumes:
  redis-data:

这份配置先不安装浏览器,只启动 RSSHub 与 Redis。RSSHub 的 1200 端口绑定本机回环地址,Redis 没有公网映射。900 秒是本文选用的路由缓存值,不是抓取定时器。

docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps

健康检查已经带上访问密钥。$$ACCESS_KEY 要保留双美元符号,否则可能在 Compose 解析阶段被错误替换。首次启动后稍等容器完成初始化,再看它是否进入健康状态。

宿主机 Caddy 可使用这个站点块,域名改成自己的:

rss.example.com {
    reverse_proxy 127.0.0.1:1200
}

DNS 指向服务器后,检查 A 与 AAAA 是否都正确,按实际环境放行 HTTPS 所需端口,验证配置再重载。Caddy 位于另一个容器中时,127.0.0.1 并不指向 RSSHub,应该改用双方都能访问的 Docker 网络地址。

从本机向外,一层一层测

RSSHub 排障顺序:先检查本机健康接口,再检查真实路由,最后检查域名和阅读器

排障顺序示意。每次只向外扩一层,更容易保留有用的判断。

先在 VPS 的部署目录中加载自己生成的环境文件,再检查服务健康:

set -a
. ./.env
set +a
curl -fsS --get \
  --data-urlencode "key=$RSSHUB_ACCESS_KEY" \
  http://127.0.0.1:1200/healthz

如果这里失败,先看容器、监听端口和密钥,不要急着改 DNS。点命令会执行文件内容,所以只加载自己维护的可信 .env。

本机健康检查成功后,再请求真正的路由。排障时保留响应头与正文比只看终端最后一行更有用:

curl -sS --get \
  --data-urlencode "key=$RSSHUB_ACCESS_KEY" \
  -D feed.headers \
  -o feed.xml \
  -w 'HTTP %{http_code}\n' \
  http://127.0.0.1:1200/github/issue/DIYgod/RSSHub/open
head -n 12 feed.headers
head -c 400 feed.xml

这次故意不用 -f,方便检查非成功响应里的错误信息。HTTP 200 也不是终点,还要看内容是不是 Feed、条目标题是否正确、时间是否符合源站。一个 HTML 验证页即使能下载,也不等于订阅正常。

本机真实路由正常后,再把请求地址换成 HTTPS 域名,在服务器外复测。只有域名这一层失败,就集中排查解析、证书、代理和入口防火墙。至于阅读器抓不到,最后再看阅读器的请求环境与刷新计划。

几种相似现象,背后的原因并不一样

容器在运行,健康状态却一直失败

首先检查开启访问控制之后,健康检查有没有带密钥。RSSHub 当前访问控制只放行少数公共路径,/healthz 不在放行列表。只测首页能打开,无法证明带保护的路径能访问。

再看健康检查程序是否存在、命令是否被 shell 正确解析、初始化是否尚未完成。本文使用官方镜像提供的 curl,并留了启动等待时间。如果换成自己制作的精简镜像,需要重新核对这些条件。

只有某条路由失败,其他订阅正常

服务入口大概率仍然可用,排查应转向该路由。先确认路径、用户 ID、分类参数有没有抄错,再看日志中的上游状态。404 可能来自路由本身,也可能是上游页面不存在;403 既可能与本实例访问控制有关,也可能来自目标网站。不要只看状态码就认定一个原因。

限流、登录过期、页面结构改变,都不能靠重启 Redis 根治。出现明确的上游拒绝时,按平台允许的方式配置登录信息或降低请求频率;不要把“不断重试”当成修复。

XML 能打开,但内容好像停住了

比较四件事:源站确实有新内容吗,当前路由过滤条件是否包含它,RSSHub 返回的 Feed 是否已经包含它,阅读器最后一次拉取是什么时候。某些页面显示的置顶或编辑时间,与路由使用的发布时间也未必一致。

缓存会影响新内容出现的时间,阅读器自己的刷新节奏也会影响。为了追一条更新把缓存改成几秒,并让多个客户端高频拉取,可能先触发上游限制。先确认延迟发生在哪一段,再决定是否调整。

浏览器能看,云阅读器却连不上

你本机能访问的地址,不一定能从阅读器服务端访问。回环地址、局域网地址、仅 VPN 可达的域名,对云端抓取往往不可用。还要检查完整 URL 是否被正确保存:多个查询参数使用 & 连接,已经有查询串时不能再加第二个 ?。

若直接 XML 正常、阅读器里只是没有显示新条目,还应排查阅读器的去重、过滤或视图。Feed 的返回结果与客户端展示是两层,不要因为界面没变就立刻重建整套服务。

密钥不要跟着求助截图一起发出去

主密钥可以访问实例中受保护的路径,订阅地址中的 code 则是按路径生成的访问码。当前计算方法是 MD5(路径 + 主密钥),路径来自 URL 的 pathname,查询参数不参与计算。

可以在已经加载环境变量的部署目录执行:

python3 - <<'PY'
import hashlib, os
path = '/github/issue/DIYgod/RSSHub/open'
code = hashlib.md5((path + os.environ['RSSHUB_ACCESS_KEY']).encode()).hexdigest()
print('https://rss.example.com' + path + '?code=' + code)
PY

输出地址仍包含凭据,适合保存到自己的阅读器,不适合公开分享。修改路径后要重新生成访问码;更换主密钥会使旧码失效。路径码并非有有效期、独立撤销与细粒度查询权限的完整令牌系统。

向社区提交问题时,可以保留路由结构、RSSHub 版本、错误类型与经过处理的日志,把令牌、Cookie、私有账号标识及访问码去掉。给出能重现问题的条件,比一张只有“请求失败”四个字的截图有用得多。

需要浏览器的时候,再加浏览器

普通路由已经工作,某条路由仍提示浏览器依赖缺失,就回到它的官方说明。RSSHub 官方部署示例提供独立 Browserless 连接方式,也有带 Chromium 的镜像可选。不同镜像版本的连接地址、认证与资源设置应单独核对。

浏览器进程会增加资源占用。不要因为普通 API 路由在小机器上很轻,就推断几十个需要渲染的页面也一样。独立浏览器服务只在内部 Docker 网络里提供给 RSSHub,通常无需给公网再开一个管理端口。

添加后,用那条真正依赖浏览器的路由验收,同时查看内存、超时与进程状态。仅仅 /healthz 变绿,无法证明浏览器连接和页面解析成功。

把订阅整理成能长期读下去的样子

服务可用之后,在 Folo 或其他阅读器添加完整 Feed 地址,先观察几次更新。把需要立即处理的通知与适合闲时浏览的长文分开;某个源每天发几十条,你却几乎不读,删掉它往往比提高刷新频率更有帮助。

RSSHub 让没有 Feed 的网页获得一个可订阅入口,但并不保证历史内容完整回填,也不保证全文、图片与附件永远可访问。真正需要保存的材料,应结合阅读器的导出或归档能力另行处理。

给重要路由留一份简短记录:源站地址、路由、关键参数、是否需要令牌、上次成功核对的时间。下次网站改版时,这份记录会比重新搜索一轮教程省事。自建的意义也在这里:知道哪一层出了问题,知道该改哪一处,而不是不断更换一个看起来能用的地址。

参考资料

本文的基础 Compose 已在本机隔离 Docker 环境验证:RSSHub 与 Redis 健康检查通过;带密钥的健康请求返回 200,无密钥返回 403;GitHub Issues 示例及路径访问码返回了可解析的 RSS。这不等于所有机房、路由或第三方登录都经过实测。

核对日期为 2026 年 9 月 30 日;第三方网站变化可能导致个别路由随后失效。