使用 Docker 部署 FreshRSS 自建专属 RSS 服务
RSS 曾是互联网上最普遍的信息获取方式。但是,随着各类智能推荐的信息流平台的诞生,2020 的 RSS 似乎早就度过了其黄金时代。
然而,现在的互联网世界越来越多元化,质量也参差不齐。而利用自己的订阅源,避开繁杂的互联网漩涡,高效地浏览所需的信息,似乎更显价值。
这是我在一年前 自建 Tiny Tiny RSS 一文中写下的开头,这句话放在 2021 年也未尝不可。RSS 已是信息获取手段中的老古董了,随着机器学习的不断推进,平台有时候比你还懂你,不断向你推送着你喜欢的内容,在它面前说实话 RSS 真没什么吸引力。但流量红利空前高涨的同时,也意味着无脑追求下的不可控性。曾目睹一个爆炸标题随便几十万浏览,而用心内容却很难被发掘。这类仅通过反响确立的「优质」是否是真正的优质,我不知道,但这是机器最方便有效的理解方式了。从这个角度看,RSS 也没有那么不堪,至少 RSS 让信息获取的主动性最大程度地保留给你自己,尽量确保信息获取的可控性。
说回来,之前对那套 Tiny Tiny RSS 的方案其实没有什么不满,只不过这次迁移想让所有服务 Docker 化。Docker 的优劣就不在这里提了,至于为什么继续用 Tiny Tiny RSS?有 Awesome-TTRSS 加持下 Docker 部署确实方便,但对于我习惯买的低配 1C/1G 小机来说有点费劲,不怎么「Tiny」。而我对 RSS 服务最关心的只不过:
- 无限制订阅源
- 排版简洁,无广告或其他干扰
至于自定义过滤规则、全文爬取不过都是锦上添花。能做好核心 RSS 功能又还算「Tiny」的,我找到了 FreshRSS。
安装
本文提到的所有服务均为 Docker 安装,所以在开始 FreshRSS 的安装之前先需先配置好 Docker。所使用 VPS 的系统为 Ubuntu 20.04,理论上 Debian 系的所用命令通用,Red Hat 系的请自行替换部分安装命令。
参考 官方文档 安装 Docker:
# 使用官方一键安装脚本
sudo curl -fsSL https://get.docker.com | sh
# 如果是非 Root 账户,将当前账户添加到 "docker" 组
sudo usermod -aG docker <your-user>
随后安装 Docker 三剑客之一——Docker Compose,有它可以方便处理存在依赖关系的服务。即便没有依赖,将长长的 bash 命令换成 yaml 文件的格式传入也舒服多了,不是吗?
# 从 GitHub 下载到本地相应目录
sudo curl -L "https://github.com/docker/compose/releases/download/1.28.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 赋予 Docker Compose 目录相应权限
sudo chmod +x /usr/local/bin/docker-compose
第一条代码中的 1.28.2
可以更换为任何你希望获取的 版本。
FreshRSS 基础服务
除了 FreshRSS 本身,还需要一个数据库才能让它跑起来。官方示例中给出了 MySQL/MarriaDB/PostgreSQL 三种方案,这里只以 PostgreSQL 举例。
创建一个新目录如 ~/freshrss
并进入该位置,新建 docker-compose.yml
,这就是 Docker Compose 的默认配置文件。
# 创建 FreshRSS 目录并进入
mkdir ~/freshrss && cd ~/freshrss
# 新建 Docker Compose 配置文件
touch docker-compose.yml
# 编辑配置文件,反正我习惯用 Vim
vim docker-compose.yml
# ~/freshrss/docker-compose.yml
version: "3"
services:
freshrss-db:
image: postgres:latest
container_name: freshrss-db
hostname: freshrss-db
restart: unless-stopped
volumes:
- freshrss-db:/var/lib/postgresql/data
environment:
POSTGRES_USER: freshrss
POSTGRES_PASSWORD: freshrss
POSTGRES_DB: freshrss
freshrss-app:
image: freshrss/freshrss:latest
container_name: freshrss-app
hostname: freshrss-app
restart: unless-stopped
ports:
- "8080:80"
depends_on:
- freshrss-db
volumes:
- ./data:/var/www/FreshRSS/data
- ./extensions:/var/www/FreshRSS/extensions
environment:
CRON_MIN: '*/45'
TZ: Asia/Shanghai
volumes:
freshrss-db:
配置文件几乎和 模板 一致,只需要注意几点:
- 14~16 行是数据库配置,请自行修改、避免使用默认配置
- 24 行是宿主机端口映射到容器内端口,由于使用 http 通信请勿修改冒号后的
80
端口,冒号前的8080
可以更改为任意空闲的端口 - 31 行是 RSS 刷新周期,单位为分钟,
*/45
表示每 45 分钟刷新一次 - 32 行是时区
:wq
保存退出后,可先前台执行观察输出,若确实无误后便可置于后台持续运行。
# 先前台执行观察输出
docker-compose up
# 确认无误后后台持续运行
docker-compose up -d
Caddy 反向代理
如果上一步没问题的话,已经可以通过 ip:port
的形式访问了。但服务器 IP 不仅不方便记忆,而且也无法使用 HTTPS 加密。所以打算借助 Caddy 接管 80/443 端口,将域名请求反代至特定端口。
至于为什么不用 Nginx/Apache 等更为常见的程式,Caddy 性能方面确实不及它们,但是自动获取 SSL 证书以及过分简单的配置文件,让使用 Caddy 不要太方便;再就是和从 Tiny Tiny RSS 切换至 FreshRSS 的理由一样,Caddy 更加轻量、占用小。这或许是对「最小化原则」的另类诠释?
参见 这篇问答,不能用 localhost
、127.0.0.1
访问从 Docker 映射出来的端口,不然迎接你的可能是 Connection Refused(别问我怎么知道的)。如果你使用的是默认配置,则监听下名为 docker0
的 Docker Bridge。
ip addr show docker0
不出意料会得到类似以下输出,进而得到 docker0
的内网地址,如这里的 172.17.0.1
。
有了该地址与端口,就可以着手于 Caddy 的配置了。由于 Caddy 会直接接管宿主机 80/443 端口,如果有新域名请求需要处理还是修改同一份 Caddy 配置文件Caddyfile
。为方便管理还是建议单独给 Caddy 开一份 Docker Compose 文件,不要共用 FreshRSS 的。
# 创建 Caddy 目录并进入
mkdir ~/caddy && cd ~/caddy
# 新建 Docker Compose 配置文件
touch docker-compose.yml
# 新建 Caddy 配置文件
touch Caddyfile
先编辑 Caddy 配置文件 Caddyfile。
vim Caddyfile
// ~/caddy/Caddyfile
freshrss.example.net {
tls your_email@example.net
reverse_proxy 172.17.0.1:8080
}
完了!是不是简单得过分?相比于其他动辄半百行配置文件的而言。Caddy 还能自动申请 Let’s Encypt 颁发的免费 SSL 证书,只需在第 2 行填写你的邮箱即可。当然你也可以上传自己的 SSL 证书,只需将 tls
行替换为类似以下内容,并把证书放在 ~/caddy/ssl/
下,之后再在 Docker Compose 配置文件将 ~/caddy/ssl
对应容器内的相应位置即可。
tls /etc/ssl/certs/path/to/cert.pem /etc/ssl/certs/path/to/key.pem
:wq
保存退出后继续编辑 Docker Compose 配置文件:
vim docker-compose.yml
# ~/caddy/docker-compose.yml
version: "3"
services:
caddy:
image: caddy:latest
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./site:/srv
- ./ssl:/etc/ssl/certs
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:
之后同样,先前台运行,如果使用域名已经能够访问网站,就切换到后台持续运行。
# 先前台执行观察输出
docker-compose up
# 确认无误后后台持续运行
docker-compose up -d
配置
完成之前的安装,在浏览器中输入设置的域名或服务器 IP + 端口的形式访问 FreshRSS。第一次访问就会进入初始化页面。
初始化
语言选择有简体中文选项,环境检查由于 Docker 严格控制变量基本不会出问题,大概需要注意的只有数据库连接,其余初始化配置就不赘述了。
![数据库连接](https://chralpha.s3.bitiful.net/docker-freshrss-setup/init-3.jpg?q=100)
用户名、密码、数据库分别对应之前 Docker Compose 配置文件中的 POSTGRES_USER
、POSTGRES_PASSWORD
、POSTGRES_DB
;表前缀任意填;主机名要稍微注意一下,既非 127.0.0.1
/localhost
也不是刚刚 Caddy 反代的 172.17.0.1
,而要用容器的 IP,用下述命令可以得到。
# 获取 Container ID
docker ps
# 查看指定容器信息
docker inspect <container id>
![获取 Container IP](https://chralpha.s3.bitiful.net/docker-freshrss-setup/container-ip.jpg?q=100)
所以示例中填写的就是 172.19.0.2
,也只有这样才能连接上 PostgreSQL。
除此以外,如果你只运行一个 PostgreSQL 数据库,可以直接将宿主机 5432 端口映射到 PostgreSQL 容器的 5432 端口,然后使用 172.17.0.1:5432
访问。这样在连接数据库这一步就可以填 172.17.0.1
。但是不建议这么做。
应用配置
默认配置大多没有问题,自己浏览一遍根据习惯来即可,但最好关闭「阅读 => 合适将文章标记为已读」的「在滚动浏览后」,否则即便不点击打开文章、只要你划过去就算已读了。
![关闭滚动浏览后标为已读](https://chralpha.s3.bitiful.net/docker-freshrss-setup/config-settings-1.jpg?q=100)
导入信息源
FreshRSS 支持一键导入信息源,这让迁移省心了不少。我尝试过的 Tiny Tiny RSS 和 Inoreader 的导出文件均可成功导入 FreshRSS,相信大多时候都不会在这里遇到问题。通过「订阅管理 => 导入/导出 => 选择文件」选择要导入信息源的文件即可。
![导入信息源 1](https://chralpha.s3.bitiful.net/docker-freshrss-setup/rss-sources-1.jpg?q=100)
![导入信息源 2](https://chralpha.s3.bitiful.net/docker-freshrss-setup/rss-sources-2.1.jpg?q=100)
插件
FreshRSS 虽有官方的插件仓库,但无法直接在插件配置中直接添加插件,说实话这我不是很理解,但在之前部署 FreshRSS 的 Docker Compose 配置文件中已经将 ~/freshrss/extensions/
对应了 FreshRSS 在容器内的插件位置,所以只需要将插件拖至 ~/freshrss/extensions/
即可。
Fever API
若希望在第三方应用中阅读,目前最方便的方法还是借助 Fever API。尽管它已经不怎么更新,但无所谓,毕竟 RSS 协议已经很稳定了。默认 Fever API 路径为 /api/fever.php
。
后
一年前,随着 2020s 的开始,许多 VPS 的厂商也借机推出许多促销机型,不少还被誉为「传家宝」,我也在这时期购入了好几台尝鲜、体验不同线路。为了尽可能不浪费手头的资源,我开始开始寻找许多服务的自建方案。其中最具代表性的、使用最频繁的莫过于 RSS 服务以及密码托管服务,所以折腾过后也只写下了「使用 Tiny Tiny RSS 搭建自己的 RSS 服务端」和「我的密码管理工具折腾记」。
一年间,折腾也从未止步,尽管有时浪费了不少时间却没有显著收获。我努力过不让那些服务器闲着,但一番操作过后发现结果还不如好好用 Google Drive、好好用 GitHub Pages、好好用 Hexo……那些服务器,大多还是归于沉寂。
一年后,一封封邮件提醒我快到期续费,我会想了下它们下半年的状态,决定把这些放在一边。所谓的「传家宝」并没有传下去,但倒是让我再认清自己的需求。我终究还是续了几台,因为我明白,上面提到的两个服务,是我离不开的、真正需要的。
评论