Команда инженеров · свой ЦОД в РФ · своё железо · своя панель · CloudStack + Linstor · MCP · база знаний по self-hosted
Наблюдаемость и аудит

Changedetection.io

Монитор изменений веб-страниц на своем сервере: по расписанию забирает страницу, сравнивает с прошлым снимком и шлет сигнал в Telegram, почту или webhook. Главный сценарий - цены и наличие товара у конкурентов, проверки идут с российского IP. Стенд - Fatmetal Cloud Server, версия 0.60.6 с контейнером Chrome.

Сентябрь 2026 ~13 минут чтения Fatmetal Team
Наблюдаемость и аудит Лицензия: Apache 2.0 Статус: запущен у нас, v0.60.6

Вердикт

Подходит
  • магазину и прайс-аналитику: цены и наличие у конкурентов без лимита на число страниц и проверок
  • тендерному и юридическому отделу: страницы закупок, реестров и оферт там, где нет RSS и рассылки
  • девопсу: дефейс своих сайтов, changelog зависимостей и advisories - рядом с Uptime Kuma
Не подходит
  • команде, которой нужны отдельные логины и роли: пароль один на всю инсталляцию
  • кому нужен гарантированный обход антибота Ozon и Wildberries - его не дает ни SaaS, ни self-host
  • кому нужен аптайм-мониторинг: это Uptime Kuma, здесь следят за содержимым страницы
Мин. тариф: CPU2-RAM4-DISK50 Рекомендуем: CPU2-RAM4-DISK50 Сложность: easy RAM в простое: ~95 МиБ на оба контейнера Главный риск: открытый UI до установки пароля - закрывается переменной SALTED_PASS Прод-готовность: с оговорками (Caddy + TLS + пароль через env)
Что это

Что это и какую задачу решает

changedetection.io отвечает на вопрос «что на странице поменялось»: по расписанию забирает URL, приводит HTML к тексту, сравнивает с прошлым снимком и при разнице шлет уведомление. Это не аптайм-мониторинг, а отслеживание изменений на сайте - в том числе на чужом.

Из коробки - фильтры CSS, XPath, JSONPath и jq, триггеры по тексту, регулярки, diff по строкам и словам, расписание с таймзоной и условные правила. Уведомления идут через Apprise: Telegram, email, Discord, Slack, ntfy, webhook - больше 85 каналов.

Фетчера два. Быстрый HTTP без JavaScript встроен в приложение, а настоящий Chrome живет в отдельном контейнере. Только с Chrome работают Visual Selector (выделить нужный блок мышкой), Browser Steps (логин и клики перед проверкой) и скриншоты в уведомлении.

Проект держит один автор: 34 204 звезды на GitHub, версии 0.60.2-0.60.6 вышли за две недели сентября 2026. Интерфейс переведен на 17 языков, русский есть.

PythonFlaskPlaywrightChrome (sockpuppetbrowser)AppriseDocker Compose
Diff между двумя проверками страницы в changedetection.io: удаленные строки подсвечены красным, добавленные зеленым
Diff между двумя проверками: что ушло, что добавилось. changedetection.io 0.60.6, стенд CPU2-RAM4-DISK50.
Главный сценарий

Уведомление о снижении цены: свой бот для отслеживания цен

Режим «цена и наличие» встроен в продукт, Telegram-бот делается за минуту, а проверки идут с российского IP.

Режим «Re-stock & Price detection» включается на карточке наблюдения. Продукт вытаскивает цену и статус наличия из микроразметки товарной страницы и дальше сравнивает не текст, а числа и флаг «в наличии».

Условия задаются там же: «цена ниже 5 000», «упала на 10 %», «товар появился». Пока условие не выполнено, уведомлений нет - список из 200 страниц конкурентов не превращается в шум.

Уведомление - одна строка Apprise вида tgram://токен-бота/chat_id. Бота создают через BotFather, между вашим сервером и вашим телефоном нет ни одного чужого сервиса, а число проверок не ограничено ничем, кроме ресурсов VM.

Про российский IP. Visualping, Distill и облако самого вендора ходят на сайты из-за рубежа: часть российских магазинов отдает им другой контент или режет запрос. Своя VM в РФ снимает это одним фактом - такого аргумента нет ни у одного SaaS.

Маркетплейсы - отдельная история. Ozon и Wildberries держат антибот, который может резать и headless Chrome; на стенде их не проверяли, поэтому не обещаем. Продукт штатно умеет прокси на каждую проверку (Settings, вкладка CAPTCHA & Proxies, или файл proxies.json) - туда подключают Bright Data, Oxylabs или свой список. Обычные интернет-магазины и сайты конкурентов антибота, как правило, не держат.

Форма настройки наблюдения в changedetection.io: вкладки Request, Visual Filter Selector, AI-LLM, Filters and Triggers, Conditions, Notifications
Настройка наблюдения: фетчер, фильтры, условия и каналы уведомлений - все на одной форме. 0.60.6.
Сравнение

Чем отличается от платных аналогов

Цены сняты со страниц вендоров 15 сентября 2026. SaaS продают одну и ту же лестницу: страницы, проверки в месяц, минимальный интервал.

Параметрchangedetection.io на своей VMОблако вендораVisualping / Distill.io
Цена500 ₽/мес за CPU2-RAM4-DISK50, лимитов нет$8.99/мес, до 5 000 URLVisualping $14-350/мес, Distill $15-80/мес
Проверок в месяцсколько потянет VMодин Chrome-раннер на все страницыот 150 до 50 000 по тарифу
Откуда идут проверкис российского IPEU / USA / Torиз-за рубежа
Chrome для JS-сайтовсвой контейнер, до 10 вкладокодин раннер включенв старших тарифах
Пользователи и ролиодин парольодин парольVisualping Business: 5-11 пользователей
ИИ-фильтр «важно / не важно»свой ключ OpenAI, Gemini, Anthropic или Ollamaв подписке с июня 2026у Visualping платно
Список того, за чем следитена вашем сервереу вендорау вендора

Против облака вендора self-host денег не экономит: $8.99 и 500 ₽ - один порядок. Экономия в разы начинается против Visualping и Distill, и растет она с частотой, а не с числом страниц: 50 страниц раз в 15 минут - это ~144 000 проверок в месяц, старший тариф Visualping за $350 дает 50 000.

Под капотом

Тех-стек и архитектура

Python и Flask, один процесс под gunicorn, REST API с OpenAPI-спекой. Базы данных нет: состояние - JSON-файлы и текстовые снимки в каталоге /datastore, это единственный том. После деплоя с двумя demo-наблюдениями каталог занимает 200 КБ.

Второй контейнер - dgtlmoon/sockpuppetbrowser: headless Chrome 153 с протоколом Playwright по WebSocket на порту 3000 внутри docker-сети. Приложение находит его по PLAYWRIGHT_DRIVER_URL; наружу порт не торчит и через reverse proxy не проходит.

Порт приложения в апстрим-compose опубликован только на 127.0.0.1:5000 - снаружи нужен reverse proxy. У нас это Caddy: TLS от Let's Encrypt и одна строка конфига; живые статусы проверок через Socket.IO за ним работают без дополнительных настроек.

Текстовый снимок страницы в changedetection.io с вкладками Text и Screenshot
Снимок страницы после приведения к тексту: именно это сравнивается между проверками. 0.60.6.
Конфигурация

Минимальная конфигурация

Апстрим системных требований не публикует. Ниже - что реально заняли два контейнера.

Официальный минимум RAMне публикуется
Реально в простое, оба контейнера~95 МиБ (127 МиБ после первой проверки через Chrome)
Образы на диске3,4 ГБ (378 + 513 МБ в сжатом виде)
Занято на диске после деплоя5,5 из 48 ГБ
Рекомендуем тарифCPU2-RAM4-DISK50 - 500 ₽/мес
i

Важно: без Chrome приложение уместилось бы и в 2 ГБ. Но каждая JS-проверка - вкладка настоящего браузера, до 10 параллельно, плюс полностраничные скриншоты высотой до 16 000 px. Под такой нагрузкой не мерили; 4 ГБ - запас именно под браузер, а не под приложение.

В маркетплейсе Fatmetal

Не хотите ставить руками?

changedetection.io есть в маркетплейсе Fatmetal - можно не повторять установку из этого разбора вручную. Заказываете сервер, за пару минут получаете рабочий сервис на своем домене, валидный TLS, контейнер Chrome и пароль в файле с доступами.

Рекомендуемая конфигурация:
2 vCPU · 4 ГБ RAM · 50 ГБ NVMe от 450 ₽/мес

Развернуть в 1 клик →
Развертывание

Развертывание на Fatmetal

Базовый путь - Fatmetal Cloud Server + Ubuntu 24.04 + Docker Compose по апстрим-рецепту, сверху Caddy.

  1. Создать VM

    Тариф CPU2-RAM4-DISK50, Ubuntu 24.04. Docker Engine и compose-plugin ставятся из официального apt-репозитория Docker, это около 40 секунд.

  2. Сгенерировать хеш пароля

    Пароль задается до первого старта переменной SALTED_PASS - тот же формат, что и у поля пароля в UI: base64 от 32 байт соли и PBKDF2-HMAC-SHA256 со 100 000 итераций.

    python3 - <<'EOF'
    import base64, hashlib, os, getpass
    pw = getpass.getpass('Пароль UI: ')
    salt = os.urandom(32)
    key = hashlib.pbkdf2_hmac('sha256', pw.encode(), salt, 100000)
    print('SALTED_PASS=' + base64.b64encode(salt + key).decode())
    EOF

    Строку из вывода кладем в .env рядом с compose-файлом.

  3. Собрать docker-compose.yml

    services:
      changedetection:
        image: dgtlmoon/changedetection.io:0.60.6
        container_name: changedetection
        restart: unless-stopped
        ports:
          - 127.0.0.1:5000:5000
        volumes:
          - changedetection-data:/datastore
        environment:
          - SALTED_PASS=${SALTED_PASS}
          - BASE_URL=https://ваш-домен
          - USE_X_SETTINGS=1
          - TZ=Europe/Moscow
          - PLAYWRIGHT_DRIVER_URL=ws://browser-sockpuppet-chrome:3000
        depends_on:
          - browser-sockpuppet-chrome
    
      browser-sockpuppet-chrome:
        image: dgtlmoon/sockpuppetbrowser:latest
        hostname: browser-sockpuppet-chrome
        restart: unless-stopped
        cap_add:
          - SYS_ADMIN
        environment:
          - SCREEN_WIDTH=1920
          - SCREEN_HEIGHT=1024
          - MAX_CONCURRENT_CHROME_PROCESSES=10
    
    volumes:
      changedetection-data:

    Приложение пиним на 0.60.6 (или на ветку 0.60). У браузера тег latest осознанно: нумерованные теги 0.0.x не обновлялись с августа 2025, а latest - от 14 сентября 2026.

  4. Поднять стек

    docker compose pull
    docker compose up -d
    curl -sI http://127.0.0.1:5000/ | head -1   # HTTP/1.1 302 -> /login

    Когда образы в кэше, оба контейнера стартуют за 2,15 с, первый ответ приходит через 2,67 с. Если pull упал по таймауту - повторить, см. «Где может сломаться».

  5. Caddy с TLS

    ваш-домен {
        reverse_proxy 127.0.0.1:5000
    }

    Caddy сам выпустит сертификат Let's Encrypt. Первый запрос сразу после рестарта может упасть с TLS internal error - это гонка с выпуском сертификата, через несколько секунд все отвечает.

  6. Первое наблюдение

    Добавить URL, во вкладке Request выбрать фетчер Playwright/Chrome, если сайт на JavaScript, включить «Re-stock & Price detection» для товарной страницы и нажать Recheck. Скриншот и снимок появятся после первой проверки.

Список наблюдений changedetection.io после первого запуска: два demo-наблюдения, теги, кнопка Recheck all
Главный экран после первого старта: два demo-наблюдения, которые продукт заводит сам. 0.60.6, тариф CPU2-RAM4-DISK50.
Настройка ИИ

ИИ-фильтр шума и ключ модели

Две функции 2026 года. «AI change intent» - правило на человеческом языке: «сообщи, только если цена ниже 5 000 рублей». «AI change summary» - краткий пересказ диффа прямо в уведомлении. Провайдер подключается через LiteLLM: OpenAI, Gemini, Anthropic, Ollama или любой OpenAI-совместимый endpoint.

Ключ вводится в Settings, вкладка AI-LLM, включение - на каждом наблюдении отдельно. Для базовой работы - diff плюс уведомление - ИИ не нужен вовсе, это надстройка для тех, у кого сотни страниц и много ложных срабатываний.

Продукту нужен ключ внешней модели, а из России напрямую до OpenAI и Gemini не достучаться. На VPS Fatmetal это уже решено: обращения к моделям идут через прокси api-proxy.fatmetal.net, он входит в сервер и отдельно не заказывается. Код не меняется - достаточно переменных HTTPS_PROXY, HTTP_PROXY и NO_PROXY в окружении контейнера.

Оговорка именно для этого продукта: те же HTTP_PROXY и HTTPS_PROXY в апстрим-compose описаны как прокси для фетчера страниц. Глобальная переменная уведет через прокси и проверки сайтов, а он рассчитан на API моделей, не на интернет вообще. На стенде ИИ-слой не включали; после включения стоит убедиться, что проверки страниц по-прежнему проходят. Выключается целиком переменной LLM_FEATURES_DISABLED=true.

Глобальные настройки changedetection.io: вкладки Fetching, Global Filters, API, RSS, Backups, CAPTCHA and Proxies, AI-LLM
Глобальные настройки: фетчер по умолчанию, прокси, ключ API, бэкапы и вкладка AI-LLM. 0.60.6.
Замеры

Что измерили после запуска

Стенд: CPU2-RAM4-DISK50, Ubuntu 24.04, Docker 29.8.0, Compose v5.5.1, Caddy 2.11.4. Без нагрузки, сразу после чистого редеплоя.

Скачивание образов (891 МБ сжатых)51,7 с со второй попытки; первая упала через 42,6 с
docker compose up -d2,15 с
Первый HTTP-ответ после команды2,67 с
RAM в простое66,98 МиБ приложение + 27,96 МиБ Chrome = 94,94 МиБ
CPU в простое0,42 % приложение, 0,01 % Chrome
Отклик локально / через Caddy по HTTPS4 мс / 229 мс главная, 87 мс страница входа
Каталог /datastore после деплоя200 КБ
От первого SSH до HTTPS-входа~17 минут, из них ~4 - ожидание Docker Hub
i

Главное: два контейнера в простое держат меньше 100 МиБ - на полтора порядка меньше тарифной ступени в 4 ГБ. Память понадобится не приложению, а Chrome под параллельными JS-проверками, и именно под него взят запас.

Проверено на changedetection.io 0.60.6, сентябрь 2026. На новых версиях результаты могут отличаться.

Подводные камни

Где может сломаться

Грабли, на которые наступили при запуске, и одна ошибка, которая воспроизводится стабильно.

net/http: timeout awaiting response headers

Причина. Транзиентный таймаут Docker Hub на крупном слое образа changedetection.io (около 430 МБ) при скачивании из РФ. Воспроизвелся дважды: при деплое упали три попытки из четырех, при контрольном замере - первая из двух.

Решение. Повторить docker compose pull: скачанные слои остаются в кэше, докачивается только остаток. В скриптах установки закладывать повтор pull как штатный шаг.

!

Открытый UI. Пароля по умолчанию нет, он ставится в Settings после первого входа - между стартом и первым входом инсталляция публична. SALTED_PASS закрывает это окно; переменную читают auth_decorator.py и flask_app.py, формат совпадает с полем в UI.

!

JS-сайты без Chrome. Встроенный фетчер не выполняет JavaScript - магазин на SPA отдаст пустую страницу. В апстрим-compose контейнер браузера закомментирован: включите его и выберите Playwright-фетчер на наблюдении.

!

Скриншот не появляется. Продукт пишет скриншот на диск только при первой проверке или при реальном изменении. Переключили наблюдение с HTTP на Chrome и перепроверили статичную страницу - файла не будет. Создавайте наблюдение сразу с нужным фетчером.

!

Символ @ в логине SMTP. Строка Apprise mailto://user@domain:pass@host ломается: второй @ парсер считает границей учетки, и письмо уходит в пустой хост. Кодируйте @ в логине как %40.

Не только цены

Мониторинг сайта конкурентов и госзакупок: сторож для страницы без RSS

Тот же механизм закрывает любую страницу, у которой нет RSS и рассылки: карточка закупки на zakupki.gov.ru, реестры ФНС, картотека суда, оферта партнера, вакансии и раздел «о компании» у конкурента.

Рецепт один: выделить Visual Selector нужный блок, чтобы не реагировать на баннеры и счетчики, и добавить «trigger text», если важно конкретное слово - «изменения», «отменена», «в наличии».

Госсайты тоже режут иностранные подсети, так что российский IP здесь работает не хуже, чем на магазинах. Для страниц за формой входа есть Browser Steps: логин, клик, ввод - и только потом снимок.

Девопсу: дефейс своих сайтов и страницы advisories с интервалом в минуты, уведомление - в ntfy рядом с алертами Uptime Kuma. Один следит, что сайт жив, другой - что он не изменился. Любое наблюдение отдает RSS, если нужна лента из страницы без ленты.

Безопасность

Безопасность и обновления

Что закрыть перед продом: пароль через SALTED_PASS до первого старта; порт 5000 только на loopback, наружу - Caddy с TLS; BASE_URL и USE_X_SETTINGS=1, иначе ссылки в уведомлениях ведут на localhost. Ключ REST API включен по умолчанию и лежит в Settings, вкладка API.

Пользователей и ролей нет. Если UI нужен нескольким людям, доступ ограничивают на уровне Caddy (basic auth, список IP) или прячут за VPN. Права cap_add: SYS_ADMIN у браузера апстрим сам называет избыточными; на стенде sockpuppetbrowser открывал страницы и без них.

Обновление - пин на минорную ветку: тег 0.60 получает патчи, latest уедет на новую ветку без предупреждения. Релизы и advisories - на GitHub проекта.

docker compose pull && docker compose up -d

Бэкап - один каталог. В Settings есть вкладка Backups с выгрузкой zip, а из консоли достаточно архива тома:

docker run --rm -v changedetection-data:/datastore:ro -v $PWD:/backup alpine \
  tar czf /backup/changedetection-$(date +%F).tgz -C /datastore .
Рядом

Связь с другими стеками

  • Uptime Kuma - отвечает «жив ли сервис»; changedetection.io - «что на странице поменялось». Ставят рядом, а не вместо.
  • ntfy - приемник уведомлений: схема ntfy:// есть в Apprise, пуш на телефон без Telegram и без чужого сервиса.
  • n8n - webhook-уведомление из changedetection.io запускает сценарий: записать цену в таблицу, поставить задачу, сравнить с прайсом.
  • Caddy - reverse proxy с автоматическим TLS перед портом 5000, одна строка конфига.
Ограничения

Когда это НЕ ваш выбор

Нужны отдельные логины и роли

Пароль один на всю инсталляцию, папок и прав нет. Команде из пяти человек с разными зонами ответственности это не подойдет; у Visualping Business есть 5-11 пользователей.

Нужен гарантированный обход антибота маркетплейсов

Ozon и Wildberries могут резать проверки даже через Chrome. Прокси на каждое наблюдение перекладывают риск на вас, но не снимают его; ни один SaaS этого тоже не гарантирует.

Нужен визуальный diff «до / после»

Здесь текстовый diff плюс скриншот текущего состояния. Сравнение двух картинок с подсветкой отличий - это Visualping, и там за него платят.

Вы хотите продавать это клиентам как сервис

Код под Apache 2.0, но в репозитории лежит COMMERCIAL_LICENCE.md: предоставление программы третьим лицам как сервиса вендор требует лицензировать отдельно. На своей VM для своих задач ограничений нет.

FAQ

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

Можно поставить без Docker?

Есть pip-пакет, но Chrome-фетчер все равно живет в отдельном контейнере; единственный путь по апстриму - Docker Compose.

Хватит ли 2 ГБ RAM?

Без Chrome - да: в простое оба контейнера держат ~95 МиБ. С Chrome и параллельными JS-проверками берите 4 ГБ, под нагрузкой не мерили.

Как задать пароль до первого входа?

Переменной SALTED_PASS, скрипт генерации - в разделе про развертывание. UI закрыт с первой секунды жизни контейнера.

Ozon и Wildberries работают?

Не гарантируем: там антибот, на стенде маркетплейсы не проверяли. Обычные интернет-магазины работают штатно, для площадок с защитой есть прокси на каждое наблюдение.

Как слать уведомления в Telegram?

Создать бота через BotFather, вставить строку tgram://токен/chat_id в Notifications и нажать «Send test notification».

Как обновлять?

docker compose pull && docker compose up -d. Держите пин на ветку 0.60 - релизы выходят каждые несколько дней.

Что бэкапить?

Только том /datastore: настройки, история снимков, скриншоты и ключ API. Базы данных нет.

Какие ограничения лицензии?

Apache 2.0, все функции подписки есть в self-host. Коммерческую лицензию вендор требует только за хостинг программы для третьих лиц как сервиса.

Итог

changedetection.io - монитор изменений страниц с режимом «цена и наличие», Chrome для JS-сайтов и уведомлениями в Telegram без чужих сервисов. Два контейнера в простое держат ~95 МиБ, стек стартует за 2,15 с, а проверки идут с российского IP - аргумент, которого нет ни у Visualping, ни у облака вендора. Пароль через SALTED_PASS, Caddy с TLS, пин на ветку 0.60 - и тариф CPU2-RAM4-DISK50 закрывает сотни страниц без лестницы SaaS.

Рекомендуемая конфигурация для установки:
2 vCPU · 4 ГБ RAM · 50 ГБ NVMe

Не хотите устанавливать вручную?

Запустите changedetection.io на этой конфигурации автоматически - от 450 ₽/мес.

Запустить changedetection.io →
Анонсы новых разборов в Telegram-канале Новые гайды и карточки в маркетплейсе первыми @fatmetal_channel →

Этот стек у нас запущен на тарифе CPU2-RAM4-DISK50. Нашли баг в гайде - напишите, поправим в течение дня.