MAATRIX / Блог / FreshRSS в Docker Compose: готовый файл

FreshRSS в Docker Compose: готовый файл

MAATRIX

Google Reader закрыли ещё в 2013-м, но проблема осталась той же: облачные RSS-читалки либо режут число лент на бесплатном тарифе, либо просят подписку, либо просто закрываются вместе с сервисом, на котором вы годами собирали источники. FreshRSS решает это одним компактным контейнером — свой сервер, свои ленты, никаких лимитов и рекламы. Ниже — рабочий docker-compose.yml, который поднимается за пять минут, плюс всё, что нужно для домена с SSL, мобильных клиентов и бэкапа.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Зачем self-hosted RSS-агрегатор и почему именно FreshRSS

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

Из готовых облачных вариантов остаются Feedly (бесплатно — 100 лент, дальше платно), Inoreader (похожая модель) и NewsBlur. Все они работают, но это чужая инфраструктура: ваш список источников и история чтения лежат на серверах третьей компании, а бесплатный тариф рано или поздно упирается в потолок.

FreshRSS — open-source альтернатива, которая закрывает эти вопросы:

  • Лёгкий. PHP-приложение, может работать на SQLite без отдельной базы — под него хватит самого младшего VPS.
  • API-совместимость. Поддерживает Google Reader API и Fever API, поэтому подключается почти любой мобильный или десктопный RSS-клиент — не нужен отдельный клиент именно под FreshRSS.
  • Без лимитов на ленты и пользователей — можно завести несколько аккаунтов (например, себе и партнёру) на одном инстансе.
  • Расширения — правила фильтрации, автоматические теги, интеграции с read-later сервисами.

Минус тоже стоит проговорить честно: обновлять и бэкапить сервер придётся самому — это не SaaS с автоматическим сопровождением. Но для агрегатора, который открывают раз в день, это разумная цена за независимость от чужого бесплатного тарифа.

Готовый docker-compose.yml

Самый простой вариант — с встроенной SQLite, без отдельного контейнера базы данных. Для личного использования и небольшого числа лент этого достаточно с запасом:

services:
  freshrss:
    image: freshrss/freshrss:latest
    container_name: freshrss
    restart: unless-stopped
    ports:
      - "8080:80"
    environment:
      TZ: Europe/Moscow
      CRON_MIN: "3,33"
    volumes:
      - freshrss_data:/var/www/FreshRSS/data
      - freshrss_extensions:/var/www/FreshRSS/extensions

volumes:
  freshrss_data:
  freshrss_extensions:

CRON_MIN включает внутри контейнера cron, который дважды в час (на 3-й и 33-й минуте) дёргает обновление лент — без него ленты будут обновляться только при заходе в веб-интерфейс.

Если планируете десятки лент и несколько пользователей, лучше сразу вынести данные в PostgreSQL — так надёжнее и проще делать бэкап отдельно от файлов:

services:
  db:
    image: postgres:16-alpine
    container_name: freshrss-db
    restart: unless-stopped
    environment:
      POSTGRES_USER: freshrss
      POSTGRES_PASSWORD: сгенерируйте_свой_пароль
      POSTGRES_DB: freshrss
    volumes:
      - freshrss_db:/var/lib/postgresql/data

  freshrss:
    image: freshrss/freshrss:latest
    container_name: freshrss
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - "8080:80"
    environment:
      TZ: Europe/Moscow
      CRON_MIN: "3,33"
    volumes:
      - freshrss_data:/var/www/FreshRSS/data
      - freshrss_extensions:/var/www/FreshRSS/extensions

volumes:
  freshrss_db:
  freshrss_data:
  freshrss_extensions:

Контейнер базы данных не публикует порт наружу — FreshRSS обращается к нему по внутреннему имени сервиса db, это имя пригодится на шаге настройки в веб-интерфейсе. Пароль в POSTGRES_PASSWORD замените на свой перед первым запуском — после инициализации базы сменить его без пересоздания volume уже сложнее.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Первый запуск: мастер настройки в браузере

Сохраните нужный вариант файла как docker-compose.yml в отдельной папке на сервере и запустите:

docker compose up -d
docker compose logs -f freshrss

Через несколько секунд контейнер должен перейти в статус healthy. Открываете http://IP-сервера:8080 — попадаете в мастер установки FreshRSS. Он спрашивает:

  1. Язык — выбирайте русский или английский, интерфейс потом можно переключить в настройках.
  2. Тип хранилища. Для варианта с SQLite просто соглашайтесь с предложенным по умолчанию. Для варианта с Postgres выбирайте PostgreSQL и указывайте хост db, имя базы, пользователя и пароль — те же значения, что задали в POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB.
  3. Администратор — логин и пароль первого пользователя.
  4. Часовой пояс и заголовок сайта.

После завершения мастера сразу заходите в Настройки → Профиль → Подключиться через API и включаете API — без этого мобильные клиенты работать не будут (об этом — ниже).

Если тестируете локально без домена, на этом этапе всё уже работает. Для боевого использования — с телефона, из другого клиента, из дома и с работы — нужен нормальный домен и HTTPS, дальше про это.

Домен и SSL: reverse-proxy перед контейнером

Открывать FreshRSS по IP и порту 8080 без шифрования — плохая идея: логин и пароль будут уходить в открытом виде. Проще всего поставить перед контейнером Caddy — он сам получает и продлевает сертификат Let's Encrypt.

Минимальный Caddyfile:

rss.ваш-домен.ru {
    reverse_proxy freshrss:80
}

Если Caddy запущен в том же docker-compose-проекте, что и FreshRSS, достаточно завести их в одной сети и обращаться по имени сервиса, как в примере выше; если Caddy живёт отдельно — используйте reverse_proxy IP-сервера:8080 и настройте DNS A-записью на этот же сервер. Подробный разбор установки и частых проблем с сертификатами — в статье про установку Caddy с авто-SSL на VPS; там же — что делать, если сертификат не выдаётся из-за занятого 80-го порта или неправильной DNS-записи.

После того как домен поднялся по HTTPS, зайдите в Настройки FreshRSS → Профиль и укажите итоговый https://rss.ваш-домен.ru как базовый URL — это важно для корректной работы API у мобильных клиентов, иначе они будут пытаться достучаться до внутреннего адреса контейнера.

Подключение мобильных и десктопных клиентов через API

Главное преимущество FreshRSS над самописными читалками — совместимость с чужими API. В настройках профиля включаете:

  • Google Reader API — под него заточено больше всего клиентов: Fluent Reader (Windows/macOS/Linux), ReadYou и FocusReader (Android), NetNewsWire на части версий.
  • Fever API — исторически поддерживается Reeder (iOS/macOS) и некоторыми Android-клиентами.

При подключении клиента указываете:

  • адрес сервера — тот самый https://rss.ваш-домен.ru/api/greader.php (для Google Reader API) или https://rss.ваш-домен.ru/api/fever.php (для Fever);
  • логин FreshRSS;
  • API-пароль, отдельный от обычного пароля входа — генерируется в том же разделе настроек профиля, где включали API.

Если клиент пишет «не удаётся подключиться» — почти всегда причина в том, что базовый URL в настройках FreshRSS не совпадает с реальным адресом (например, остался http://localhost), либо API просто не включён для конкретного протокола.

Автообновление лент, бэкап и обновление образа

CRON_MIN в примерах выше уже настроил регулярное обновление лент — раз в полчаса этого достаточно для большинства источников, для новостных сайтов можно поставить более частые минуты через запятую, например "0,15,30,45".

Бэкап для варианта с SQLite — это volume freshrss_data, для варианта с Postgres — volume freshrss_db плюс freshrss_data (в нём тоже лежат кэш иконок и часть настроек). Дамп базы вручную:

docker compose exec db pg_dump -U freshrss freshrss > freshrss-backup-$(date +%F).sql

Общий подход к резервному копированию именно docker-томов — с ротацией и переносом на другой сервер — разобран в статье про бэкап docker volume; там же — типичные ошибки вроде бэкапа «на горячую» без остановки записи.

Обновление образа — обычные для Compose два шага:

docker compose pull
docker compose up -d

FreshRSS сам применяет миграции базы при старте новой версии, поэтому дополнительных действий обычно не требуется — но перед обновлением на новую мажорную версию лишний раз сделать дамп базы не помешает. Если не хотите следить за обновлениями руками, автоматизировать это можно через Watchtower — как его настроить и на что обратить внимание (например, чтобы не обновить контейнер базы данных на несовместимую мажорную версию), написано в статье про автообновление контейнеров Watchtower.

Если Docker для вас не обязателен и хочется классическую установку пакетами прямо в систему — с nginx, php-fpm и системным cron — такой вариант тоже есть, он разобран в статье про установку FreshRSS на Ubuntu 24.04 без контейнеров; плюс в предсказуемости обновлений системы целиком, минус — больше ручной настройки зависимостей.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Сколько ресурсов сервера нужно FreshRSS?

Для личного использования с несколькими десятками лент хватает 1 vCPU и 512 МБ–1 ГБ RAM даже с вариантом на SQLite. PostgreSQL добавляет постоянное потребление памяти под сам процесс базы — закладывайте на связку в целом от 1 ГБ RAM.

Можно ли перенести ленты из Feedly или Inoreader?

Да, через OPML: экспортируете список подписок из старого сервиса файлом .opml, в FreshRSS — раздел «Управление подписками» → «Импорт/экспорт» → загружаете файл. Прочитанные статьи и история при этом не переносятся, только сам список источников.

FreshRSS сам ходит на сайты источников или мне нужен отдельный краулер?

Сам — по расписанию из CRON_MIN внутри контейнера или при ручном обновлении в интерфейсе. Отдельный сервис не нужен.

Что делать, если сайт-источник отдаёт RSS с ошибками или блокирует запросы сервера?

Такое встречается редко, но случается — некоторые сайты блокируют по User-Agent или IP-диапазону дата-центров. В большинстве случаев проблема решается сменой региона сервера или обращением к владельцу сайта; специфику конкретного фида FreshRSS не обходит автоматически.

Нужен ли отдельный домен именно под RSS-читалку?

Не обязательно — можно использовать поддомен (rss.ваш-домен.ru) на том же сервере, где крутятся другие сервисы за тем же reverse-proxy, как показано выше с Caddy.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →