首页 / 资讯中心 / 文章详情

自建RSSHub完整部署指南:Docker Compose、Nginx反代与CORS配置

自建RSSHub完整部署指南:Docker Compose、Nginx反代与CORS配置 ★ FEATURED ARTICLE
我最早接触RSSHub是因为手上几个小站点都靠手工拼更新想要的内容分散在不同页面里汇总起来非常痛苦。后来决定把内容采集做成一套统一出口让RSSHub生成订阅后再交给各个端去消费于是才真正开始研究部署。整个过程折腾下来我最大的感受是把容器跑起来并不难难的是部署完成之后宝塔面板和1Panel两套环境里反向代理、HTTPS、跨域这些入口层的协作方式差别很大稍不留神就会栽在CORS这种小问题上。这篇文章就把我实际操作的完整过程从头到尾整理出来包含Compose配置、环境变量、跨域策略、Nginx配置、常见故障排查给正在自建的人一份可以直接照抄的参考。1. 为什么自建RSSHub场景与选型思考1.1 哪种情况真的需要自己建一套先说需求边界。RSSHub的核心作用是把那些没有RSS订阅入口的网页内容统一包装成标准RSS源。自建实例之后你相当于有了一个完全由自己控制的订阅生成中心不再依赖任何公共节点的稳定性。我见过最需要自建的是三类人。第一类是多端阅读用户手机阅读器、桌面客户端、网页版想共享同一份订阅数据公共实例很容易因为访问频繁被限流自定义源也可能因为某些路由不稳定而突然失效。第二类是做数据汇聚的开发者比如内部运营后台需要批量读取某些公开页面并自动入库这时候直接用公共接口既不稳定也不好控制缓存和频率。第三类是对隐私比较敏感的用户自建之后订阅行为只发生在自己的服务器上所有请求记录都由自己管理数据不会经过第三方服务收集。反过来说如果你只是给自己的Podcast或者某一个固定站点生成订阅公共实例完全够用没必要折腾服务器和面板。自建真正划算的场景是“长期、多源、要对外暴露接口给其他应用用”而不是冲动式地跟风部署。1.2 宝塔与1Panel按需求而不是按名气选很多人在选面板时会纠结我两个环境都实际操作过结论是没有谁全面碾压谁关键看你现有的服务器生态和操作习惯。我整理了一个比较主观但实用的对照表维度宝塔面板1Panel上手门槛老牌面板功能模块多适合熟悉传统Web运维的人更强调容器化概念上偏现代适合已经习惯用Docker管理服务的人Docker管理需要额外安装Docker管理器插件Compose功能入口相对收敛原生集成Docker与Compose容器、网络、编排都在一个地方反向代理网站模块点几下就能完成Nginx反代适合快速配置OpenResty定制能力强但写配置的位置需要找一下资源占用面板自身服务比较多内存占用稍高相对轻量整体更克制SSL证书站点绑定时可一键签发并自动续期证书管理独立模块操作也不复杂我个人建议的标准很简单如果你服务器上已经有一批站点由宝塔管理那直接在里面加一个容器服务成本最低不必为了RSSHub单独再装一套面板。如果你是新建的机器或者已经习惯用1Panel管理多个容器那就在1Panel里完成一切。需要注意两套面板的Web操作路径完全不同。宝塔倾向于用“网站-反向代理”的思维去理解入口1Panel更倾向于用“容器-编排-网络端口”的思维。同一个docker-compose文件在两边的入口和展示方式都不一样理解了这一点后面才不会被界面带偏。1.3 容器部署为什么是最省心的方式RSSHub的部署方式有好几种最传统的是在服务器上直接安装Node.js、克隆代码、安装依赖、然后用进程守护工具跑起来。这种方式能工作但问题很多RSSHub的依赖升级频率高Node版本一变整个环境就容易崩如果机器上还有其他Node服务依赖很容易互相干扰升级操作也要手动拉代码、装依赖繁琐不说还容易出问题。用Docker Compose是我目前最推荐的方式。镜像里已经把运行时和所有依赖都封装好了启动一个容器就等于起了一个隔离的服务以后升级只需要拉新镜像再重建容器一分钟不到就能完成环境变量在配置文件里集中管理换机器迁移时只要把compose文件带上整个服务就能原样跑起来。还有一个容易被忽略的点容器方式对面板操作者更友好。宝塔和1Panel都有容器管理界面日志、状态、资源占用都看得清清楚楚不用每次排查故障都去SSH里敲一堆命令。2. 部署前准备服务器、面板与端口规划2.1 配置要求与资源盘点先聊配置很多第一次自建的人会担心服务器带不动。RSSHub本身是一个Node.js应用进程占用内存一般在200到400MB之间具体看启用的路由和并发量。如果只是个人使用1核1G的机器能跑但比较勉强建议内存至少2GB起步这样即使后续加缓存和日志也有余量。存储方面镜像本身大约几百MB运行时的数据目录主要是日志和缓存文件所以硬盘剩余空间大于几个GB就很稳妥。系统方面我试过Debian和Ubuntu都没问题CentOS也支持面板安装时会自动处理环境依赖。如果你打算在外层再套一个Nginx反代那还需要预留一点CPU处理HTTPS加解密的开销这个在个人场景下几乎可以忽略。真正会拉高资源的是把RSSHub接口暴露给公网后被陌生人高频调用后面我会专门讲防护策略。2.2 宝塔面板下安装Docker并规划项目目录如果服务器已经装好宝塔面板第一步是到“软件商店”里找到Docker管理器并安装安装完成后确认Docker服务处于启动状态。宝塔的Docker管理器比较方便可以直接查看镜像列表、容器列表和日志也提供了编排Compose的入口但不同版本的界面差异较大如果你在界面上找不到Compose入口直接用SSH登录到服务器命令行操作更稳妥。在动手之前我建议先在服务器上规划好一个独立目录比如/opt/rsshub。把所有和RSSHub相关的文件都集中在一个目录里后续备份、迁移、排查都省事。目录建好之后后面所有的compose文件和容器数据都在这个目录下不要在服务器根目录随意散落文件这是我一直坚持的习惯。2.3 1Panel里的容器与防火墙设置1Panel是基于容器技术设计的面板安装完成后Docker环境已经就绪不需要额外装什么插件。你只需要关注两件事第一容器和编排功能在“容器”菜单里创建和查看都比较直观第二某服务不要直接暴露到公网时在“端口映射”上不要填写0.0.0.0只映射到127.0.0.1即可。还有一点容易被新手忽略云服务器的“安全组”和面板的“防火墙”是两个独立环节。面板里放行端口了不代表云控制台的安全组也放行了。我最早部署时就是因为只改了面板防火墙安全组没放开导致外部访问一直超时。所以只要涉及公网端口先到云服务商后台确认安全组规则再回到面板检查系统防火墙两级都放行才算真正通了。3. 核心部署RSSHub Compose 编排与启动校验3.1 一份可以直接用的docker-compose配置完整配置我贴在这里你可以直接创建docker-compose.yml文件然后根据自己需要微调services: rsshub: image: diygod/rsshub:latest container_name: rsshub restart: always environment: - NODE_ENVproduction - PORT1200 - CORS_ORIGIN* - CACHE_TYPEmemory - CACHE_EXPIRE3600 - TZAsia/Shanghai ports: - 127.0.0.1:1200:1200 volumes: - ./data:/app/data这里有一个关键经验端口映射我写的是127.0.0.1:1200:1200而不是常见教程里的1200:1200。两者的差别在于前者只让RSSHub监听在服务器本机的回环地址上外部网络无法直接访问1200端口只能通过服务器上的Nginx反代来访问后者则会把服务直接暴露到公网任何人都能扫到这个端口并尝试调用你的RSSHub。既然是自建服务就没有必要冒这个风险后面所有入口都走Nginx一个端口就好。如果你看到这里觉得Compose文件比较陌生可以这么理解services下面定义了一个叫rsshub的服务image指定运行镜像environment设置应用启动环境变量ports做端口映射volumes把容器里的数据目录映射到宿主机磁盘上。这套结构在宝塔和1Panel里都是通用的。3.2 环境变量怎么配才合理环境变量是RSSHub配置的核心我逐个说下实际用到的几个变量变量名作用我的建议NODE_ENV指定运行环境固定为production避免调试模式带来额外输出和性能损耗PORT应用监听端口保持1200不要随意改动如果需要可以通过端口映射调整外部端口CORS_ORIGIN允许跨域访问的来源如果是自用且要配合Nginx可以设为具体域名如果想让容器直接输出跨域头先设为*CACHE_TYPE缓存存储类型个人部署用memory即可并发高再加RedisCACHE_EXPIRE缓存保留时间默认单位是秒我习惯设3600内容更新不频繁时能明显降低源站压力TZ时区设为Asia/Shanghai日志时间显示才不别扭很多人在这个阶段会忽略CORS_ORIGIN等前端调用的时候才发现跨域被拦。这里先说清楚逻辑如果你打算在前端页面直接用JavaScript请求RSSHub接口浏览器会强制检查跨域头如果所有请求都从Nginx代理入口走而且Nginx本身会统一加跨域头那容器里的CORS_ORIGIN其实可以设成具体来源双保险。关于Redis个人使用的场景我一般不建议一开始就上。因为容器里已经默认支持内存缓存对绝大多数订阅需求已经够了。等到你发现订阅源特别多、内存缓存频繁挤占资源时再在compose文件里加一个Redis容器并把CACHE_TYPE改成redis把Redis的连接地址通过环境变量指向它这才是合理的演进路径。3.3 启动、日志验证与基础测试配置写好后启动动作在三类环境下的操作方式不同但本质是一样的。如果你习惯命令行直接SSH到服务器进入/opt/rsshub目录执行docker compose up -d如果用的是宝塔的Docker管理器找到Compose或编排入口选择这个目录并启动即可1Panel的容器编排界面也同样可以识别到compose文件并一键拉起。启动完成之后用docker ps能看见一个叫rsshub的容器处于运行状态。这时候不要急着配域名先用本机地址验证一下服务本身curl http://127.0.0.1:1200如果返回了页面内容说明容器已经正常工作。然后再看日志确认没有明显的报错docker logs --tail 50 rsshub日志能看到路由注册记录和缓存初始化情况。只要没有Error级别的频繁输出基本就可以进入下一步的入口配置了。我在这里遇到过的第一个问题就是忘记加127.0.0.1绑定导致容器端口被公网直接扫描后面通过慢慢优化的日志才发现的。所以端口绑定这一课建议一开始就做好。4. 跨域服务解析CORS 和反向代理怎么配合4.1 为什么curl正常但浏览器总报错跨域问题是自建RSSHub之后几乎必然遇到的一道坎。很多人会遇到一个很诡异的场景在服务器上用curl请求http://127.0.0.1:1200一切正常返回数据和响应头都对但一放到前端页面里用Ajax调用浏览器就报错说请求被CORS策略拦截。这个问题的根源在于浏览器强制执行同源策略不会让一个域名下的页面随意读取另一个域名接口的数据而curl没有这种限制。这里可以打一个比方浏览器和服务器之间隔着一个严格的保安服务器已经让你进了但保安要看你的“门牌号”是不是属于允许列表。如果你的前端页面在a.example.com接口地址在b.example.com二者协议、域名或端口任意一项不一致请求就被归为跨域。除非接口返回了Access-Control-Allow-Origin响应头保安才会放行。所以排查跨域问题永远要先确认两件事第一接口是否真的返回了正确的CORS响应头第二OPTIONS预检请求是否得到正确处理。4.2 容器自带跨域 vs Nginx统一跨域解决跨域有两种思路。第一种是让RSSHub容器自己输出跨域头也就是把环境变量CORS_ORIGIN设置为*这是最简单的方案适合只想快速跑通、不做精细控制的情况。但它的缺点也很明显要么全都放行要么只能配一个固定来源无法做到同时允许多个信任域名的白名单效果。第二种思路是把跨域控制统一放到Nginx反向代理这一层。这么做的好处非常实在RSSHub本身不需要知道谁是前端Nginx对外统一管理跨域策略后端容器保持干净如果以后要调整允许的来源只改Nginx配置就行不用动容器而且能在代理层顺便处理HTTPS、限流、日志等一堆事情。我的实际建议是走第二种思路。虽然多写几行配置但入口和服务的职责被分开了后续你在这个Nginx后面再挂其他RSS服务或者要限制某些路径的访问都会轻松很多。4.3 宝塔Nginx跨域配置实例在宝塔面板中当你要把某个已有站点作为RSSHub的入口时通常不需要去改复杂的Nginx全局配置。你在网站设置里找到“反向代理”把代理目标地址填成http://127.0.0.1:1200保存后再去修改该站点的Nginx配置文件在对应的location /块里加入以下内容location / { proxy_pass http://127.0.0.1:1200; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods GET, POST, OPTIONS, HEAD always; add_header Access-Control-Allow-Headers Origin, Authorization, Content-Type, X-Requested-With always; add_header Access-Control-Expose-Headers Content-Length always; if ($request_method OPTIONS) { return 204; } }这里最关键的细节是add_header后面的always参数。默认情况下Nginx只有在返回200、201、302这些正常状态码时才会带上add_header声明的响应头如果请求返回了403、502之类的结果跨域头就会被丢掉浏览器照样拦截。加上always之后无论最终状态码是什么响应头都会带上这能避免很多莫名其妙的CORS报错。预检请求的处理也值得解释。浏览器在发起复杂跨域请求之前会先发一个OPTIONS请求试探服务器允不允许。这个试探请求不希望服务器真的去执行业务逻辑只要返回204并在响应头里带上允许的源、方法、请求头就够了。上面的配置里if ($request_method OPTIONS) { return 204; }干的就是这件事。4.4 1Panel反代中的跨域配置位置在1Panel里配置反代逻辑和宝塔类似但入口不同。你需要先创建一个“反向代理”类型的网站绑定一个域名然后目标地址填http://127.0.0.1:1200。建立完成之后到该网站的高级设置里找Nginx配置文件找到对应的location /代码块再粘贴刚才那段跨域配置。有些习惯用1Panel输入Nginx配置的人会问为什么不用全局配置我用下来的体会是尽量别把跨域规则写在全局server或http层因为你以后可能在同一台服务器上部署多个站点全局放开跨域意味着所有网站都不设防容易产生意料之外的接口泄漏问题。把跨域规则限定在某一个站点的location块里控制面更小也符合最小权限原则。另外在1Panel里填反代目标地址时我建议一定写127.0.0.1:1200而不是公网IP。一方面减少请求绕一圈网络的开销另一方面也避免云安全组规则误伤内部请求。这个习惯在宝塔里同样适用。5. 域名、HTTPS、访问安全一起安排5.1 绑定域名并在面板里签发SSLRSSHub容器本身只负责生成RSS真正的对外入口是Nginx。给入口绑定域名并上HTTPS不仅影响浏览器地址栏的小锁标识还会直接影响跨域策略的稳定性。如果一个接口在HTTP和HTTPS之间来回切换前端请求会频繁出现混合内容被拦截的报错所以域名一旦确定协议就要统一。在宝塔面板中你需要在“网站”列表找到刚才设置反代的站点确认域名绑定无误然后在“SSL”面板中开启自动签发功能让它自动申请证书并续期。在1Panel中证书管理是独立的菜单你需要先创建一个证书再把它关联到对应的网站上。两套面板的自动化程度都很高只要域名解析已经生效证书一般几分钟内就能签发完成。我的建议是先不用HTTPS直接用HTTP验证反代链路是否通畅等接口确实能返回数据了再去签发SSL。否则一旦证书申请失败或者续期配置有问题很难分清是证书的问题还是反代的问题。5.2 不要漏掉X-Forwarded-Proto反向代理还有一个容易被忽略的细节当RSSHub跑在Nginx后面时Node.js应用接收到的请求是从Nginx发起的本地HTTP请求它无法直接知道外部用户实际是用HTTP还是HTTPS访问。如果应用内部需要生成回调地址或者拼接链接就会默认用HTTP最终产物里就会出现http://的混合内容浏览器看到后直接拦截。解决方法是把原始请求的协议传递给后端即在Nginx配置里加上proxy_set_header X-Forwarded-Proto $scheme;。这样一来RSSHub才能正确识别外部请求的真实协议生成的所有链接都会保持HTTPS。这也是很多自建站部署完成后发现页面加载正常但某些链接点过去却变成HTTP然后被浏览器拦下来的原因之一。5.3 多前端共用一个RSSHub时的跨域策略很多场景下不是只有一个前端在消费RSSHub。比如你有两个子站一个用React做页面一个用Vue做后台它们都需要通过浏览器直接请求同一个RSSHub接口。如果各自设置不同域名作为允许来源就会出现一种情况A站正常B站报跨域错误于是你同时修改RSSHub环境变量和Nginx配置很容易手忙脚乱。我推荐的方案是把对外访问统一收敛到一个专用子域名上比如rss.yourdomain.com把这个域名作为所有前端统一调用的地址。然后在Nginx上为这个子域名单独维护一个跨域白名单策略需要增加新的来源时只改一处配置。这样做看起来多了一个子域名实际上把所有入口管理集中到了一个地方后续调试成本会低很多。5.4 限流、认证与防滥用自建RSSHub一旦暴露到公网很容易被陌生人扫到。我见过有人把RSSHub部署好之后一晚上CPU被打满原因很简单有第三方脚本在批量请求各类路由频繁触发页面抓取。所以只要服务要对外提供服务防滥用是第一优先级。先做基础认证。如果调用方都是你自己的系统和少数可信端可以在Nginx里给对应路径加上Basic Auth或者在RSSHub环境变量的基础上配合HTTP基础认证把访问权限锁住。如果调用方是多个前端那么至少应该把CORS_ORIGIN设置成具体的来源列表而不是用*。再做限流。在Nginx的location块里可以配置limit_req控制每个IP的每秒请求次数。下面是常用的限流写法limit_req_zone $binary_remote_addr zonersshub:10m rate2r/s; server { ... location / { limit_req zonersshub burst5 nodelay; proxy_pass http://127.0.0.1:1200; ... } }rate2r/s表示平均每秒最多处理2次请求burst5表示允许突发5个请求排队。个人自建的场景下这个量完全够用又能有效挡掉大部分脚本扫描。别觉得限流麻烦等到服务器带宽和CPU被打满再回头补成本会翻好几倍。6. 常见问题与排查实录6.1 容器启动即退出怎么办我部署过程中遇到最多的问题就是容器启动后立即退出。这种情况基本跑不掉第一件事永远是看日志而不是反复去点重启。用docker logs rsshub能看到最后一段输出大多数原因都会直接写在日志里。最常见的原因是端口被占用。比如服务器上已经有一个进程监听了1200端口这时候要么改compose里的端口映射要么先处理掉冲突进程。另一个常见原因是内存不足尤其1G内存的小机器RSSHub在启动阶段会申请较多内存容器直接被系统杀掉。解决方法是适当减少同时启用的路由数量或者给容器加内存限制让它不要和其他服务抢占资源。如果日志里出现权限相关的报错还要检查挂载目录。compose里映射的./data目录如果宿主机的权限不对容器写不进去数据也会退出。遇到这种问题直接给目录设置一个合理的权限或者手动创建目录并授权容器就能正常跑起来。6.2 浏览器预检请求失败的完整排查顺序CORS问题是我被问到最多的问题其实排查顺序完全可以固定下来按步骤走基本都能解决。第一步用curl模拟请求并查看响应头确认Access-Control-Allow-Origin是否出现。第二步检查请求是否触发了预检也就是浏览器是否先发OPTIONS请求这可以看Nginx访问日志里有没有OPTIONS记录。第三步确认OPTIONS请求是否正常返回了204并且响应头里带了允许的方法和请求头。第四步检查Nginx配置里的add_header是否加了always参数。容易漏的是自定义请求头。如果你的前端请求里带了Authorization或者自定义的头那么Nginx配置里的Access-Control-Allow-Headers必须包含这个头否则预检请求在“允许请求头”这一步就直接被拒。我看到很多人的配置只写了Content-Type一加认证就报跨域所以建议一开始就写全。还有一个细节如果你同时配置了RSSHub容器的CORS_ORIGIN和Nginx的跨域头最终响应里可能会被加两次跨域头。浏览器对重复头处理很严格某些情况下会直接失败。解决方案是二选一我建议保留Nginx层的控制把容器里的CORS_ORIGIN设成具体来源即可。6.3 内存与CPU占用异常的优化手段如果你发现RSSHub启动后内存一直在涨或者CPU时不时飙高先不要急着加内存先看看缓存配置和路由使用情况。RSSHub的路由请求是实时抓取目标页面再生成RSS的如果某些路由被高频调用CPU自然会被拉升。有一个很有效的做法是加大缓存时间把CACHE_EXPIRE从3600改成更大的值内容更新不频繁的源可以明显减少重复抓取。如果内存压力始终很大可以给容器设置内存上限。在compose文件中加入如下配置services: rsshub: ... mem_limit: 512m这个配置表示容器最多使用512MB内存超过之后会被限制。个人使用场景下512MB通常已经够用。不过要注意如果订阅源非常多或者并发请求很大内存限制会带来访问变慢这时候反而要提升配置而不是继续压着运行。日志膨胀也是容易被忽视的问题。Docker默认的日志驱动会把容器内标准输出完整保留时间长了会吃掉不少磁盘。可以在compose里增加日志轮转配置限制日志文件的数量和大小比如logging: driver: json-file options: max-size: 10m max-file: 3这样单份日志最大10MB只保留3份磁盘压力小很多。6.4 重启与升级时的几个习惯服务器重启后RSSHub能不能自动恢复取决于compose文件里有没有restart: always。加上这一行后只要Docker服务本身启动容器就会自动拉起。宝塔面板和1Panel一般也会在系统启动时自动启动Docker服务两个条件都满足服务器重启后就不需要手动去点启动。升级RSSHub的时候不建议直接停掉容器再拉镜像那样容易忘记重新创建容器。更稳的做法是进入compose文件所在目录执行docker compose pull拉取最新镜像再执行docker compose up -d --force-recreate重建容器。这个过程中容器会短暂停止但升级结束后配置和数据都保留着因为数据卷没有变。如果某一次升级后出现路由异常先不要急着回滚镜像先看日志里有没有红字报错。很多时候是依赖更新导致某个路由暂时不可用过几天项目修复后又恢复正常。经常备份compose文件和本地目录也是一种好习惯每次改动后都复制一份带日期的备份出了问题能快速回到稳定版本。故障现象可能原因处理思路容器启动即退出端口占用、内存不足、数据目录权限异常先看docker logs再逐一排查端口、内存和挂载目录浏览器报CORS错误响应头缺失、OPTIONS未处理、重复跨域头按固定顺序检查响应头、预检和Nginx配置前端页面有HTTP混合内容没有转发X-Forwarded-Proto在Nginx配置中加入协议转发头公网访问超时云安全组或系统防火墙未放行同时检查云控制台安全组和面板防火墙CPU和内存持续飙高路由被频繁调用、缓存过期时间太短调大缓存过期时间必要时配置限流和内存上限服务器重启后服务失效compose缺少restart配置加上restart: always并确认Docker开机自启最后说点个人体会。整套东西搭建完之后我最大的感受是RSSHub部署本身并不复杂真正的工程难点基本集中在入口这一层——Nginx反代、HTTPS、跨域、限流、访问控制。只要最开始把这些想清楚后面所有消费RSS数据的系统都会非常省心。我现在长期跑着一个专用子域名作为统一RSS出口Nginx层统一管理跨域和缓存策略基本没有再为CORS报错烦恼过。如果你也准备自建我建议第一次就按这个结构走Compose部署RSSHub、面板做反代、绑定HTTPS、Nginx统一跨域、最后补上访问控制五步一次到位后面收益远超前期投入。
阅读完成 · 觉得有帮助?
咨询建站