ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

自建FreshRSS:用Docker轻松部署私有RSS阅读器,夺回信息流控制权

自建FreshRSS:用Docker轻松部署私有RSS阅读器,夺回信息流控制权 说实话我已经很久没有主动打开过资讯类App了。今年年初我把服务器上的FreshRSS重新部署了一遍从写docker-compose到服务跑起来只花了几分钟然后花了一个晚上把所有还在坚持输出RSS的博客、周刊、项目更新全部收进了同一个阅读列表。每天早上打开FreshRSS按自己的节奏把未读读完那种“内容由我决定”的感觉比刷算法的信息流踏实太多了。这篇文章就把这套FreshRSS部署方案完整拆开来讲从选型理由、环境准备、一键部署、反向代理到客户端配置和常见问题排查尽量做到照着抄就能用。想重新掌控信息流、不想再被推荐算法牵着走的读者应该能从里面拿到不少有用的东西。1. 为什么是FreshRSS自建RSS的方案选型思路1.1 从算法推荐里抽身把信息选择权拿回来先说一个大家都能感受到的问题现在的资讯类App本质上不是给你“看内容”的而是给你“看流量”的。它会根据你的点击、停留时长、购买记录不断调整推送策略把你留在信息流里越久越好。于是你刷到的内容越来越像观点越来越重复标题越来越夸张真正想看的深度内容反而容易被淹没。这种感觉持续久了会有一种“看了很多但什么都没记住”的疲惫感。RSS这种老协议恰好是另一个逻辑它不追踪你不猜你喜欢什么你订阅什么源就推送什么内容排序完全由你自己决定。没有推荐权重没有时间线算法没有乱七八糟的“猜你想看”。很多人觉得RSS已经过时了但实际上它只是被主流平台藏起来了。大量博客、开源项目、技术社区至今依然在输出RSS/Atom源反而是最稳定的信息渠道。选择“自建”而不是注册某个在线RSS服务的理由也很直接曾经最大的在线RSS阅读器Google Reader说关就关让无数用户不得不迁移到其他平台之后不少RSS服务也经历了收费、被收购、数据丢失等波折。自己部署一套FreshRSS数据文件在自己服务器上订阅源在自己手里不用看服务商脸色也不会被突然通知“服务将于下月停止”。隐私方面也更好没有中间商读你的阅读习惯FreshRSS甚至可以完全匿名使用只要你自己不登录。1.2 FreshRSS 与 Tiny Tiny RSS、Miniflux 的横向对比自托管RSS阅读器里大家提得最多的三个方案是FreshRSS、Tiny Tiny RSSTTRSS和Miniflux。我在选型时把三者都跑过一遍这里直接给一个对比表方案技术栈界面风格多用户API兼容资源占用扩展能力FreshRSSPHP传统Web界面配置项丰富支持Google Reader API Fever API中等插件机制完善扩展多Tiny Tiny RSSPHP偏Geek可配合主题插件支持TTRSS自有API中等偏高插件多但配置略复杂MinifluxGo极简无JavaScript负担单用户Google Reader API极低扩展少胜在轻量我最终选择FreshRSS核心原因是它的综合成熟度。首先是官方Docker镜像维护得非常好部署基本不需要手动装PHP环境其次是API兼容Google Reader协议这意味着手机端可以直接用Reeder、FeedMe、Read You等热门客户端连接不用被Web端绑定第三它支持多用户如果你家里有人也想摆脱推荐流开个子账号就能共用一套服务第四FreshRSS的插件系统很丰富官方扩展仓库里能下载到不少有意义的功能比如把文章自动推送到通知渠道、按规则过滤垃圾内容等。Tiny Tiny RSS同样很优秀但它更适合喜欢深度定制、愿意折腾主题和插件的用户。如果你只想安安静静读个RSSTTRSS的初始配置成本反而有点高。Miniflux我承认它轻快得惊人非常适合资源紧张的小机器但它只支持单用户而且没有完整的插件体系。对于大多数人来说FreshRSS是那个“装上就能用、以后想折腾也有空间”的平衡点。2. 部署前要准备的东西服务器、Docker与域名2.1 服务器配置怎么选域名到底要不要FreshRSS本身非常轻量一个订阅源几百到上千条文章数据量也不会很大。以我实际使用经验看1核1G内存的云服务器完全够用如果只是自己一个人用512MB内存的机器也能跑只是后台刷新大量订阅源时CPU会短暂飙升。如果你打算同时部署RSSHub、WeWe RSS这类辅助服务建议直接上2G内存以上免得后面内存不够再迁移折腾起来反而浪费时间。操作系统建议直接用Ubuntu 22.04 LTS或Debian 12社区的教程和排错经验最多。这里多说一句我不太推荐在免费的虚拟主机或面板型主机上部署FreshRSS虽然也有办法跑但文件权限、计划任务、扩展安装这些环节很容易被平台限制卡住出了问题排查起来非常费劲。既然目标是“自建”还是建议找一台能完整掌控的云服务器。域名这块我的建议是如果你只是短期内自己测试直接用IP加端口访问也行如果打算长期使用尤其是要用手机客户端通过API同步阅读那最好准备一个域名并配置HTTPS。原因有两个一是FreshRSS的Google Reader API接口涉及账号密码明文HTTP传输风险太高二是不少客户端在没有HTTPS的地址下会拒绝连接。域名不用太贵注册一个普通的就行反正只需要解析一个二级域名给FreshRSS用比如freshrss.example.com。2.2 安装Docker与Docker Compose把基础环境一次弄好FreshRSS官方提供了非常成熟的Docker镜像所有PHP扩展、Apache和运行环境都已经打包好了所以部署FreshRSS最省心的方式就是用Docker Compose。先把服务器上的Docker环境装好Ubuntu下推荐直接安装官方源里的docker-ce和docker-compose-pluginsudo apt update sudo apt install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release echo $VERSION_CODENAME) stable | \ sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl enable --now docker docker --version docker compose version装完之后有两个细节容易踩坑一是老教程里还在用docker-compose带横杠命令那是Compose v1的旧命令新版Docker默认安装的是docker compose带空格插件用的时候注意区分二是如果你在云服务商那里拿到的机器有防火墙或安全组规则记得放行后面要用的端口不然程序跑起来但你从浏览器访问不通会误以为是部署失败。Docker Hub镜像拉取速度在不同地区差异很大如果拉取FreshRSS镜像特别慢可以按自己所在地区的情况给Docker配置镜像加速器修改/etc/docker/daemon.json后重启Docker即可。这一步属于常规网络优化不在本文展开遇到问题的人应该都知道怎么做。3. FreshRSS一键部署实操完整动手过程3.1 编写docker-compose.yml真正的一分钟跑起来装好Docker之后在服务器上找一个干净目录比如/opt/freshrss创建一个docker-compose.yml。下面是我实际在用的配置去掉注释后非常简洁services: freshrss: image: freshrss/freshrss:latest container_name: freshrss restart: unless-stopped ports: - 8080:80 environment: TZ: Asia/Shanghai CRON_MIN: */15 * * * * FRESHRSS_USER: admin FRESHRSS_PASSWORD: 换成你自己的强密码 volumes: - ./data:/var/www/FreshRSS/data - ./extensions:/var/www/FreshRSS/extensions然后执行cd /opt/freshrss docker compose up -d docker compose logs -f freshrss严格来说“一分钟”这个说法没有算上镜像下载的时间首次拉取镜像要看网络情况。但从镜像拉完、执行docker compose up -d到FreshRSS容器启动完成一分钟内肯定够。如果一切正常日志里会出现Apache启动成功的提示这时打开浏览器访问http://服务器IP:8080就能看到安装界面。这套配置里有几个要解释的地方。TZ: Asia/Shanghai是时区设置不设的话服务器上的时间默认是UTC会导致文章“更新时间”和你的直觉差8个小时。CRON_MIN是FreshRSS容器内部的计划任务表达式我设的是每15分钟刷新一次订阅源这个值可以根据你的订阅源数量调整。FRESHRSS_USER和FRESHRSS_PASSWORD是预置管理员账号的环境变量官方镜像的启动脚本会检测到用户未初始化并自动创建管理员省掉手动填表的步骤。3.2 Web初始化与首次登录十分钟内完成基础设置进入http://服务器IP:8080后页面会引导你完成FreshRSS的初始化。语言选择简体中文数据库选择SQLite然后填入管理员用户名和密码点击安装就行。这里的SQLite是FreshRSS默认的存储方案对单用户或几个人的小规模使用完全够用所有数据就是一个文件备份时直接把data目录里的数据库文件拷走即可。如果你预计以后会有几十个用户同时使用或者想追求更稳定的并发性能可以考虑在Compose里加一个MariaDB容器并把FreshRSS的数据库配置指向它。但从实际体验看个人和小家庭使用场景下SQLite的差别几乎感知不到我建议先SQLite跑起来真到规模变大了再迁移。迁移过程FreshRSS后台也有文档说明不用提前焦虑。初始化完成之后会自动跳转到登录页用刚才设置的管理员账号登录。登录后第一件事我建议去“订阅管理”页面手动添加一两个你常看的博客或技术社区RSS源测试一下抓取是否正常。确认没问题后再去“设置”页面检查一下刷新频率、文章保留天数和用户资料。这里有个小经验文章保留天数不用设成“永久”我一般设60天因为大部分RSS文章看完一遍就不会再翻了长期堆积反而占用数据库空间、拖慢刷新速度。3.3 加一层Nginx反向代理把HTTPS证书安排上为了让手机客户端能安全连接FreshRSS的API接口我强烈建议在FreshRSS前面加一层反向代理并配置HTTPS。这里有两种主流选择一种是Nginx配合certbot自动申请Lets Encrypt证书另一种是直接用CaddyCaddy会自动申请和续期证书配置量最少。如果你已经装了Nginx先修改FreshRSS的端口映射让它只监听本地回环地址避免直接暴露到公网ports: - 127.0.0.1:8080:80然后新建一个Nginx站点配置server { listen 80; server_name freshrss.example.com; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }执行sudo certbot --nginx -d freshrss.example.com申请证书certbot会自动改写Nginx配置并开启HTTPS。如果你不想装NginxCaddy会更省心在Caddyfile里写两行就行freshrss.example.com { reverse_proxy 127.0.0.1:8080 }然后systemctl reload caddyCaddy会自动完成HTTPS证书的申请和续期。这里有一个特别容易踩的坑只要用了反向代理就必须在FreshRSS的环境变量里设置TRUSTED_PROXY否则FreshRSS不知道客户端是通过HTTPS进来的页面里的资源链接可能还是http导致样式错乱甚至部分功能异常。以Nginx为例在docker-compose.yml的environment里加上TRUSTED_PROXY: 127.0.0.1然后重启容器。Caddy场景下通常也需要这一项具体值看你的反代部署方式。4. 让FreshRSS真正好用订阅、导入与客户端连接4.1 添加订阅源、批量OPML导入与分类管理FreshRSS的订阅管理做得比较直观登录后台后在“订阅管理”页面点击“添加订阅”把RSS或Atom链接粘进去选择放到哪个分类下就行。我习惯按“技术博客”“产品思考”“行业资讯”“开源项目”几个分类管理这样每天打开后可以按分类逐批阅读不会混在一起显得很乱。如果你之前用的阅读器支持导出OPML文件比如Feedly、Inoreader、甚至是旧版Google Reader备份可以直接在FreshRSS后台导入。OPML是一种标准化的订阅源清单格式导出的文件记录了所有你已经订阅的源地址和分类结构。导入后FreshRSS会自动重建分类省去一个个手动添加的麻烦。我当年从旧服务迁移过来三千多条订阅用OPML一次性搞定非常省事。还需要留意的是FreshRSS的“文章保留天数”和“刷新频率”是两套独立配置。前者控制数据库里最多保留多少天的文章后者决定后台多久去源站抓一次新内容。如果订阅源数量很多建议刷新频率不要低于15分钟一次如果只有几十个源每小时甚至每天刷新都行频率越高对源站压力越大也可能被部分网站限制访问。4.2 手机端用Reeder、FeedMe或Read You连接FreshRSSFreshRSS支持Google Reader API和Fever API这是它比很多同类自托管阅读器都强的地方因为这意味着移动端生态非常成熟。手机端的体验直接关系到你愿不愿意长期用RSS如果只能在电脑上读很难坚持下来。在FreshRSS后台的“设置”页面找到“认证”或“API”相关选项启用Google Reader API记下服务器地址格式https://freshrss.example.com/api/greader.php。然后用手机端RSS客户端配置账号以FeedMe为例选择Google Reader API填写服务器地址、用户名、密码就行。iOS上很受欢迎的Reeder 5也是类似配置方式选Google Reader API后填入同一个地址。我自己现在的组合是电脑上用FreshRSS网页端手机上用Read You配合服务端的“已读同步”功能在手机上读过的文章回到电脑上会自动标记为已读反之亦然。这个多端同步体验和商业阅读器差不多但它全部跑在自己的服务器上没有任何第三方介入。需要提醒的是API连接必须走HTTPS不然账号密码在公网明文传输风险太大了。4.3 过滤规则、标签和通知扩展把信息流整理成自己的FreshRSS默认的功能已经够用但它的魅力还在于可以扩展。后台自带的扩展列表里我最常用的是“过滤规则”和“Webhooks”相关扩展。过滤规则可以按关键词、来源、标题等维度对文章做自动标记、自动分组或者自动忽略。举一个实际例子我订阅了很多技术博客其中不少会发“促销”“抽奖”“广告”类内容这些不是我想看的。于是我在过滤规则里加了一条标题包含“促销”或“广告”的文章自动标记为已读。这样后台刷新后这些垃圾内容不会出现在未读列表里阅读效率直接提升。规则可以很灵活比如临时追某个热点话题可以建一条规则把所有包含该关键词的文章自动放在一个标签下方便集中阅读。如果你用Telegram、Slack、钉钉或类似的通知工具FreshRSS也有Webhooks扩展可以设置成“有新的未读文章时推送到某个渠道”。这个适合订阅量不大但需要实时跟踪的场景比如你订阅了某个项目的Release更新一旦有新版本发布立刻推送到自己的通知机器人比开邮件提醒清爽多了。5. 进阶玩法让信息源更全、更自动化5.1 用WeWe RSS把微信公众号文章接入FreshRSS很多朋友和我一样有一批重要的信息源只在微信公众号上更新但微信生态没有开放RSS这是自建RSS方案里最让人头疼的缺口之一。好在这几年开源社区已经有了比较成熟的解决方案比如WeWe RSS通过本地部署的方式把你关注到的公众号文章转换生成RSS订阅源再把这个源添加到FreshRSS里就能在同一个阅读器里读到公众号内容。WeWe RSS本身也是一个支持Docker部署的项目大致思路是部署好容器后按项目文档的说明完成配置它会在本地生成一个RSS地址把这个地址加到FreshRSS就行了。具体命令以项目GitHub仓库的最新说明为准因为我每次都是按官方文档来装的版本更新后参数可能有变化。这种工具的使用前提是遵守相应平台的规定只订阅你自己会正常查看的公开内容别拿来做爬虫批量采集也别突破任何平台限制。5.2 用RSSHub补齐没有RSS源的内容RSSHub是另一个我非常依赖的开源项目它做的事情本质上是一个“万物转RSS”的网关很多网站本身不提供RSS但RSSHub提供了几十类路由能把B站、微博、知乎、小红书、YouTube等平台的内容动态生成RSS。部署RSSHub同样用Docker跑起来后把对应平台内容的路由地址填进FreshRSS就可以订阅原本订阅不到的内容。RSSHub的部署很简单官方镜像一条命令就能启动。比较推荐的做法是把RSSHub和FreshRSS放在同一台服务器上这样FreshRSS添加订阅源时可以直接填内网地址比如http://localhost:1200/bilibili/user/dynamic/某个UID内网访问稳定也省公网流量。需要注意的是RSSHub的稳定性很大程度取决于上游平台的反爬策略有些路由时好时坏这是正常现象另外部分平台的路由需要传入Cookie才能工作使用时要仔细看官方文档做好Cookie的保密也别反复请求给源站造成压力。5.3 试过用本地模型给文章做自动摘要体验很有意思最近不少朋友在折腾本地大模型部署而FreshRSS其实也能和这个方向结合。大致思路是用FreshRSS的Webhooks扩展把新文章推送到一个本地脚本脚本调用部署好的本地模型给文章生成摘要再把摘要回写到标签里或者推送到通知渠道。按我自己的实测感受这件事完全可行但别期待“零成本”。文字摘要这种任务普通量级的小模型其实就够用没必要非得跑一个超大参数量的模型推理速度和显存开销都要考虑。我目前是在一台带GPU的闲置机器上跑了一个量化过的模型配合FreshRSS每天固定时段批量处理前一天的文章摘要效果算是“能用”但离完美还很远。这个玩法更多是给喜欢折腾的朋友一个方向如果你已经在搞本地大模型不妨把FreshRSS接进来试一试。6. 常见问题与排查技巧实录6.1 定时刷新不生效文章迟迟不更新怎么办这个是我被问得最多的一个问题。症状通常是FreshRSS安装好了手动在后台点“刷新”能抓到文章但放着不管过一晚上也没有新内容进来。绝大多数原因是CRON_MIN环境变量没有设置或者容器内的定时任务没有启动。FreshRSS镜像内部其实集成了cron但需要你通过环境变量告诉它什么时间执行。检查方法很简单在服务器上执行docker compose exec freshrss crontab -l如果输出为空说明容器内没有计划任务需要检查你的docker-compose.yml里是否设置了CRON_MIN。设置后记得重新创建容器docker compose up -d --force-recreate freshrss如果仍然不生效可以手动验证更新脚本是否正常docker compose exec freshrss php cli/update.php --cron这条命令会强制FreshRSS执行一次订阅源抓取。如果手动执行没问题那问题基本就锁定在cron配置上如果手动执行也报错再去查数据目录权限和日志输出。6.2 用了反向代理后页面样式丢失、一直跳http这个问题在Nginx反代场景下非常典型。症状是通过域名访问FreshRSS页面能打开但CSS、图片加载失败页面光秃秃的或者登录后跳转回http地址导致浏览器报警。原因在于FreshRSS收到请求时没有正确识别出“客户端是通过HTTPS访问的”它以为自己还在普通的http环境里于是生成资源链接时全用了http协议。解决办法就两条确保Nginx配置里设置了proxy_set_header X-Forwarded-Proto $scheme;在docker-compose.yml的environment里加上TRUSTED_PROXY并指向反向代理服务器的IP也就是运行Nginx的那台机器本机场景下就是127.0.0.1配置完成后重启FreshRSS容器再强制刷新浏览器页面样式一般就恢复正常了。Caddy用户虽然没有前面那个header问题但TRUSTED_PROXY该设还是要设不然FreshRSS记录的客户端IP可能全是代理的地址影响日志分析和部分扩展的判断。6.3 订阅源抓取失败显示超时或被拒绝订阅源抓取失败的原因五花八门但大部分集中在几个方向。我习惯先拿浏览器直接打开这个RSS地址如果浏览器也打不开那说明源站本身就不健康如果浏览器能打开但FreshRSS显示超时大概率是服务器到源站的网络链路有问题或者是源站对自动化请求有拦截。不少网站会对抓取请求的User-Agent做过滤FreshRSS默认的UA可能被部分源站拒绝。解决办法是在FreshRSS后台的“设置”里找到抓取参数把User-Agent改成常见浏览器的UA比如Mozilla/5.0开头的一段完整UA。另外有些站点的RSS只提供http版本服务器如果强制走HTTPS反而握手失败这种情况可以手动把订阅源地址改成http试一次虽然不推荐长期用明文协议但部分老旧源确实是这个情况。下面这张速查表是我平时排查问题用的直接贴出来给大家参考现象可能原因解决办法安装页无法访问端口未映射、安全组未放行检查docker ps端口放行防火墙规则后台能打开但文章不更新未设置CRON_MIN或cron未生效设置环境变量重建容器手动执行update.php验证反代后样式错乱、跳http缺少X-Forwarded-Proto或TRUSTED_PROXY补上代理头和TRUSTED_PROXY重启容器某订阅源永远抓取失败UA被拦截、http/https不匹配、源地址失效换成浏览器UA尝试http浏览器打开确认手机客户端无法连接APIAPI未开启、未走HTTPS、地址错误开启Google Reader API用HTTPS域名检查API路径忘记管理员密码无用容器内CLI创建新用户或重置密码6.4 数据目录越来越大资源占用持续走高FreshRSS用久了之后data目录下的SQLite数据库文件会越来越大尤其是你同时订阅了几百个更新频繁的源文章每天都在大量堆积。服务器内存和CPU占用升高多半也是后台刷新任务在扫描海量历史文章所致。这个问题的解决办法有两个层面。第一是控制保留天数在FreshRSS后台把文章保留期限从“永久”改成30天或60天FreshRSS的清理机制会定期删除过期文章。第二是调整刷新频率把全局CRON_MIN从每5分钟一次改到每30分钟或每小时一次对大部分人的阅读习惯来说完全够用。我自己的经历是订阅源从一百多涨到五百多之后把刷新频率从15分钟改到30分钟CPU占用明显下来了文章更新延迟也并没有感知到多大差异。还有一个小经验是定期做SQLite的完整性检查和备份。备份最简单直接打包整个data目录就行tar czf freshrss-backup-$(date %F).tar.gz /opt/freshrss/data恢复的时候把data目录解压回去然后重建容器即可。对普通用户来说这套“文件级备份”已经足够安全了。这套自建FreshRSS的方案我自己从第一次安装到现在已经稳定跑了一年多。严格来说RSS解决不了“内容过剩”的问题它只是把“谁来决定你读什么”这个权利还给了你。我最深的体会是自建的真正收益不是省下几十块订阅费而是每一条过滤规则、每一个订阅源、每一台连接设备都由自己掌控。如果你也腻了刷不完的算法流不妨就从今天这个部署开始。先让它跑起来再花点时间慢慢把信息源整理成自己喜欢的样子这件事值得做。
返回列表