跳到主要内容

部署教程

RSSHub 部署教程:Docker Compose、订阅路由与访问密钥

发布于

使用 VPS 部署 RSSHub,介绍配置、访问方式、实际操作及数据备份。

开始前

每天打开几个网站看更新,单次花不了多少时间,积起来却很烦。RSS 能把这些更新放进同一个收件箱;碰到没有订阅地址的网站,RSSHub 则补上了中间那一段:读取网站内容,整理成阅读器能识别的订阅源。

把 RSSHub 放到自己的 VPS 上,最实在的好处是入口、配置和更新时间都可以自己管。公共实例拥挤时,不用跟着换地址;某条路由需要令牌,也有地方保存。但自建并不意味着所有网站都会放行:上游限流、登录要求和页面改版,仍然会影响结果。

这篇从一台已经能通过 SSH 登录的 Linux VPS 开始,完成 Docker Compose 部署、Redis 缓存、访问密钥、Caddy 反向代理,再把一条真实路由交给阅读器。示例里的 `rss.example.com` 是占位域名,操作时要换成自己的。

部署前先确认 VPS 的磁盘、内存和公网访问条件,也可以查看雨云云服务器;注册时填写优惠码 `KuZhuJi`。

前往雨云选购 ↗

注册推荐码:KuZhuJi

先弄清楚要装什么

RSSHub 是内容转换服务,不是保存已读状态的阅读器。Folo、FreshRSS 或其他 RSS 客户端负责展示文章、标记已读、整理文件夹;RSSHub 负责让原本没有标准 Feed 的页面也能被订阅。两者可以搭配,也可以分别使用。

如果一个网站已经提供稳定的原生 RSS 或 Atom,优先用原生地址。例如 RSSHub 项目发布记录本身就有 GitHub Releases Atom,没必要为它额外绕一次转换。把 RSSHub 留给真正缺订阅入口的内容,维护负担会小很多。

本文先部署不带浏览器的基础服务。部分路由依赖 Chromium 或 Browserless,等确认需要再加。一次把所有依赖装齐,看起来省事,真正出问题时却很难判断是哪一层在拖后腿。

买服务器之前,先看你要订阅哪些网站

RSSHub 的请求从 VPS 发出。因此,服务器到目标网站的连通性,比你本机访问服务器的速度更值得关注。主要订阅海外开发者社区,就要关注机房到相应平台的访问情况;主要关注中文网站,也不能只凭“国内机房”四个字判断是否可用。目标站对机房 IP、地区和访问频率可能有自己的限制。

给少量个人订阅做起步预算,可以从 1—2 GB 内存的普通 Linux VPS 考虑。要跑浏览器路由、同时订阅很多更新频繁的源,应该留出更多内存,并根据实际占用调整。

选购时把这几项看清楚:能否使用 Docker,是否有独立公网入口,流量与带宽怎么计费,系统能否重装,续费价格是多少。已经有闲置 VPS 的话,先拿现有机器试几条路由,通常比直接买新机器更合理。

还没有服务器,可以从 雨云云服务器入口 看起。用于本文这类 Docker 服务,重点比较云服务器的内存、系统与网络条件;没必要因为产品列表里还有游戏云或裸金属,就给一个个人订阅工具配上用不到的规格。下单前再核对当时的套餐、续费与退款说明,具体价格以页面为准。

把公网入口收在 Caddy 这一层

*部署结构示意。下面的配置假设 Caddy 装在宿主机,而不是另一个容器里。*

本文让 RSSHub 只监听宿主机 `127.0.0.1:1200`,Redis 不映射宿主机端口。阅读器通过 HTTPS 域名访问 Caddy,再由 Caddy 转发给 RSSHub。这样无需向公网开放 1200 和 6379,也不必让客户端记住端口号。

如果你已有 1Panel 或其他面板,先确认哪个服务占用了 80、443,以及已有代理能否复用。不要在同一台机器上再起一个争抢端口的 Caddy。容器里的 Caddy 访问 `127.0.0.1` 指向它自己,需要改用同一 Docker 网络中的服务名;不能原样照抄本文的宿主机配置。

建好目录,保存访问密钥

先安装 Docker Engine 和 Compose 插件。不同发行版的安装命令不同,按 Docker 官方安装入口 选择系统。已经安装 Docker 的机器先检查:

bash;使用前请核对本文前提。 如内容超出,可左右滑动,键盘使用方向键或 Home/End 查看。
仅复制文本,不会执行。
docker version
docker compose version

以下命令假设当前用户有 Docker 权限;没有时按系统管理方式使用 `sudo`。能操作 Docker 的账号具备很高权限,不要为图方便给无关用户加入 Docker 用户组。

bash;使用前请核对本文前提。 如内容超出,可左右滑动,键盘使用方向键或 Home/End 查看。
仅复制文本,不会执行。
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`:

yaml;使用前请核对本文前提。 如内容超出,可左右滑动,键盘使用方向键或 Home/End 查看。
仅复制文本,不会执行。
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:

这里有几个看似细小、实际很关键的地方。

`CACHE_EXPIRE: "900"` 是本文主动设置的路由缓存时间,单位为秒,也就是 15 分钟。它不是“每隔 15 分钟主动抓取全站”的定时任务。阅读器发来请求,RSSHub 再结合缓存处理;阅读器自己的刷新间隔还会影响你看到更新的时间。

`depends_on` 配合 Redis 健康检查,让首次启动时尽量避免 RSSHub 抢在 Redis 准备好之前连接。它不能代替运行期间的错误处理,也不能保证上游网站一直可达。

健康检查里的 `$$ACCESS_KEY` 有两个美元符号。这是让 Compose 把变量交给容器内的 shell 展开。只写一个美元符号,可能被 Compose 在宿主机侧提前替换。密钥开启后,`/healthz` 也受访问控制;漏带密钥会把正常服务判成不健康。

Redis 只做缓存,命名卷保留其数据目录。不要把它当成文章归档库,RSSHub 也不会因为接了 Redis 就替你永久保存所有历史文章。

准备独立实例时,可在雨云选择适合的云服务器配置,优惠码 `KuZhuJi`。配置按实际任务选择,数据库和附件另做备份。

启动后,先在服务器本机检查

bash;使用前请核对本文前提。 如内容超出,可左右滑动,键盘使用方向键或 Home/End 查看。
仅复制文本,不会执行。
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=80 rsshub

`config --quiet` 检查配置是否能解析,不会把完整配置和密钥打印出来。镜像第一次下载可能较慢;如果失败,先看是网络、磁盘空间,还是镜像平台不兼容,不要一上来就把整台服务器重装。

接着检查健康接口:

bash;使用前请核对本文前提。 如内容超出,可左右滑动,键盘使用方向键或 Home/End 查看。
仅复制文本,不会执行。
set -a
. ./.env
set +a
curl -fsS --get \
  --data-urlencode "key=$RSSHUB_ACCESS_KEY" \
  http://127.0.0.1:1200/healthz

这段只适用于自己创建并维护的 `.env`,因为 shell 会执行文件里的内容。不要对网上下载的未知环境文件运行 `source` 或点命令。

健康接口成功,只说明入口能响应。下一步还要测真实路由。本文用 RSSHub 仓库的 GitHub Issues 路由作为例子:

bash;使用前请核对本文前提。 如内容超出,可左右滑动,键盘使用方向键或 Home/End 查看。
仅复制文本,不会执行。
curl -fsS --get \
  --data-urlencode "key=$RSSHUB_ACCESS_KEY" \
  http://127.0.0.1:1200/github/issue/DIYgod/RSSHub/open \
  -o feed.xml
head -c 300 feed.xml

正常结果应是 Feed 内容,而不是登录页或错误 HTML。这条路由依赖 GitHub API,可受匿名请求额度影响;它是验证路径的例子,不是保证永远成功的测试服务器。遇到限流时,先看日志和 GitHub 返回信息,再决定是否按 RSSHub 配置添加令牌。

接上域名与 HTTPS

给自己的子域名添加指向 VPS 的 A 记录。如果设置了 AAAA,也要确保对应 IPv6 地址能正常服务;错误的 AAAA 会造成一部分客户端正常、一部分失败。DNS 托管在哪家并不影响 Caddy 的基本使用,不需要为了这套部署强行迁移到 Cloudflare。

在宿主机已有的 Caddyfile 中添加独立站点块,保留其他站点:

caddyfile;使用前请核对本文前提。 如内容超出,可左右滑动,键盘使用方向键或 Home/End 查看。
仅复制文本,不会执行。
rss.example.com {
    reverse_proxy 127.0.0.1:1200
}

常规公开 HTTPS 部署需要域名正确解析,服务器入口和防火墙允许所需的 80、443 流量,并且没有其他程序争抢监听。验证配置后再重载:

bash;使用前请核对本文前提。 如内容超出,可左右滑动,键盘使用方向键或 Home/End 查看。
仅复制文本,不会执行。
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

若 Caddy 由容器或面板管理,应使用对应的验证、重载方式,而非生搬 systemd 命令。拿到证书也不是部署结束,再从服务器外测试一次域名下的健康接口和真实路由。

不要为排查代理问题临时把 Redis 暴露到公网。Caddy 无需直接访问 Redis,开放 6379 对解决证书、域名或 RSSHub 路由问题没有帮助。

需要增加服务器时,可以打开雨云选购页面,填写优惠码 `KuZhuJi`;迁移前保留数据与原有部署配置。

交给阅读器时,可以只给一条路由的访问码

最直接的订阅地址是:

text;使用前请核对本文前提。 如内容超出,可左右滑动,键盘使用方向键或 Home/End 查看。
仅复制文本,不会执行。
https://rss.example.com/github/issue/DIYgod/RSSHub/open?key=你的访问密钥

但把主密钥放进云阅读器,就相当于把实例的通用访问凭据交给它。RSSHub 还支持按路径生成 `code`。当前实现是对“路由路径 + 主密钥”计算 MD5;下面用 Python 生成,不把密钥写死进命令:

bash;使用前请核对本文前提。 如内容超出,可左右滑动,键盘使用方向键或 Home/End 查看。
仅复制文本,不会执行。
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

路径要与订阅 URL 完全一致,包含开头的 `/`。查询参数不参与当前实现的计算;这个访问码可以约束路径,却不是有到期时间的完整授权系统。拿到它的人仍然能请求这条路径,主密钥更换后旧访问码也会失效。不要把含 `key` 或 `code` 的地址公开贴出来。

在 Folo 或其他阅读器中选择添加订阅,把完整地址粘进去。先订阅三五个真正会读的源,过几天再增加。一次导入几百个地址,除了很快堆出未读数,也会让排查坏源变得麻烦。

跑起来之后,还要留下这些东西

保存好 `compose.yaml`、`.env`、Caddyfile 对应站点块,以及正在使用的镜像摘要。`latest` 便于首次安装,但以后拉取会拿到新的镜像;维护时应记录已验证版本,必要时把 `RSSHUB_IMAGE` 固定成摘要再更新。

日志轮转能限制本文配置下容器日志的增长,不能限制镜像、缓存卷和系统其他日志。定期看一次 `df -h`、`docker system df` 与 `docker stats --no-stream`,比等磁盘满了再处理轻松得多。清理前先分清哪些是可重建缓存,哪些是配置或其他业务数据。

如果以后需要浏览器路由,再按官方 Compose 示例增加 Browserless 或选择带 Chromium 的镜像,同时观察内存、超时与网络。基础路由已经够用,就没有必要让浏览器进程一直占着资源。

自建 RSSHub 最值得保留的成果,是一个稳定的订阅域名和一份自己看得懂的配置。服务器将来可以换,阅读器也可以换;入口和维护记录在手里,迁移就不必从头再来。

RSSHub 迁移时保存哪些配置

保存 Compose、.env、路由清单、访问密钥,以及路由实际使用的 Cookie、令牌和代理配置。Redis 通常用于缓存,迁移后重点检查目标路由能否重新生成;自己的阅读器数据另外备份。

更新镜像后逐条检查常用路由

记录当前镜像版本,阅读变更说明后更新。先检查带密钥的健康接口,再访问常用路由,确认状态、Feed 内容和新条目;需要浏览器的路由另检查浏览器服务。

保留原域名与订阅地址

新实例恢复时沿用访问密钥及路由,先暂停旧实例相关操作,再切换域名解析。旧路径、key 或 code 变化会影响阅读器;切换后从阅读器实际使用的网络检查。