这是「Docker 好项目」系列的第 12 期。这一期聊一个「信息流焦虑」的解药:RSS 阅读器。如果你还在被各大 App 的信息流喂料、被算法牵着走,Miniflux 能把订阅权重新交回你自己手里。

痛点开场
每天打开的不是新闻,是十个 App 的开屏广告和推荐流。想看的东西要看平台脸色,不想看的塞满首页,算法还越来越懂怎么让你多划两下。
RSS 是把订阅权还给用户最干净的方式:你订阅谁、看什么、什么时候看,全由你定。但公共 RSS 服务要么停了(Google Reader 的痛很多人还记得),要么开始加广告、限速、卖数据。
Miniflux 就是这个问题的自托管解:一个极简、固执己见(opinionated)的 RSS 阅读器,作者 Frédéric Guillot 一个人维护了很多年,做减法的哲学贯彻到底——不堆功能,只把「读订阅」这件事做到顺手。
能力边界
能干什么 - 抓取 RSS / Atom / JSON Feed,支持大部分站点,自带 content scraper(把只有摘要的源抓成全文) - 全文搜索(底层是 Postgres 的全文检索,不是简单 LIKE) - 多用户、分类、星标、已读历史、规则过滤(按关键词自动标星/标记已读/转发) - 自带 API(Miniflux API + 兼容 Fever API + Google Reader API),Reeder、NetNewsWire、NewsFlash、Flux 等主流客户端直接连 - 30+ 集成:ntfy、Telegram、Discord、Matrix、Slack、webhook,以及 Linkding / Raindrop / Wallabag 等书签/稍后读工具 - 图片走 Media Proxy,不泄露你的 IP 给文章里的图床
不干什么 - 不做社交、不做推荐、不做「猜你喜欢」 - 不存文章到本地文件(数据全在 Postgres 里,没有独立的「附件库」) - 不内置通知中心推送(告警靠集成转发到 ntfy/Telegram 这类外部渠道,详见后文) - 不支持 MySQL / SQLite,只认 PostgreSQL
一句话:Miniflux 只管「把订阅拉下来、整理好、让你读」,其他的一律交给别的工具。
部署前准备
- 一台能跑 Docker 的机器(主人这台华为云 ECS 完全够用,Miniflux 本体是 Go 单二进制,内存占用极低,给 256M 都绰绰有余)
- 一个 PostgreSQL 数据库(Miniflux 只支持 Postgres,不支持 MySQL/SQLite)。可以单独起一个 Postgres 容器,也可以用 1Panel 的「数据库」模块建一个
- 一个域名 + 反向代理(Nginx Proxy Manager / Caddy 都行),后面细说
- 镜像:
miniflux/miniflux:2.3.3
关于镜像 tag 必须说一句(往期踩过这个坑):Miniflux 的 Docker Hub 只发布完整版本号 tag(2.3.3)和 latest,没有 2.3 或 2 这类次版本/主版本滚动 tag。我实测 miniflux/miniflux:2.3 和 :2 都返回 404,而 :latest 当前的 digest 与 :2.3.3 完全一致。所以这一期钉全量版本 2.3.3,不要图省事写 :latest(哪天升了 2.4 你毫无防备),也不要写 :2 或 :2.3(根本拉不到)。
docker run 一行版
适合先快速验证,正式用建议走下面的 compose:
docker run -d \
--name miniflux \
-p 8080:8080 \
-e "DATABASE_URL=postgres://miniflux:你的密码@postgres主机IP:5432/miniflux?sslmode=disable" \
-e "RUN_MIGRATIONS=1" \
-e "CREATE_ADMIN=1" \
-e "ADMIN_USERNAME=admin" \
-e "ADMIN_PASSWORD=换一个强密码" \
miniflux/miniflux:2.3.3
注意:容器里 LISTEN_ADDR 默认被 Dockerfile 设成 0.0.0.0:8080,所以 -p 8080:8080 能直接通。如果你只映射了宿主的 80 端口,就写 -p 80:8080。
RUN_MIGRATIONS=1 第一次必须带——它会自动建表/跑迁移。建完之后其实可以去掉,但留着也无害(幂等)。
docker-compose 推荐版
把 Miniflux 和 Postgres 放一起,最省心:
services:
miniflux:
image: miniflux/miniflux:2.3.3
container_name: miniflux
restart: always
ports:
- "8080:8080"
depends_on:
db:
condition: service_healthy
environment:
- DATABASE_URL=postgres://miniflux:secret@db:5432/miniflux?sslmode=disable
- RUN_MIGRATIONS=1
- CREATE_ADMIN=1
- ADMIN_USERNAME=admin
- ADMIN_PASSWORD=换一个强密码
- BASE_URL=https://rss.你的域名.com
# 可选健康检查
# - HEALTHCHECK 见下方说明
healthcheck:
test: ["CMD", "/usr/bin/miniflux", "-healthcheck", "auto"]
interval: 60s
timeout: 10s
retries: 3
db:
image: postgres:18
container_name: miniflux-db
restart: always
environment:
- POSTGRES_USER=miniflux
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=miniflux
volumes:
- miniflux-db:/var/lib/postgresql
healthcheck:
test: ["CMD", "pg_isready", "-U", "miniflux"]
interval: 10s
start_period: 30s
volumes:
miniflux-db:
depends_on ... condition: service_healthy 保证 Postgres 真正能连上之后 Miniflux 才启动,避免首次跑迁移时连库失败。db 用服务名 db 作为主机名(Docker 内部 DNS),所以 DATABASE_URL 里写 db:5432 而不是 IP。
配置项逐项解释
下表是这一期用到的关键环境变量,默认值来自 Miniflux 源码 internal/config/options.go(2.3.3 实测):
| 变量 | 默认值 | 说明 / 为什么这么写 |
|---|---|---|
DATABASE_URL |
user=postgres password=postgres dbname=miniflux2 sslmode=disable |
Postgres 连接串,支持 libpq 键值对格式或 postgres:// URL 格式。同网络用 db:5432,跨机用 IP。自托管一般 sslmode=disable |
RUN_MIGRATIONS |
0 |
必须设 1,否则库里没表,Miniflux 起不来。迁移幂等,可长期保留 |
CREATE_ADMIN |
0 |
设 1 会在启动时用下面两个变量创建首个管理员。建完账号后可删掉这三项 |
ADMIN_USERNAME / ADMIN_PASSWORD |
空 | 仅 CREATE_ADMIN=1 时生效。密码别用示例的 test123 |
BASE_URL |
http://localhost |
非常重要:写成你的公网地址(如 https://rss.xxx.com)。它决定登录后跳转、Cookie 作用域、Fever/API 回调地址。写错会登录后跳回 localhost 或 404 |
LISTEN_ADDR |
配置默认 127.0.0.1:8080,但镜像里被 Dockerfile 改成 0.0.0.0:8080 |
容器实际监听 0.0.0.0:8080。一般不用动;想换端口改这个 + 映射端口即可 |
POLLING_FREQUENCY |
60(分钟) |
整轮所有订阅的抓取间隔。源多就调大,源少想更实时就调小(如 15) |
WORKER_POOL_SIZE |
16 |
并发抓取的 worker 数(老版本是 5,2.x 提上来了)。订阅几百个以上可以适当加大 |
BATCH_SIZE |
100 |
每批处理的订阅数,一般不用动 |
CLEANUP_FREQUENCY_HOURS |
24 |
清理已读条目历史/会话的间隔 |
MEDIA_PROXY_MODE |
http-only |
图片代理策略:http-only 只代理 http 图(防 IP 泄露),all 全代理,none 不代理。默认已够隐私,建议保持 |
FETCHER_ALLOW_PRIVATE_NETWORKS |
0 |
坑点:默认禁止抓取内网地址。如果你要订阅同局域网自建服务的 RSS(比如自己搭的 FreshRSS、Halo 的评论订阅),必须设 1 |
DISABLE_HSTS |
0 |
Miniflux 检测到 HTTPS 会自动加 HSTS 头。若反代是 Cloudflare「Flexible」模式(TLS 在 CF 就终结,回源是 http),HSTS 会让你被锁在门外,这种情况设 1 |
TRUSTED_REVERSE_PROXY_NETWORKS |
空 | 走反代时,填反代所在网段(如 172.18.0.0/16 或反代容器 IP),让 Miniflux 正确读取真实客户端 IP,否则日志里全是反代 IP |
HTTPS |
0 |
Miniflux 自己不处理 TLS,TLS 交给反代。保持 0 |
1Panel 面板怎么搞
1Panel 应用商店里没有 Miniflux 官方一键应用,但用 1Panel 跑它很顺:
- 进入 容器 → 编排,新建一个编排,把上面的
docker-compose整段粘进去,名称填miniflux,点部署即可。1Panel 会自动拉起两个容器并建好网络 - 数据库也可以交给 1Panel:数据库 → PostgreSQL → 创建,建一个
miniflux库和用户,然后把DATABASE_URL指向 1Panel 的 Postgres(注意 1Panel 的 Postgres 端口和容器网络,跨 compose 网络时要用宿主 IP + 映射端口,或把 Miniflux 也放进同一个 1Panel 容器网络) - 部署后在 容器 里看
miniflux容器日志,出现Starting Miniflux...且健康检查变绿就 OK
实操提示:华为云这台机器如果 Postgres 也跑在 1Panel 里,建议 Miniflux 和 Postgres 放在同一个 compose / 同一个自定义网络,直接用服务名
db互通,最省事也最不容易因为端口没开而连不上。
首次访问
- 浏览器打开
http://<你的IP>:8080(或在反代配好后打开域名) - 用
ADMIN_USERNAME/ADMIN_PASSWORD登录(首次建的 admin) - 进去第一件事:设置 → 修改密码,把示例密码换成自己的
- 点「添加订阅」,贴一个 RSS 源 URL(比如
https://www.xlee.chat/atom.xml,咱自己博客的订阅源),或导入 OPML(很多阅读器能导出.opml文件) - 等几轮抓取(默认 60 分钟一轮)。想马上看到效果,除了在 UI 里点「刷新」,也可以直接在宿主机敲命令强制全量拉取一次:
docker exec miniflux miniflux -refresh-feeds
左边就能读了
Miniflux 的快捷键很全:g u 去未读、j/k 上下、v 在外部打开、r 标已读。用熟了比刷信息流快得多。
最小可用配置
如果你只想先跑起来看效果,下面这份就是最小集(其余全走默认值):
environment:
- DATABASE_URL=postgres://miniflux:secret@db:5432/miniflux?sslmode=disable
- RUN_MIGRATIONS=1
- CREATE_ADMIN=1
- ADMIN_USERNAME=admin
- ADMIN_PASSWORD=你的强密码
# BASE_URL 先不填也能本地用,但一旦上公网务必补上
跑通之后,再按需加 BASE_URL、健康检查、反代相关变量。
告警 / 通知配置
Miniflux 本身没有内置的「系统告警」(不像 Uptime Kuma 那样告诉你「服务挂了」),它的「通知」指的是订阅内容的转发。两套玩法:
1. 内容规则 → 外部渠道(真·通知)
设置里有「规则」(Rules):当文章标题/内容匹配某关键词时,自动「标星 / 标记已读 / 转发到集成」。配合集成里的 ntfy、Telegram、Discord、webhook,就能实现「某某博客更新了 → 推到我手机」。比如给自己的博客源加一条规则:匹配作者名就转发到 ntfy,等于一个轻量更新播报。
2. 服务存活监控(外部保活)
Miniflux 暴露了标准健康检查端点,docker run 里的 healthcheck 就是用它:
/healthcheck
/liveness /healthz (存活探针)
/readiness /readyz (就绪探针)
想监控「Miniflux 还活着」,用 Uptime Kuma(第 1 期讲过的)加一个 HTTP 监控,URL 填 https://rss.你的域名.com/healthz,返回 200 即正常。这样服务挂了你能第一时间收到告警,而不是等想看订阅时发现白屏。
反向代理与 HTTPS
Miniflux 自己不处理 TLS,TLS 交给反代。以 Nginx Proxy Manager(第 2 期)为例:
- Hostname/IP 填 Miniflux 容器可达的地址:
127.0.0.1:8080(若 NPM 和 Miniflux 在同一台机器),或反代容器能解析到的服务名/IP - Scheme:
http - 勾上 SSL(Let's Encrypt 或导入证书)
BASE_URL必须设成公网 HTTPS 地址,二者要对得上
Caddy 用户更省事,一份 Caddyfile:
rss.你的域名.com {
reverse_proxy 127.0.0.1:8080
}
反代跑在 Cloudflare 后面的注意两点:
- 若 CF 用 Flexible(回源 http),Miniflux 的 HSTS 会把你锁门外 → 设 DISABLE_HSTS=1
- 设 TRUSTED_REVERSE_PROXY_NETWORKS 为反代所在网段,否则日志 IP 全错
踩坑清单
- tag 别写
:2/:2.3:这俩在 Docker Hub 上根本不存在(实测 404),只能写全量2.3.3或:latest BASE_URL不填 = 登录后跳 localhost:上了公网一定填公网地址,且和反代的proxy_pass域名一致FETCHER_ALLOW_PRIVATE_NETWORKS默认0:要抓局域网/同主机其他容器的 RSS,必须设1,否则连接被拒- Cloudflare Flexible + HSTS 锁门:见上,设
DISABLE_HSTS=1 - 只认 Postgres:别拿 MySQL 容器去连,Miniflux 不认;也不需要手动建
hstore扩展(2.0.27 之后已不需要,2.2.14 还专门跑了移除迁移) CREATE_ADMIN只生效一次:账号建好后再重启不会覆盖密码。忘了密码用容器里的 CLI 重设:
docker exec -it miniflux miniflux -reset-password
按提示输入用户名和新密码即可,不需要停服
7. WORKER_POOL_SIZE 老文档写 5:2.x 默认已提到 16,照着老教程调小反而变慢
8. 反向代理后的真实 IP:不配 TRUSTED_REVERSE_PROXY_NETWORKS,所有访问记录都显示反代 IP
备份
Miniflux 没有独立文件库,数据全在 Postgres,所以备份 Postgres 就等于备份了 Miniflux。
# 导出整个 miniflux 库
docker exec miniflux-db pg_dump -U miniflux miniflux > miniflux-$(date +%F).sql
恢复:
docker exec -i miniflux-db psql -U miniflux -d miniflux < miniflux-某日期.sql
另外,订阅源(不含文章)可以用 UI 里的 设置 → 导出 OPML 单独备份,换机器时导入即可。1Panel 的「数据库」模块如果用了它的 Postgres,也能直接在面板里设定时备份,比手写 cron 省心。
小结
适合谁 - 受够了算法推荐、想自己掌控信息流的人 - 已经在跑 Docker / 1Panel、有 Postgres 习惯的自托管玩家 - 需要把「某源更新」推到手机(ntfy/Telegram)做轻量播报
不适合谁 - 想要「社区/发现/推荐」那种社交化阅读体验的(Miniflux 刻意不做) - 不想养一个 Postgres 的极简主义者(那可以看看用 SQLite 的 FreshRSS 单文件版,但 Miniflux 只认 PG) - 订阅量极大又不想调参的(默认配置对几千个源也 OK,但极端的要调 worker / 频率)
把这台华为云 ECS 上的 Miniflux 搭起来,你的信息流就再也不看任何平台的脸色了。
项目地址
- GitHub:https://github.com/miniflux/v2
- 官网文档:https://miniflux.app
- Docker 镜像:
miniflux/miniflux:2.3.3(Docker Hub)/ghcr.io/miniflux/miniflux:2.3.3(GHCR,国内拉取更稳时可换这个)