SSD Nodes Learn 🎉 VPS от $4.99/мес
Руководства Matt ConnorАвтор: Matt Connor

RSS-ридеры на VPS: Miniflux, FreshRSS и ещё 3

Сравните Miniflux, FreshRSS, CommaFeed, yarr и Tiny Tiny RSS: память, базы данных, Fever и Google Reader API, а также поведение обновлений.

Какой self-hosted RSS-ридер выбрать для небольшого VPS

Miniflux — self-hosted RSS-ридер для небольшого VPS. Он состоит из одного бинарного файла на Go и PostgreSQL. Он поддерживает API Fever и Google Reader, поэтому к нему подключаются сторонние мобильные приложения. Обновление выполняется за один docker compose pull. Выберите FreshRSS, если вам нужны расширения и один контейнер со встроенным SQLite.

На VPS стоит разместить пять ридеров: Miniflux, FreshRSS, CommaFeed, yarr и Tiny Tiny RSS. В этой статье сравниваются их реальные различия: сколько памяти требуется каждому стеку, какую базу данных предполагает каждый вариант, какой API синхронизации нужен мобильному приложению и что происходит во время обновления. Все приведённые здесь значения либо опубликованы разработчиками проектов, либо получены простым расчётом; в тексте указано, какой именно это случай. Эти данные не являются результатами тестирования вашего оборудования, поэтому измерьте собственный сервер с помощью docker stats.

Пять ридеров, по одному абзацу о каждом

Miniflux написан на Go и поставляется в виде одного статически скомпилированного бинарного файла. В документации прямо указана единственная обязательная зависимость: он «работает только с PostgreSQL». Режима SQLite нет. Поддерживаются REST API, API, совместимый с Fever, и API, совместимый с Google Reader, а также импорт и экспорт OPML. Полнотекстовый поиск выполняет PostgreSQL, поэтому база данных обязательна.

FreshRSS написан на PHP и запускается в одном контейнере, где находятся веб-сервер и приложение. SQLite используется по умолчанию и не требует отдельного сервиса. Для более крупных установок поддерживаются PostgreSQL и MySQL. Поддерживаются Google Reader API и Fever API. Установка уже описана в нашем руководстве по FreshRSS на VPS, поэтому здесь мы сравниваем FreshRSS и не повторяем инструкции по установке.

CommaFeed написан на Java для Quarkus и использует интерфейс, скопированный с Google Reader. База данных выбирается во время сборки, а не во время выполнения. Поэтому проект публикует отдельный образ для каждой базы данных: athou/commafeed:latest-h2 для встроенной базы H2, athou/commafeed:latest-postgresql для PostgreSQL, а также варианты для MySQL и MariaDB. Приложение предоставляет REST API и API, совместимый с Fever.

yarr (yet another rss reader) — это один бинарный файл Go со встроенной SQLite. Контейнер не требуется. Обычный ./yarr прослушивает 127.0.0.1:7070. Флаги короткие: -addr 0.0.0.0:7070 -auth alice:secret открывает доступ из сети и включает защиту паролем, а -db /data/yarr.db задаёт расположение базы данных. Поддерживается API, совместимый с Fever. Последний помеченный релиз — v2.8 от July 2024, проверено в August 2026. Поэтому считайте этот проект завершённым, а не активно разрабатываемым.

Tiny Tiny RSS — самый старый и самый сложный в развёртывании из пяти проектов. Официальная конфигурация Docker включает четыре сервиса: контейнер PostgreSQL, контейнер приложения PHP-FPM, отдельный контейнер updater для получения лент и контейнер nginx перед ними. В документации прямо сказано: «эта конфигурация использует PostgreSQL». Проект предоставляет собственный JSON API, с которым работают его Android-клиент и несколько сторонних приложений. Fever не поддерживается.

Сколько памяти требуется каждому стеку

Приведённые ниже значения — это бюджеты, а не результаты измерений: максимальный объём памяти, в пределах которого каждый стек должен работать на небольшом VPS. Значение для CommaFeed взято из опубликованного примера проекта: для контейнера установлен предел 256 MB. Для остальных стеков указаны пределы с запасом для загрузчика лент. Именно он потребляет больше памяти при запуске цикла обновления.

ChartMemory ceiling per reader stack, in MB
The data behind this chart
[
  {
    "label": "yarr (SQLite)",
    "containers": 1,
    "mem_limit_mb": 128
  },
  {
    "label": "FreshRSS (SQLite)",
    "containers": 1,
    "mem_limit_mb": 256
  },
  {
    "label": "CommaFeed (H2)",
    "containers": 1,
    "mem_limit_mb": 256
  },
  {
    "label": "Miniflux + Postgres",
    "containers": 2,
    "mem_limit_mb": 320
  },
  {
    "label": "Tiny Tiny RSS",
    "containers": 4,
    "mem_limit_mb": 640
  }
]

yarr требует меньше всего памяти — 128 MB, поскольку состоит из одного бинарного файла и одного файла SQLite. Ему не нужны отдельный сервер базы данных и среда выполнения языка. Miniflux требует 320 MB для 2 контейнеров. Большая часть этого объёма приходится на PostgreSQL, а не на Miniflux. Tiny Tiny RSS является исключением: ему требуется 640 MB для 4 контейнеров. Приложение, обновляющий процесс, база данных и веб-сервер работают как четыре отдельных процесса, каждый со своей кучей.

Задайте эти значения как реальные ограничения, а не как желаемые показатели. В разделе Ограничения памяти в Docker Compose описаны синтаксис и поведение контейнера при достижении предела. Контейнер без ограничения не завершает работу корректно при полном заполнении памяти сервера: kernel выбирает процесс и завершает его. Часто это оказывается не тот контейнер, который создал дефицит памяти.

Какую базу данных требует каждый вариант

База данных — главное эксплуатационное различие между этими пятью вариантами. Это более важный выбор, чем любые различия в пользовательском интерфейсе, поскольку от него зависят процедура резервного копирования и риск при обновлении.

PostgreSQL требуется для Miniflux и официальной установки Tiny Tiny RSS. Это обеспечивает полноценный полнотекстовый поиск и безопасную одновременную запись. Но потребуется второй контейнер и отдельный volume. Кроме того, возникает регулярная проблема: официальные образы PostgreSQL не умеют переносить данные между основными версиями без остановки. В документации Tiny Tiny RSS это указано напрямую: "official PostgreSQL containers have no support for migrating data between major versions". Реалистичные варианты — зафиксировать старую основную версию либо выполнить дамп и восстановление с помощью pg_dump и pg_restore. Планируйте такую процедуру раз в один-два года.

SQLite используется по умолчанию в FreshRSS и yarr. Нужен один файл, но не нужны сервер, порт и пароль. Для одного пользователя с несколькими сотнями лент этого обычно достаточно. При одновременной записи нескольких пользователей производительность снижается. В такой ситуации начинает оправдывать себя вариант FreshRSS с PostgreSQL. В yarr появилась необязательная поддержка PostgreSQL в v2.7, но обычно его запускают со встроенной базой данных.

H2 — встроенная база данных по умолчанию в CommaFeed. Перед началом работы это требует отдельного решения, поскольку CommaFeed выбирает базу данных на этапе сборки образа. Переход с H2 на PostgreSQL позднее не сводится к изменению конфигурации. Потребуется другой образ и самостоятельная миграция данных. Поэтому примите решение до того, как в системе накопится история чтения за год.

Будет ли работать мобильное приложение

Этот вопрос важнее, чем кажется, поскольку веб-интерфейс — только половина сценариев использования feed reader.

Miniflux поддерживает Fever compatible API и Google Reader compatible API, поэтому к нему подключается большинство клиентов для iOS и Android. FreshRSS поддерживает те же два API, но в собственной документации сравнивает их: Google Reader API назван «лучшим» и поддерживает все функции, а Fever API имеет «ограниченные возможности и менее эффективное» поведение. Перед входом любого приложения в FreshRSS также нужно выполнить два шага. В разделе Authentication включите параметр «Allow API access (required for mobile apps)», затем создайте API password в профиле пользователя. Если не создать API password, приложение выдаст ошибку аутентификации, а вход через веб-интерфейс продолжит работать. Это может сбить с толку, пока вы не узнаете, где искать причину.

CommaFeed и yarr предоставляют только Fever compatible API. Поэтому они работают с клиентами, поддерживающими Fever, но не с приложениями, которые поддерживают только Google Reader. У Tiny Tiny RSS вместо этого есть собственный API, поэтому для него нужен специально разработанный клиент. Проверьте, поддерживает ли выбранное приложение этот feed reader, прежде чем импортировать в него 300 feeds.

Рабочий compose-файл для сервера с 1 GB ОЗУ

Это стек Miniflux, адаптированный из собственного примера Docker для проекта по состоянию на August 2026. Опубликованный порт привязан к loopback, адрес прослушивания задан явно, а для обоих контейнеров установлен лимит памяти.

services:
  miniflux:
    image: miniflux/miniflux:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    depends_on:
      db:
        condition: service_healthy
    environment:
      - DATABASE_URL=postgres://miniflux:CHANGE_ME@db/miniflux?sslmode=disable
      - LISTEN_ADDR=0.0.0.0:8080
      - BASE_URL=https://rss.example.com/
      - RUN_MIGRATIONS=1
      - CREATE_ADMIN=1
      - ADMIN_USERNAME=admin
      - ADMIN_PASSWORD=CHANGE_ME_TOO
      - POLLING_FREQUENCY=60
    healthcheck:
      test: ["CMD", "/usr/bin/miniflux", "-healthcheck", "auto"]
    mem_limit: 128m
  db:
    image: postgres:18
    restart: unless-stopped
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=CHANGE_ME
      - POSTGRES_DB=miniflux
    volumes:
      - miniflux-db:/var/lib/postgresql
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "miniflux"]
      interval: 10s
      start_period: 30s
    mem_limit: 192m
volumes:
  miniflux-db:

В этом файле есть три строки, в которых чаще всего ошибаются. LISTEN_ADDR=0.0.0.0:8080 задан потому, что документированное значение по умолчанию для бинарного файла — 127.0.0.1:8080. Процесс, привязанный к loopback внутри контейнера, нельзя подключить через опубликованный порт. В результате соединение сбрасывается, хотя контейнер выглядит работоспособным. Путь тома /var/lib/postgresql соответствует PostgreSQL 18. В version 17 и более ранних версиях данные хранятся в /var/lib/postgresql/data. Если смонтировать неправильный путь, каталог данных вообще не будет находиться на томе, и все данные исчезнут при следующем пересоздании контейнера. 127.0.0.1:8080:8080 не позволяет опубликовать порт в общедоступный Интернет, поскольку публикация порта без указания адреса добавляет правило в цепочку, которой ufw не управляет. В статье Порты Docker обходят ufw объясняется этот механизм, а reverse proxy Traefik позволяет разместить TLS перед сервисом.

docker compose up -d
docker compose ps
docker compose logs -f miniflux
docker stats --no-stream

docker compose ps должен показывать оба сервиса в состоянии running, а для базы данных должно быть указано состояние healthy. При первом запуске Miniflux записывает в журнал миграции схемы. Именно это запускает RUN_MIGRATIONS=1. docker stats --no-stream выводит текущее значение столбца памяти. С ним нужно сравнивать ограничения, указанные в таблице выше. Если контейнер Miniflux циклически перезапускается, прочитайте его журнал: connect: connection refused означает, что контейнер запустился до того, как PostgreSQL начал принимать подключения. Именно это предотвращает условие service_healthy, поэтому проверьте, что после редактирования файла условие сохранилось. Если Compose для вас новый инструмент, в статье Основы Docker Compose на VPS сначала рассматривается структура файла.

Что не поместится на сервере с 1 GB RAM

Tiny Tiny RSS лучше не использовать. Официальный стек из четырёх сервисов работает на VPS с 1 GB RAM, если на этом VPS больше ничего не запущено. Рядом с другим приложением, использующим базу данных, и reverse proxy он уже не работает. Четыре сервиса означают четыре набора накладных расходов. Один из них — PostgreSQL.

CommaFeed помещается, но только с образом H2 и ограничением в 256 MB, указанным в собственном примере проекта. Маленький сервер перестаёт справляться, когда JVM работает рядом с отдельным сервером базы данных: JVM использует весь оставленный ей запас памяти. В документации CommaFeed -Xmx256m указано как жёсткое ограничение, а OpenJ9 назван «более эффективной по памяти альтернативой JVM HotSpot». Это показывает, куда расходуется память.

Если на сервере заканчивается память, kernel out of memory killer выбирает процесс и завершает его. В dmesg -T появляется строка вида Out of memory: Killed process 1234 (java), а контейнер просто исчезает из docker compose ps без сообщения в application log, потому что приложение не успело его записать.

Как выполняются обновления в каждом из них

  • Miniflux: docker compose pull && docker compose up -d, миграции схемы применяются при запуске, пока задан параметр RUN_MIGRATIONS=1. Риск обновления связан не с Miniflux, а с используемой под ним основной версией PostgreSQL.
  • FreshRSS: загрузите новый образ. При использовании SQLite отдельный движок базы данных обновлять не требуется, поэтому обычная причина сбоев — сторонние расширения, которые не успели адаптироваться.
  • CommaFeed: загрузите вариант образа, соответствующий вашей базе данных. Переключение с latest-h2 на latest-postgresql не переносит данные.
  • yarr: замените бинарный файл и сохраните файл базы данных. Поскольку с июля 2024 года, а по состоянию на август 2026 года, новых выпусков не было, обновлять обычно нечего.
  • Tiny Tiny RSS: docker compose pull && docker compose up -d. Миграции схемы выполняются автоматически. Если требуется подтверждение, интерфейс перенаправляет вас на экран миграции.

Перед любым из этих действий создайте дамп базы данных, а не после него.

docker compose exec -T db pg_dump -U miniflux miniflux | gzip > miniflux-$(date +%F).sql.gz

Сколько трафика требует интервал обновления

Приведённые ниже значения получены расчётным путём, а не измерены. Они рассчитаны для 100 лент, одного запроса к каждой ленте за интервал и 40 KB на ответ. Фактический трафик обычно ниже, если сервер обрабатывает условные запросы, и выше, если ленты содержат полный текст статей.

ChartMonthly fetches and bandwidth for 100 feeds at 40 KB per response
The data behind this chart
[
  {
    "label": "Every 5 minutes",
    "fetches_per_month": "864,000",
    "gb_per_month": 34.6
  },
  {
    "label": "Every 15 minutes",
    "fetches_per_month": "288,000",
    "gb_per_month": 11.5
  },
  {
    "label": "Every 30 minutes",
    "fetches_per_month": "144,000",
    "gb_per_month": 5.8
  },
  {
    "label": "Every 60 minutes",
    "fetches_per_month": "72,000",
    "gb_per_month": 2.9
  }
]

Интервал в пять минут для 100 лент составляет 864,000 запросов и примерно 34.6 GB в месяц. При опросе раз в час получается 72,000 запросов и около 2.9 GB. В Miniflux параметр POLLING_FREQUENCY по умолчанию установлен в 60 минут. Это последняя строка на этой диаграмме, и такое значение подходит почти всем. Статья не появится раньше только потому, что вы чаще запрашиваете ленту.

Именно условные запросы удерживают фактический показатель ниже расчётного. Клиент, который сохраняет заголовки ETag и Last-Modified, полученные от ленты, отправляет их обратно как If-None-Match и If-Modified-Since, а сервер без новых данных отвечает кодом 304 Not Modified без тела ответа. Соединение всё равно требует handshake, но полезная нагрузка не передаётся. Ленты, которые игнорируют условные запросы, каждый раз передают весь документ. Поэтому несколько крупных лент могут самостоятельно формировать основную часть расходов на трафик.

Слишком частый опрос также может привести к блокировке. Сервер, который решит, что вы отправляете слишком много запросов, ответит кодом 429 Too Many Requests, а некоторые сайты используют вместо этого код 403. Miniflux сохраняет последнюю ошибку для самой ленты. Поэтому список лент — первое место, которое следует проверить, если одна лента перестала обновляться, а остальные продолжают работать.

Ленты перестают работать, а файл OPML не является резервной копией

Ленты перестают обновляться быстрее, чем вы ожидаете. Срок действия домена заканчивается, сайт переезжает на платформу без поддержки лент, а URL, который раньше возвращал XML, начинает отдавать HTML-страницу с ошибкой и статусом 200 OK. Последний случай особенно неудобен: загрузка завершается успешно, разбор завершается ошибкой, и reader записывает ошибку разбора, а не сетевую ошибку. Раз в год сортируйте список лент по времени последнего обновления и удаляйте те, которые давно не обновлялись.

Экспорт OPML — это список ваших подписок. В нём хранятся URL лент и названия папок. В нём не хранятся состояние прочтения, отмеченные статьи, настройки отдельных лент, правила фильтрации и сохранённый текст статей. После импорта этого OPML в новую установку вы получите свои ленты, но все когда-либо прочитанные статьи снова будут отмечены как непрочитанные.

Важнее всего резервная копия базы данных. Для PostgreSQL достаточно выполнить команду pg_dump, приведённую выше. Для reader на SQLite, например FreshRSS или yarr, остановите процесс записи и скопируйте файл либо создайте согласованную копию во время работы с помощью sqlite3 yarr.db ".backup '/tmp/yarr-backup.db'". Обычный cp базы данных, в которую выполняется запись, может создать файл, который впоследствии не откроется: копия может содержать незавершённую запись. Затем регулярно отправляйте эти файлы за пределы сервера. Для этого предназначены резервные копии restic на VPS. Хотя бы один раз восстановите копию во временный контейнер, чтобы убедиться, что процедура работает.

Reader лент — один из самых недорогих сервисов для самостоятельного размещения, поэтому он входит во все списки сервисов, которые стоит размещать самостоятельно в 2026 году. Разместите рядом с ним собственный экземпляр SearXNG, и чтение, и поиск будут выполняться на оборудовании под вашим контролем.

FAQ

Какой self-hosted RSS reader использует меньше всего памяти?

yarr. Это один бинарный файл Go со встроенной SQLite. Поэтому ему не нужны сервер базы данных и отдельная языковая среда выполнения, а ограничение в 128 MB для него достаточно. Компромисс — обслуживание и набор функций: последний выпуск — v2.8 от July 2024, а поддерживается только Fever API. Если нужен активно развиваемый проект с сопоставимым потреблением ресурсов, лучше выбрать Miniflux с PostgreSQL при ограничении 320 MB.

Можно ли запустить self-hosted RSS reader на VPS с 1 GB?

Да. Miniflux с PostgreSQL занимает около 320 MB, если задать mem_limit для обоих контейнеров. FreshRSS с SQLite помещается в один контейнер. На VPS с 1 GB следует избегать официального стека Tiny Tiny RSS: в нём 4 сервиса, включая собственный PostgreSQL. Всегда задавайте ограничения памяти. Если контейнер на полностью загруженном сервере работает без ограничения, kernel завершает один из процессов. Часто им оказывается база данных, а не приложение, в котором возникла проблема.

Какие из этих решений работают с RSS-приложениями для iOS и Android?

Miniflux и FreshRSS поддерживают Fever compatible API и Google Reader compatible API, поэтому к ним подключается почти любой мобильный клиент. CommaFeed и yarr поддерживают только Fever API. Tiny Tiny RSS использует собственный API, поэтому нужен клиент, созданный для него. В FreshRSS также нужно включить доступ к API в разделе Authentication и задать отдельный пароль API в профиле. Иначе приложение не сможет войти в систему, хотя сайт продолжит работать.

Является ли экспорт OPML резервной копией RSS reader?

Нет. OPML содержит URL лент и папки. Он позволяет восстановить список подписок, но не другие данные. Состояние прочтения, отмеченные элементы, правила фильтрации и текст статей хранятся в базе данных. Создайте резервную копию самой базы данных с помощью pg_dump для PostgreSQL или команды .backup для SQLite. Затем скопируйте результат за пределы сервера.

Поддерживает ли Miniflux SQLite?

Нет. В документации проекта указано, что он "работает только с PostgreSQL". Полнотекстовый поиск реализован с помощью функций PostgreSQL, поэтому переключиться на более лёгкий режим нельзя. Если нужен feed reader без отдельного контейнера базы данных, запустите FreshRSS с backend SQLite по умолчанию или yarr со встроенным файлом.