为什么搭建自己的 RSS 系统的
一开始我用的是 Folo↗
当作 RSS 客户端。它的界面和体验其实都不错,作为日常阅读工具也足够顺手。但后来这个软件逐渐走向付费,非会员基本已经很难正常使用。对我来说,RSS 这种东西本来就应该是一个长期、稳定、可掌控的信息输入系统,如果核心入口被商业策略卡住,那迟早会变成隐患。
所以我决定尽早迁移,把自己的 RSS 系统重新搭起来。
不要把自己的信息输入系统完全绑死在某一个客户端上。如果只是把 RSS 当成一个“看资讯的软件”,那客户端体验当然最重要;但如果把 RSS 看成一个长期的信息基础设施,那事情就不一样了。
这次我的目标很明确:前端体验要好,后端要稳定,订阅源要尽可能可扩展,而且尽量掌握在自己手里。
作为一个完整的RSS系统,我们需要支持订阅源可迁移,例如OPML导入导出;前后端解耦,并支持自托管;还需要有可拓展的订阅源,能够补足非原生RSS数据来源。
在我比较下我打算使用
Miniflux↗
做后端,
Nextflux↗
做前端,
RSSHub↗
提供非官方的RSS补充源。
方案实施
一开始我原本想用 Caddy 来处理域名和 HTTPS,但是我服务器上已经部署了Bitwarden,占用了80和443端口,这个时候不能让Caddy占用端口,否则现有服务会冲突。
最后的实现逻辑为保留主机上的Nginx,并让Nginx统一接管所有的域名,Docker中Miniflux、Nextflux、RSSHub只监听127.0.0.1的本地端口,并通过Nginx反向代理到这些本地端口。
同时我的域名分配为:
Nextflux 阅读界面↗
,
Miniflux 后台管理↗
,
RSSHub 路由服务↗
。
目录结构
mkdir -p ~/rss-stack/data/{postgres,redis}
cd ~/rss-stack
最后的目录结构大致如下:
rss-stack/
├── compose.yaml
├── .env
└── data/
├── postgres/
└── redis/
设置境变量.env
Miniflux 需要数据库密码、管理员账号密码,以及自己的外部访问地址。
cat > .env <<'EOF'
MINIFLUX_DB_PASSWORD=your_db_password_here
MINIFLUX_ADMIN_USERNAME=admin
MINIFLUX_ADMIN_PASSWORD=your_admin_password_here
MINIFLUX_BASE_URL=https://miniflux.downmars.com
EOF
需要注意的点是,MINIFLUX_DB_PASSWORD是 PostgreSQL 数据库密码,不是网页登录密码;MINIFLUX_BASE_URL 必须是 Miniflux 的真实外部访问地址。
编写compose.yaml
因为宿主机的 80/443 已经由 Nginx 占用,所以这里不能再让容器直接对外暴露 Web 端口,而是只绑定到本机回环地址。
compose.yaml
74 lines
services:
db:
image: postgres:17-alpine
container_name: miniflux-db
environment:
POSTGRES_USER: miniflux
POSTGRES_PASSWORD: ${MINIFLUX_DB_PASSWORD}
POSTGRES_DB: miniflux
volumes:
- ./data/postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U miniflux -d miniflux"]
interval: 10s
timeout: 5s
retries: 10
restart: unless-stopped
miniflux:
image: miniflux/miniflux:2.2.17
container_name: miniflux
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: postgres://miniflux:${MINIFLUX_DB_PASSWORD}@db/miniflux?sslmode=disable
RUN_MIGRATIONS: "1"
CREATE_ADMIN: "1"
ADMIN_USERNAME: ${MINIFLUX_ADMIN_USERNAME}
ADMIN_PASSWORD: ${MINIFLUX_ADMIN_PASSWORD}
BASE_URL: ${MINIFLUX_BASE_URL}
ports:
- "127.0.0.1:18080:8080"
healthcheck:
test: ["CMD", "/usr/bin/miniflux", "-healthcheck", "auto"]
interval: 10s
timeout: 5s
retries: 10
restart: unless-stopped
nextflux:
image: electh/nextflux:latest
container_name: nextflux
depends_on:
miniflux:
condition: service_healthy
ports:
- "127.0.0.1:13000:3000"
restart: unless-stopped
redis:
image: redis:7-alpine
container_name: rsshub-redis
volumes:
- ./data/redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 10
restart: unless-stopped
rsshub:
image: diygod/rsshub:latest
container_name: rsshub
depends_on:
redis:
condition: service_healthy
environment:
NODE_ENV: production
CACHE_TYPE: redis
REDIS_URL: redis://redis:6379/
ports:
- "127.0.0.1:11200:1200"
restart: unless-stopped
miniflux绑定到127.0.0.1:18080;nextflux绑定到127.0.0.1:13000;rsshub绑定到127.0.0.1:11200。也就是说,这三个服务都只在宿主机本机可访问,外部公网不能直接打到容器,而必须通过 Nginx 代理。启动容器
如果系统支持 docker compose,可以直接:
docker compose up -d
docker compose ps
启动之后,可以用下面的方式确认服务是否正常起来:
curl -I http://127.0.0.1:13000
curl -I http://127.0.0.1:18080
curl -I http://127.0.0.1:11200
如果能看到 HTTP 响应,就说明容器层已经没有问题了。
配置 Nginx 反向代理
接下来由宿主机 Nginx 接管域名,再代理到这些本地端口。
vim /etc/nginx/sites-available/rss-stack
/etc/nginx/sites-available/rss-stack
44 lines
server {
listen 80;
server_name read.downmars.com;
location / {
proxy_pass http://127.0.0.1:13000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name miniflux.downmars.com;
location / {
proxy_pass http://127.0.0.1:18080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name rsshub.downmars.com;
location / {
proxy_pass http://127.0.0.1:11200;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name downmars.com;
return 301 http://read.downmars.com$request_uri;
}
之后启用配置:
ln -s /etc/nginx/sites-available/rss-stack /etc/nginx/sites-enabled/rss-stack
nginx -t
systemctl reload nginx
配置 HTTPS
certbot --nginx -d read.downmars.com -d miniflux.downmars.com -d rsshub.downmars.com -d downmars.com
申请完证书后,Nginx 会自动补上 HTTPS 配置。
同时需要在服务器的代理界面上添加对应的域名启用,之后就可以在对应的网页访问服务了。
初始化 Miniflux
Miniflux 后台起来之后,先登录后台创建 API Key。
进入Setting->API Keys->Create a new API key
然后在 Nextflux 里填Server URL:https://miniflux.downmars.com,API Token:刚创建的 API Key,这样就可以正常使用RSS服务了。
分类这件事
系统搭建好了之后,另有一个很重要的事情,RSS源该怎么分类?
如果花很多时间涉及体系,最后的维护成本高于阅读本身。
分类服务于阅读本身,而不是服务于分类本身。
我现在主要分为资讯观察、闲日杂谈、耳边电台和创作频道,分别是一些资讯平台的热点事件、社区动态等;高质量博客的内容、长篇随笔等;偏博客与音频内容;以及视频创作者。
如果没有特殊的原因,不会对分组有太多的修改。RSS系统最怕的不是混乱,而是维护成本过高导致自己懒得用。
为什么想要用RSS
现在没有很多完整的时间来慢慢梳理最近发生了什么我关注的资讯,而且很多不同资讯来自于不同的平台,整理和梳理的成本很大。同时,为了娱乐解闷,很多时候视频平台推什么你看什么,社交平台决定你刷到什么,很容易把人的注意力粉碎到无止境的娱乐中。
用RSS不是为了更热闹的沉浸娱乐中,而是为了更安静、更可控、更连续捕获到自己所需要的东西。