为什么还值得自建

算法推荐刷久了信息源越来越窄,RSS 的好处是订阅列表自己定、没有插入广告、历史文章能全文检索。FreshRSS 是 PHP + SQLite/PostgreSQL 的老牌方案,对服务器要求极低,一台 1 核 1G 的小 VPS 就够,还支持多用户与 Google Reader API,手机端能直接连。替代里 Miniflux 是 Go 单二进制、更轻但功能少,Tiny Tiny RSS 偏重且维护状态一般,Inoreader 是托管服务不用运维但要付费。自建的代价是域名、证书和偶尔升级,适合本来就有常开机器的人。

docker-compose 起服务

services:
  freshrss:
    image: freshrss/freshrss:latest
    container_name: freshrss
    restart: unless-stopped
    ports:
      - "8081:80"
    environment:
      TZ: Asia/Shanghai
      CRON_MIN: '*/15'
    volumes:
      - ./data:/var/www/FreshRSS/data
      - ./extensions:/var/www/FreshRSS/extensions
    logging:
      options:
        max-size: "10m"
        max-file: "3"
mkdir -p data extensions
docker compose up -d
docker compose logs -f freshrss

浏览器打开 http://服务器IP:8081 走安装向导:检查依赖、选 SQLite(单用户最省事)或 PostgreSQL、设管理员账号。装完第一件事是到"认证"里关掉匿名访问,或用 Nginx 前置一层 basic auth。所有数据都在 ./data 目录,备份就是打包它,别去备份容器本身。

刷新是最容易漏的一步

FreshRSS 不会自己定时拉取订阅,必须配 cron。用官方镜像时设 CRON_MIN 环境变量最省事;手动部署则在宿主机 crontab 里加一行,指向容器内的刷新脚本。不配的结果是所有订阅永远停在导入那一刻,很多人以为部署失败,其实只是没刷新。

*/15 * * * * docker exec freshrss php /var/www/FreshRSS/app/actualize_script.php > /var/log/freshrss_cron.log 2>&1

反代、移动端与踩坑

server {
    listen 443 ssl;
    server_name rss.example.com;
    ssl_certificate /etc/letsencrypt/live/rss.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/rss.example.com/privkey.pem;
    location / {
        proxy_pass http://127.0.0.1:8081;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }
}

手机端在"用户 → API 管理"里设 API 密码并开启 Google Reader API 支持,然后用支持该协议的客户端(FeedMe、Readably、Reeder 等)填 https://rss.example.com/api/greader.php 加账号密码,已读状态双向同步。订阅源用 OPML 导入导出,迁移和备份都靠它;过滤规则可以按关键词自动标已读或打标签,用来压掉信息流里的噪音。

踩坑:时区没设成 Asia/Shanghai 时文章时间整体偏移;SQLite 在并发刷新时偶发 database is locked,订阅多就换 PostgreSQL;部分境外源拉取超时要给容器配代理;全文抓取扩展对动态渲染的站点基本失效,别指望它;升级前一定先备份 ./data 和导出的 OPML,容器重建时数据卷挂错路径等于换了个空库。