信息流被算法投喂久了,人容易产生一种错觉:自己看到的就是全世界。我做了五六年内容聚合相关的折腾,从最早的本地RSS阅读器到后来的自建聚合服务,中间踩过的坑能写满一个笔记本。RSSHub这个开源项目算是让我重新找回"主动订阅"快感的关键工具——它把那些不提供RSS输出的网站,硬生生转换成了标准订阅源,微博、知乎、B站、播客、GitHub动态,几乎你能想到的内容平台都有对应的路由。但问题来了,官方公共实例经常因为访问量过大而限流甚至挂掉,自己买服务器跑又得考虑运维成本。Vercel的免费额度恰好卡在一个很舒服的位置:个人使用完全够,部署流程也足够傻瓜化。这篇内容就是把我反复部署、迁移、调优过程中攒下来的经验一次性摊开,从零开始讲清楚怎么在Vercel上跑起一个属于自己的RSSHub实例,包括那些官方文档里不会写的坑和绕路方案。适合有一定动手能力、想摆脱算法推荐、愿意花半小时换长期清爽阅读体验的朋友。
1. 为什么自建RSSHub值得折腾这一趟
1.1 公共实例的限流逻辑与真实体验
很多人第一次接触RSSHub都是直接用官方公共实例,复制一个路由地址往阅读器里一贴,能用就完事了。刚开始确实爽,但用不了多久就会发现某些路由开始报错,返回429或者直接超时。这不是你的网络问题,而是公共实例的限流策略在起作用。官方实例面向全球用户,每个路由都有频率限制,热门路由比如微博热搜、知乎热榜这类,几乎全天处于被大量请求轰炸的状态。你偶尔刷一次可能没事,但如果阅读器设置了每小时抓取一次,很快就会触发限制。
我自己的使用习惯是订阅了大概四十多个源,其中有一半是冷门博客和播客,这些倒还好。真正麻烦的是那几个高频更新的平台路由,公共实例上基本处于"能用但不好用"的状态。更别提有时候官方实例会因为维护或者突发流量直接整体不可用,你的阅读器里所有依赖它的订阅源全部变灰,那种感觉就像早上起来发现报纸全被收走了一样。
自建实例的核心价值就在这里:你拥有独立的请求配额,不受其他人影响。Vercel的免费套餐给每个部署实例分配了独立的函数调用额度,个人日常使用——哪怕你订阅上百个源、每小时刷新一次——也远远碰不到上限。这个账很好算:假设你订阅50个源,每小时抓取一次,一天就是1200次请求,一个月三万六千次左右。Vercel免费版每月给100GB-小时的执行时间和100万次函数调用,RSSHub单次请求的执行时间通常在几百毫秒级别,算下来完全在安全范围内。
1.2 Vercel免费额度到底够不够用
这里得把账算细一点,因为很多人对"免费"两个字既心动又怀疑。Vercel的Hobby计划(也就是免费版)包含的内容对个人RSSHub部署来说相当宽裕:
| 资源项 | 免费额度 | RSSHub实际消耗估算 |
|---|---|---|
| 函数调用次数 | 100万次/月 | 50源×每小时1次≈3.6万次/月 |
| 执行时间 | 100GB-小时/月 | 单次约0.3秒×3.6万次≈3GB-小时 |
| 带宽 | 100GB/月 | 纯文本RSS输出,几乎可忽略 |
| 部署次数 | 100次/天 | 日常更新远低于此 |
从表格能看出来,个人使用场景下免费额度有巨大的冗余空间。真正需要注意的是两个隐性限制:一是函数冷启动问题,免费版没有预留实例,长时间无请求后第一次访问会慢几秒;二是单次函数执行有10秒的超时上限,某些需要抓取大量数据的路由可能会超时。这两个问题后面会专门讲应对方案。
还有一个容易被忽略的点:Vercel的免费版要求项目是公开仓库或者通过CLI部署,如果你打算用GitHub集成的方式自动部署,仓库可以是私有的,但Vercel那边读取代码的权限配置要弄对。这个细节在部署环节会详细展开。
1.3 自建之后能解锁哪些公共实例没有的玩法
自建实例最直接的收益是稳定性,但用久了你会发现还有不少附加价值。首先是自定义路由参数的自由度,公共实例上某些路由的默认参数是固定的,比如抓取条数、是否包含某些字段,自建之后你可以直接在URL里带上完整参数,阅读器里存下来的地址就是你想要的精确输出。
其次是私有路由的可能性。RSSHub支持通过环境变量配置一些需要认证的路由,比如某些需要登录态才能访问的内容源。公共实例上这类路由要么不可用,要么需要你把自己的凭证交出去,显然不现实。自建实例里你可以安全地配置自己的访问凭证,让那些原本抓不到的内容也能进入订阅列表。
再就是缓存策略的调整。公共实例为了照顾所有人,缓存时间设置得比较保守,有些路由缓存长达十几分钟。自建之后你可以通过环境变量调整缓存时长,对于更新频繁的源可以缩短缓存,对于冷门源可以拉长缓存减少请求次数。这种精细控制是公共实例给不了的。
2. 部署前的准备工作与关键决策
2.1 账号注册与仓库 Fork 的正确姿势
动手之前先把两样东西准备好:一个代码托管平台的账号和一个Vercel账号。Vercel支持直接用代码托管平台的账号登录,这一步没什么难度,但有个细节要注意——登录时选择的账号类型会影响后续的仓库访问权限。如果你用的是个人账号,Fork下来的仓库会挂在你的个人空间下,Vercel能正常读取;如果你用的是组织账号,需要确保Vercel有该组织的访问授权,否则部署时会报"仓库不存在"的错误。
Fork RSSHub主仓库的时候,建议保持默认的仓库名,不要改。原因是Vercel在识别项目类型时会参考仓库结构,改名虽然不影响功能,但后续如果跟着某些教程操作,路径对不上容易犯迷糊。Fork完成之后,你得到的是主分支的完整代码,这个分支会随着上游更新而落后,后面会讲怎么同步。
提示:Fork的时候留意一下仓库的默认分支名,有些项目主分支叫main,有些叫master,Vercel部署时如果分支名填错会直接失败。RSSHub目前的主分支是master,但保险起见Fork完去仓库设置里确认一眼。
2.2 环境变量里那些必须提前想清楚的事
RSSHub的配置几乎全部通过环境变量完成,部署之前在Vercel的项目设置里把这些变量填好,能省掉后面反复重新部署的麻烦。核心变量有这么几个:
NODE_ENV:设为production,这个不设的话某些路由的行为会不一样。CACHE_TYPE:缓存类型,Vercel环境建议设为memory,因为免费版没有持久化存储,用Redis之类的反而增加复杂度。CACHE_EXPIRE:缓存过期时间,单位秒,默认是300。个人使用可以设小一点,比如120,让更新更及时。REQUEST_TIMEOUT:单次请求超时时间,默认是3000毫秒。某些慢速源可以适当调大,但别超过8000,否则会撞上Vercel的10秒函数上限。ACCESS_KEY:访问密钥,强烈建议设置。不设的话你的实例就是公开的,任何人拿到地址都能用,虽然概率低,但万一被扫到大量请求,你的免费额度会被迅速消耗。
ACCESS_KEY这个变量值得多说两句。设置之后,所有请求都需要在URL里带上?key=你的密钥参数才能正常返回。这个机制不是加密,只是简单的访问控制,但对于防止实例被滥用已经足够。密钥生成用任意随机字符串工具都行,长度建议32位以上,混合大小写和数字。
2.3 部署方式的选择:一键部署还是手动导入
Vercel提供了两种主要部署路径:一种是通过项目主页的Deploy按钮一键部署,另一种是手动在Vercel控制台里导入仓库。一键部署看起来省事,但它会自动创建一个新仓库的副本,后续上游更新同步起来比较麻烦。手动导入则是直接关联你Fork的那个仓库,上游有更新时你只需要在代码托管平台同步一下Fork,Vercel会自动触发重新部署。
我两种方式都试过,长期用下来推荐手动导入。具体操作是在Vercel控制台点"Add New Project",然后选择"Import Git Repository",找到你Fork的RSSHub仓库。导入过程中Vercel会自动识别项目类型为Node.js,Framework Preset保持默认的"Other"即可,Build Command和Output Directory都不用改,RSSHub的构建脚本已经配好了。
有一个容易卡住的地方:如果你的仓库是私有的,Vercel需要安装一个Git App来获得读取权限。首次导入私有仓库时页面会提示你安装,跟着引导走就行,安装时可以选择只授权给特定仓库,不必给全账号权限。
3. 部署过程中的实操细节与参数调优
3.1 构建配置里那几个不能动的默认值
导入仓库之后会进入配置页面,这里有几个字段需要确认。Root Directory保持默认的./,不要指向子目录。Build Command留空,Vercel会自动读取项目里的vercel.json或者package.json里的构建脚本。Output Directory也留空,RSSHub是服务端渲染的Node应用,不需要静态输出目录。
真正需要留意的是Environment Variables区域,把上一节准备好的变量逐个填进去。填的时候注意变量名的大小写,Vercel对环境变量名是大小写敏感的,CACHE_TYPE和cache_type会被当成两个不同的变量。填完之后点Deploy,构建过程大概持续两三分钟,日志里会显示依赖安装和构建的各个阶段。
构建成功的标志是日志末尾出现"Build Completed"并且分配了一个*.vercel.app的域名。这时候别急着高兴,先做一次冒烟测试:在浏览器里访问https://你的域名/,如果返回一个RSSHub的欢迎页面或者JSON格式的说明,说明基础部署成功了。如果返回500错误,大概率是环境变量没配对,去Vercel的Functions日志里看具体报错。
3.2 首次访问的冷启动延迟与预热技巧
免费版Vercel的函数是冷启动模式,也就是说如果一段时间没有请求,函数实例会被回收,下次请求时需要重新拉起。这个冷启动时间实测在2到5秒之间,取决于当时平台的整体负载。对于阅读器来说,这个延迟通常可以接受,因为阅读器抓取是后台行为,慢几秒用户感知不到。但如果你在浏览器里手动访问,第一次打开会明显感觉卡顿。
有个简单的预热技巧:在Vercel项目设置里配置一个Cron Job,定时访问一个轻量路由。免费版支持每天触发一次的Cron,虽然频率不高,但至少能保证每天有一次预热。更实际的做法是在你的阅读器里把抓取间隔设置得均匀一些,避免所有源集中在同一时刻请求,这样函数实例被回收的概率会降低。
注意:不要试图用外部监控服务高频ping你的实例来保活,免费版的调用额度虽然宽裕,但高频ping会白白消耗额度,而且Vercel对滥用行为有检测机制,得不偿失。
3.3 自定义域名绑定与HTTPS的自动处理
*.vercel.app这个默认域名在国内部分网络环境下访问不太稳定,绑定一个自己的域名会好很多。Vercel支持免费绑定自定义域名,并且自动签发HTTPS证书,整个过程不需要手动配置证书。
操作路径是在项目设置里找到"Domains",输入你的域名,Vercel会给出一个CNAME记录值,去你的域名解析服务商那里添加这条记录。解析生效后Vercel会自动完成证书签发,通常几分钟内就能用HTTPS访问。这里有个细节:如果你用的是根域名(比如example.com而不是rss.example.com),CNAME记录可能不被某些解析服务商支持,这时候要么改用子域名,要么用A记录指向Vercel提供的IP,但A记录方式Vercel不保证IP长期不变,所以子域名是更稳妥的选择。
绑定域名之后记得把ACCESS_KEY的用法也同步更新,阅读器里的订阅地址要从*.vercel.app换成你的自定义域名,否则密钥参数对不上会返回403。
4. 部署之后:订阅源管理与日常维护
4.1 路由地址的拼接规则与参数调试
RSSHub的路由结构是/路由路径/参数的形式,比如微博用户的时间线是/weibo/user/用户ID。自建实例的完整地址就是https://你的域名/weibo/user/用户ID?key=你的密钥。拼接的时候注意两点:一是密钥参数要放在最后,用?key=开头;二是如果路由本身已经带了查询参数,密钥要用&key=连接而不是?。
调试新路由的时候,建议先在浏览器里直接访问完整地址,看返回的XML内容是否符合预期。如果返回的是错误信息,根据错误码判断问题:404通常是路由路径写错了,403是密钥不对或者没带密钥,500是路由内部抓取失败(可能是目标网站改版或者反爬)。RSSHub的官方文档里有每个路由的参数说明,但文档更新有时滞后于代码,遇到文档和实际不符的情况,去仓库的对应路由源码里看参数定义是最准的。
4.2 阅读器端的配置要点与抓取频率建议
把自建实例的地址填进阅读器时,有几个设置项会影响使用体验。抓取间隔建议设置在30分钟到1小时之间,太频繁没必要而且浪费额度,太稀疏又失去了RSS即时性的优势。并发数设置成1或者2就行,RSSHub实例处理并发请求的能力有限,同时抓太多源容易触发超时。
如果你的阅读器支持自定义User-Agent,建议改成一个常见的浏览器标识。某些目标网站会对非浏览器UA的请求做额外限制,虽然RSSHub内部已经做了UA伪装,但阅读器到RSSHub这一层如果UA太奇怪,偶尔也会被Vercel的边缘网络拦截。这个不是普遍问题,但遇到莫名其妙的403时可以往这个方向排查。
4.3 上游代码更新后的同步与重新部署
RSSHub的路由是社区维护的,目标网站改版后对应的路由会失效,维护者修复后会合并到主分支。你Fork的仓库不会自动更新,需要手动同步。在代码托管平台的仓库页面点"Sync fork"按钮,选择更新主分支,然后Vercel会检测到仓库变化自动触发重新部署。整个过程不需要你改任何代码。
同步频率建议一个月一次,或者当你发现某个常用路由突然失效时去同步一次。同步之前可以先看看上游的提交记录,如果最近有大量路由修复的提交,那值得同步;如果只是文档更新或者无关紧要的改动,可以跳过。同步之后留意Vercel的部署日志,如果构建失败,大概率是上游引入了新的依赖或者改了构建脚本,这时候去项目的Issue区看看有没有人遇到同样的问题。
5. 那些官方文档不会告诉你的坑
5.1 函数超时导致的间歇性失败
Vercel免费版的函数执行上限是10秒,这个限制在RSSHub的某些重路由上会被触发。典型场景是抓取一个需要翻页或者需要多次请求才能组装完整内容的源,单次函数执行时间很容易超过10秒。表现是阅读器里这个源时好时坏,有时候能抓到,有时候报超时。
应对思路有两个:一是换用更轻量的路由变体,很多路由提供了?limit=参数可以限制抓取条数,条数少了执行时间自然短;二是接受这个限制,把这类源的抓取频率调低,减少触发超时的概率。彻底解决需要升级到付费版获得更长的执行时间,但对个人使用来说,前两个方案已经够用。
5.2 缓存策略与数据新鲜度的平衡
前面提到CACHE_EXPIRE设成120秒,但实际用下来发现这个值需要根据源的类型区别对待。新闻资讯类的源更新快,缓存短一点合理;但像播客、长文博客这类源,更新频率本来就低,缓存设短了纯属浪费请求。RSSHub支持在路由级别覆盖缓存设置,具体是在URL里加?cache=参数,但这个参数的生效依赖路由本身的实现,不是所有路由都支持。
更实际的做法是接受全局缓存设置,然后在阅读器端做区分:高频源设短抓取间隔,低频源设长间隔。这样即使RSSHub端有缓存,整体数据新鲜度也能满足需求。我自己的配置是全局缓存180秒,阅读器端新闻类源30分钟抓一次,博客类源2小时抓一次,用下来体验很平衡。
5.3 密钥泄露后的应急处理
ACCESS_KEY一旦泄露,最直接的后果是别人可以白嫖你的实例额度。虽然个人实例被盯上的概率不高,但如果你把带密钥的订阅地址分享到公开场合,被爬虫扫到的可能性是存在的。应急处理很简单:去Vercel项目设置里改掉ACCESS_KEY的值,重新部署,然后更新所有阅读器里的订阅地址。改密钥不会影响已有缓存,但会让所有旧地址立即失效。
预防措施是不要把带密钥的完整地址发到公开聊天群或者论坛里,分享的时候把key参数去掉。如果确实需要分享某个源给朋友,可以单独生成一个只读的分享链接,但RSSHub本身不支持多密钥分级,所以最稳妥的还是各用各的实例。
5.4 免费额度的监控与异常消耗排查
Vercel控制台的Usage页面能看到函数调用次数和执行时间的实时消耗。正常情况下个人使用的曲线是平缓的,如果某天发现调用次数突然飙升,大概率是某个源出了问题导致阅读器反复重试。排查方法是去Functions日志里按时间排序,看哪个路由的请求最密集,找到之后要么修路由参数,要么暂时禁用那个源。
还有一种异常消耗是阅读器的bug导致的,某些阅读器在抓取失败后会进入快速重试循环,几分钟内就能打掉几千次调用。遇到这种情况先把那个源在阅读器里禁用,观察消耗曲线是否恢复正常,确认是阅读器问题后换个阅读器或者等阅读器更新修复。
6. 从能用走向好用:进阶配置思路
6.1 多实例分流减轻单点压力
当你订阅的源越来越多,单个实例的请求压力会逐渐显现。一个可行的思路是部署两个Vercel项目,用不同的仓库分支或者不同的环境变量配置,然后把订阅源按类型分到两个实例上。比如一个实例专门跑高频的社交平台路由,另一个跑低频的博客和播客路由。这样单个实例的负载减半,冷启动概率降低,某个实例出问题时也不至于全军覆没。
两个实例的部署流程完全一样,只是Fork的时候可以Fork两份,或者用同一个仓库的不同分支。Vercel对同一账号下的多个项目分别计算免费额度,所以两个实例各自都有完整的免费配额,总容量翻倍。这个方案的成本是管理复杂度上升,订阅地址要分两套维护,适合订阅量确实很大的用户。
6.2 结合本地阅读器的离线缓存策略
RSSHub负责抓取和转换,阅读器负责展示和缓存,两者配合好了能实现接近离线阅读的体验。关键设置是阅读器的"保留已读文章"选项,开启之后即使RSSHub暂时不可用,你之前抓下来的内容还在本地,不会出现打开阅读器一片空白的情况。配合RSSHub的缓存机制,即使实例短暂挂掉,阅读器重试几次后也能拿到缓存内容。
这个策略对移动端阅读尤其有用,通勤路上网络不稳定的时候,本地缓存的内容能保证阅读连续性。设置上建议保留最近500到1000篇文章,太多了占空间,太少了不够看。
6.3 路由失效的自检清单与快速定位
某个源突然不更新了,排查顺序应该是这样的:先在浏览器里直接访问完整路由地址,看返回内容。如果返回正常XML但阅读器不更新,问题在阅读器端,检查抓取间隔和错误日志。如果返回错误,看错误码:403查密钥,404查路由路径,500查目标网站是否改版。确认是路由失效后,去RSSHub仓库的Issue区搜路由名,通常已经有人报告并附带了修复方案,等上游合并后同步Fork即可。
这套排查流程走下来,大部分问题能在五分钟内定位。真正需要耐心的是等上游修复,有些冷门路由的修复可能要等几周,这段时间可以先在阅读器里禁用该源,避免反复重试浪费额度。
6.4 长期维护的心态与节奏
自建服务这件事,最怕的是一开始热情高涨,用几个月后疏于维护,最后实例荒废。我的经验是把维护动作嵌入日常习惯:每月初花五分钟同步一次Fork,顺便看一眼Usage页面有没有异常;遇到某个源失效时顺手排查一下,能修就修,修不了就禁用;密钥每半年换一次,换的时候顺便清理一下不再看的源。这套节奏下来,维护成本几乎可以忽略,但实例的可用性能长期保持在较高水平。
说到底,自建RSSHub不是为了炫技,而是为了拿回信息获取的主动权。算法推荐有它的价值,但完全依赖推荐会让视野越来越窄。RSS这种"我选我订"的模式,配合自建实例的稳定输出,算是在信息过载时代给自己留的一块自留地。部署本身半小时能搞定,真正花时间的是后续根据自己的阅读习惯慢慢调优,这个过程本身也挺有意思的。