MAATRIX / Блог / Как установить и настроить Firecrawl на VPS

Как установить и настроить Firecrawl на VPS

Как установить и настроить Firecrawl на VPS

MAATRIX

Firecrawl превращает любую веб-страницу в чистый markdown для LLM-агентов и RAG, но облачный тариф считает каждый запрос кредитами, а бесплатная квота заканчивается быстрее, чем начинается проект. Установка Firecrawl на VPS даёт тот же движок в Docker Compose — без лимита запросов, но с собственным стеком из пяти контейнеров и своими заботами о ресурсах. Разберём путь от git clone до первого успешного скрейпа: точные команды, реальные ошибки и честная оценка того, сколько сервера стеку действительно нужно.

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

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

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

Что такое Firecrawl и зачем ставить его на свой сервер

Firecrawl — открытый движок (лицензия AGPL-3.0) для превращения веб-страниц в данные, пригодные для LLM: вместо сырого HTML с меню, баннерами и вёрсткой он отдаёт чистый markdown, plain-текст или структурированный JSON. Проект вырос из Mendable AI, организация на GitHub переименована из mendableai в firecrawl — старые ссылки на github.com/mendableai/firecrawl ведут туда же.

У Firecrawl пять операций. /scrape забирает одну страницу. /map за секунды строит список всех ссылок сайта без скачивания контента — удобно сначала оценить объём. /crawl обходит сайт по ссылкам асинхронно и возвращает страницы пачками по мере готовности. /search ищет в вебе и по желанию скрейпит найденные результаты. /extract вытаскивает структурированные данные по JSON-схеме через LLM — нужен ключ OpenAI или совместимого провайдера.

Типичный потребитель Firecrawl — не человек, а другой сервис: RAG-пайплайн, агент в n8n, дёргающий API как HTTP-узел в сценарии, или MCP-клиент вроде Claude Desktop через официальный firecrawl-mcp-server. Поэтому установка на VPS обычно встаёт как часть более широкого AI-стека.

Главное отличие self-host от облака — не в функциях, а в двух вещах. Приятная: никаких кредитов за запрос, единственный счётчик — ресурсы сервера. Менее приятная: облако включает проприетарный слой обхода антибот-защиты (fire-engine) с ротацией прокси, а self-host по умолчанию ходит на сайты напрямую через обычный Playwright — ресурсы с Cloudflare ответят капчей или 403, и обходить это придётся своим прокси.

Требования к серверу: сколько ядер и памяти просит стек

Полный self-host стек Firecrawl — пять контейнеров: api, playwright-service, redis, rabbitmq, nuq-postgres. Есть опциональный foundationdb — альтернативный backend очереди вместо Postgres+RabbitMQ, но по умолчанию не нужен и для старта только усложняет картину.

КонтейнерОбраз / сборкаПорт наружуРоль
apibuild apps/api3002приём запросов, отдаёт результат
playwright-servicebuild apps/playwright-service-tsтолько внутри сетирендерит JS-страницы
redisredis:alpineтолько внутри сетикэш и рейт-лимиты
rabbitmqrabbitmq:3-managementтолько внутри сетиочередь задач между api и воркерами
nuq-postgresbuild apps/nuq-postgresтолько внутри сетихранит очередь заданий и (опционально) авторизацию

Официальный гайд честно пишет, что проверенный минимальный размер хоста для этого стека не публикуется. Но у самого docker-compose.yaml есть косвенная подсказка: он выставляет api лимит в 4 vCPU / 8 ГБ памяти, а playwright-service — 2 vCPU / 4 ГБ. Это потолок, а не гарантия работы с меньшим, но ориентир честнее случайной цифры из чужого блога.

Из требований — Docker Engine с плагином Compose v2, git, curl и свободный порт 3002. Работаем на Ubuntu 24.04 (Debian подходит без изменений). Порт 3002 в фаервол пока не открываем — решение откладываем до раздела про прод-режим:

apt update && apt upgrade -y
ufw allow 22/tcp && ufw enable

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

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

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

Установка Firecrawl: git clone, .env и docker compose up

Ставим Docker официальным скриптом и проверяем плагин Compose:

curl -fsSL https://get.docker.com | sh
docker compose version

Клонируем репозиторий и фиксируемся на релизном теге, а не на ветке main — так вы не словите недокументированные изменения между релизами:

git clone https://github.com/firecrawl/firecrawl.git
cd firecrawl
git checkout v2.11.0   # актуальный тег смотрите на странице Releases репозитория

Ключевой момент — файл окружения. В корне репозитория нужен свой .env, который читает docker-compose.yaml — это не то же самое, что apps/api/.env.example внутри кода API, использовать его как готовый контракт для Compose не стоит. Минимальный рабочий .env без базы аутентификации:

cat > .env <<'EOF'
USE_DB_AUTHENTICATION=false
POSTGRES_USER=postgres
POSTGRES_PASSWORD=замените-на-32-случайных-символа
POSTGRES_DB=postgres
ALLOW_LOCAL_WEBHOOKS=false
BLOCK_MEDIA=false
EOF

false в последних двух строках написан явно, не оставлен пустым — пустая строка в булевом флаге роняет api при старте, разберём это в разделе про грабли. Пароль Postgres — реальная случайная строка от 32 символов, openssl rand -hex 24 подходит.

Запускаем стек и проверяем, что все контейнеры поднялись:

docker compose up --build -d
docker compose ps

Первая сборка занимает несколько минут — образ playwright-service тянет за собой Chromium. В выводе docker compose ps должно быть пять строк, причём у firecrawl-rabbitmq-1 и firecrawl-nuq-postgres-1 в статусе должно появиться (healthy) — у них есть health-check, и api начинает принимать трафик только после готовности RabbitMQ.

Проверка: health-check и первый запрос к API

Первым делом — liveness-проверка, она не требует авторизации и отвечает быстрее всего:

curl --max-time 5 http://localhost:3002/v0/health/readiness

Ответ {"status":"ok"} значит, что процесс поднялся и слушает порт. Дальше — реальный скрейп одной страницы:

curl -s -X POST http://localhost:3002/v1/scrape \
  -H 'Content-Type: application/json' \
  -d '{"url": "https://example.com", "formats": ["markdown"]}' | jq .

Ожидаемый ответ — JSON вида {"success": true, "data": {"markdown": "...", "metadata": {"statusCode": 200}}}. Заголовок Authorization не нужен: при USE_DB_AUTHENTICATION=false ключи не проверяются вовсе — вернёмся к этому в разделе про прод-режим. У свежих сборок рядом с /v1/scrape появился /v2/scrape с расширенным набором параметров, v1 продолжает работать.

Асинхронный обход сайта проверяется двумя запросами — сначала запускаем job, потом опрашиваем его статус:

JOB=$(curl -s -X POST http://localhost:3002/v1/crawl \
  -H 'Content-Type: application/json' \
  -d '{"url": "https://example.com", "limit": 5}' | jq -r .id)

curl -s http://localhost:3002/v1/crawl/$JOB | jq '{status, pages: (.data | length)}'

Сразу после запуска status будет scraping, затем completed, а pages — число забранных страниц. curl: (7) Failed to connect на первом же запросе значит, что api ещё не поднялся или не прошёл health-check зависимостей; смотрите docker compose logs -f api.

Грабли self-host: NUQ_RABBITMQ_URL, ZodError и pg_cron

Три ошибки, с которыми сталкивается почти каждый при первом запуске стека — все не про Firecrawl как продукт, а про конфигурацию контейнеров.

NUQ_RABBITMQ_URL is not configured. Контейнер api падает сразу при старте, если переменная подключения к очереди не собралась в валидный URL вида amqp://пользователь:пароль@rabbitmq:5672 — она должна ссылаться на те же RABBITMQ_USER/RABBITMQ_PASSWORD, что и сам RabbitMQ. Разошлись в одном месте и забыли синхронизировать в другом — получите эту строку в docker compose logs api.

ZodError на пустой булевой переменной. API парсит .env через схему валидации Zod, и пустая строка в поле, ожидающем true/false (типичные кандидаты — ALLOW_LOCAL_WEBHOOKS и BLOCK_MEDIA), — это не «пусто = false», а ошибка валидации, из-за которой api не стартует вовсе. Лечится как в разделе установки: писать литеральное значение, а не оставлять переменную без него.

pg_cron и exit code 3. Внутри nuq-postgres включено расширение pg_cron, а оно требует shared_preload_libraries=pg_cron и параметр cron.database_name с именем реальной базы. Разошлось с фактическим POSTGRES_DBnuq-postgres завершается кодом выхода 3, а api следом падает с ошибкой очереди: симптом похож на проблему RabbitMQ, хотя корень в Postgres.

Отдельно — решение авторов, не баг: корневой docker-compose.yaml не объявляет постоянные тома для Postgres, Redis и RabbitMQ. Обычный docker compose down, а тем более down -v, стирает очередь и историю job'ов вместе с контейнерами. Для рабочего инструмента именованные тома и бэкапы базы — целиком ваша забота.

Последнее в разделе — не техническая деталь, а юридическая. AGPL-3.0 — лицензия с сетевым copyleft: меняете код и предлагаете изменённую версию как публичный сервис третьим лицам — обязаны открыть изменения. Для внутреннего использования на своём сервере это ограничение не касается.

Прод-режим: домен, авторизация и обновления

По умолчанию API Firecrawl слушает 0.0.0.0:3002 без авторизации — это прямо написано в документации по self-host. Держать порт открытым без защиты — плохая идея: любой в интернете сможет гонять через ваш сервер скрейпы и жечь ресурсы.

Два варианта. Для работы с того же сервера или через n8n/агента в той же docker-сети — не публиковать порт api наружу, держать ufw deny 3002/tcp и обращаться по 127.0.0.1:3002 или по имени контейнера в сети backend. Для доступа снаружи — реверс-прокси (Nginx или Caddy) с TLS перед портом, сам порт пробрасывать только на локальный адрес.

Включить настоящую авторизацию — не то же самое, что поменять флаг. USE_DB_AUTHENTICATION=true подключает выдачу API-ключей поверх Supabase: без SUPABASE_URL, SUPABASE_ANON_TOKEN, SUPABASE_SERVICE_TOKEN и миграции схемы флага недостаточно — «просто включить» не значит «получить рабочую авторизацию». Альтернатива — держать api за своим прокси с проверкой заголовка или ключа на уровне Nginx.

Отдельно защитите админку очереди: BULL_AUTH_KEY открывает панель Bull по адресу /admin/<ваш-ключ>/queues со всеми заданиями. Задайте случайную строку — без ключа UI не поднимется вовсе.

Обновление — это смена тега и пересборка:

git fetch --tags
git checkout v2.12.0
docker compose pull
docker compose up --build -d

Перед переходом на новый тег загляните в его docker-compose.yaml и заметки к релизу — список сервисов и переменных между версиями меняется, а слепой git pull на main регулярно ломает то, что вчера работало.

Стек стабилен — свяжите его с остальным AI-стеком на том же сервере: n8n с AI-агентами дёргает /v1/scrape как обычный HTTP-узел в сценарии, а markdown-результат удобно заливать в векторную базу для RAG или в рабочее пространство AnythingLLM, если он уже стоит рядом.

Какой сервер под Firecrawl брать в MAATRIX

Firecrawl в self-host — не одна программа, а пять контейнеров: очередь, база, кэш и Chromium под капотом Playwright. Экономить на памяти опаснее, чем кажется — не хватит RAM, и первым падёт не самый заметный контейнер, а Postgres или RabbitMQ, а разбираться придётся с непонятным exit code, а не с честным OOM в логах api.

ВариантКонфигурацияДля чего хватает
Минимум4 vCPU, 8 ГБ RAM, 40 ГБ NVMeЛичные обходы, тесты, несколько job'ов подряд — без запаса
Комфортный6–8 vCPU, 16 ГБ RAM, 80–100 ГБ NVMeПараллельные crawl'ы, постоянные тома, бэкапы без тревоги за место

Минимум подобран не произвольно — это потолок, который docker-compose.yaml резервирует под один контейнер api (4 vCPU / 8 ГБ). playwright-service и api формально делят те же четыре ядра, и при параллельных crawl'ах это чувствуется — первым делом стоит опустить NUM_WORKERS_PER_QUEUE с дефолтных 8 до 2–4. Комфортный вариант даёт обоим их лимиты одновременно (4+2 vCPU, 8+4 ГБ) и оставляет память под Redis, RabbitMQ, Postgres и ОС без свопа.

По локации логичнее всего Великобритания. Причина не в блокировках, а в маршруте скрейпов: львиная доля целевых сайтов — европейские и международные ресурсы, и лондонский узел даёт короткий пинг до них и меньше поводов заподозрить «нетипичную» геолокацию запроса. Та же логика для /extract с OPENAI_API_KEY — обращения к OpenAI с британского адреса идут без региональных сюрпризов, подробнее — в статье про прокси к OpenAI через сервер в Великобритании.

Firecrawl не входит в каталог apps.maatrix.io: сервер приходит чистой Ubuntu 24.04 или Debian, весь путь от git clone до docker compose up вы проходите сами. Зато в каталоге есть готовые сборки смежных вещей из того же AI-стека — n8n, Open WebUI, AnythingLLM ставятся при заказе без единой команды, а Firecrawl связываете с ними уже после, через API. Оформить сервер можно на странице аренды VPS: тариф и локация — на месте, оплата картой российского банка, по СБП, криптовалютой или токеном MAAT.

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

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

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

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

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

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

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

Нужен ли API-ключ, чтобы обращаться к self-hosted Firecrawl?

По умолчанию нет: при USE_DB_AUTHENTICATION=false запросы на порт 3002 идут без заголовка Authorization. Это нормально, пока порт закрыт файрволом; для настоящей авторизации нужен не только флаг true, но и подключённый Supabase (SUPABASE_URL, SUPABASE_ANON_TOKEN, SUPABASE_SERVICE_TOKEN).

Чем self-host хуже облачного Firecrawl?

Двумя вещами: нет антибот-слоя fire-engine с ротацией прокси (сайты за Cloudflare обходите своим PROXY_SERVER или ScrapingBee), и нет постоянных томов — без вашей настройки очередь и история job'ов не переживут docker compose down.

Сколько сервера реально нужно под self-host Firecrawl?

Официальный гайд не публикует минимум, но сам docker-compose.yaml ограничивает api 4 vCPU/8 ГБ, а playwright-service — 2 vCPU/4 ГБ. На практике 4 vCPU/8 ГБ — рабочий, но впритык минимум, 6–8 vCPU/16 ГБ — комфортный запас.

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

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