Alternativas self-hosted ao Firecrawl para um VPS
Compare Draco, Hound e Firecrawl self-hosted por RAM, uso de navegador headless e compatibilidade de API. Instale uma versao fixada e conecte MCP.
O que uma alternativa self-hosted ao Firecrawl tem de fazer
Uma alternativa self-hosted ao Firecrawl tem uma tarefa: receber um URL e devolver a página em Markdown limpo, que um agente consiga ler. As APIs alojadas cobram por página. Por isso, o custo aumenta à medida que o agente faz mais consultas. Um VPS que já paga pode fazer o mesmo trabalho. Os projetos diferem numa questão: é necessário iniciar no seu servidor um navegador headless (um motor de navegador real executado sem janela)?
Essa resposta determina o consumo de memória, o custo de cada página e quais páginas são devolvidas vazias. Este guia compara Draco, Hound e a versão self-hosted do Firecrawl, instala a opção mais leve numa versão fixada e liga-a a um agente através de MCP (model context protocol).
Os quatro projetos e o que cada um é na prática
Draco é um único binário, escrito em Rust e licenciado ao abrigo das licenças MIT ou Apache-2.0. A versão v0.20.5 foi publicada em 16 July 2026. draco scrape <url> imprime markdown em stdout. draco serve executa um daemon que responde em 127.0.0.1:3002, a porta usada pelo Firecrawl. Não fornece uma imagem de contentor e não inicia nenhum browser.
Firecrawl self-hosted é o motor por trás do produto alojado, ao abrigo da licença AGPL-3.0. O respetivo docker-compose.yaml define sete serviços: playwright-service, api, redis, rabbitmq, nuq-postgres, foundationdb e foundationdb-init. Obtém a fila de crawling real, mas tem de executar um pequeno sistema distribuído.
Hound está no repositório master-fetch e é distribuído no PyPI como hound-mcp. Usa a licença MIT e, em 3 August 2026, estava na versão 13.0.1. Requer Python 3.11 ou posterior. É primeiro um servidor MCP e depois um fetcher: tenta usar HTTP simples e só inicia um browser Patchright quando a obtenção simples é bloqueada.
Trawl é incluído porque aparece nas pesquisas pelos outros projetos, mas executa uma função diferente. Resolve desafios JavaScript e CAPTCHAs com um Firefox modificado ao nível da fingerprint, como substituto do FlareSolverr numa stack multimédia *arr. Não é um extrator de markdown. A secção sobre utilização responsável abaixo explica por que motivo esta distinção determina se ele pertence sequer à stack do seu agente.
Por que o conjunto de browsers é onde VPS pequenos começam a falhar
Cada separador aberto do browser é um processo renderer separado, que mantém o seu próprio DOM (document object model) e o seu próprio heap JavaScript. Por isso, o consumo de memória aumenta com o número de páginas abertas ao mesmo tempo, não com o número de páginas consultadas por dia. Dois destes projetos registam esse custo nos próprios ficheiros compose.
The data behind this chart
[
{
"label": "Firecrawl api",
"memory_limit_gb": 8
},
{
"label": "Firecrawl playwright",
"memory_limit_gb": 4
},
{
"label": "Hound (browser included)",
"memory_limit_gb": 3
}
]O ficheiro compose do Firecrawl limita o contentor api a 8 GB e o contentor Playwright a 4 GB, com limites de swap correspondentes. O compose do Hound define 3 GB para um único contentor que inclui um Chromium integrado. Estes são limites máximos escolhidos pelos projetos e valores publicados, não medições de um sistema em repouso. Redis, RabbitMQ, PostgreSQL e FoundationDB continuam a precisar da sua parte além dos valores do Firecrawl.
Um limite superior à RAM disponível não resolve nada. Quando o servidor fica sem memória, o kernel termina um processo através do out-of-memory killer. Por isso, um contentor desaparece de docker compose ps sem que seja escrito um erro no log da aplicação. Consulte dmesg -T | tail depois de qualquer reinício que não consiga explicar. Reserve 8 GB para a stack completa do Firecrawl e considere 4 GB o mínimo para um servidor de testes. A definição dos valores por serviço é explicada em limites de memória no Docker Compose.
Há outro detalhe do browser que pode consumir uma noite de diagnóstico. O Docker atribui 64 MB de memória partilhada a um contentor em /dev/shm, e o Chromium coloca aí os buffers dos processos renderer. Em páginas pesadas, isto provoca falhas. As duas stacks de browser aumentam esse valor. O compose do Hound inclui shm_size: "1gb". Copie essa linha para qualquer imagem que crie em torno do Playwright.
Qualidade da extração em páginas com muito JavaScript
Em HTML estático, como num blog renderizado no servidor, numa página de documentação ou num artigo de notícias, todos estes casos devolvem Markdown quase idêntico, e a opção mais rápida vence. A diferença surge nas páginas renderizadas no cliente, em que o HTML entregue é apenas uma estrutura vazia e o texto chega através de JavaScript depois do carregamento.
O Draco aumenta o nível de execução por etapas. Os níveis 0 e 1 analisam o HTML sem executar JavaScript. O nível 2 executa o JavaScript da própria página dentro de um isolate V8 no mesmo processo. Trata-se do motor JavaScript sem um navegador à sua volta, e o README informa que o código da página não recebe bindings de capacidades do host nesse ambiente. Isto abrange muitas aplicações de página única com uma fração da memória de um navegador. Quando o Draco encontra um bloqueio que não consegue ultrapassar, draco scrape termina com o código 3, needs_browser. Verifique este caso nos scripts, porque um ficheiro vazio com código de saída 0 é uma falha que corrompe silenciosamente o contexto de um agente:
draco scrape https://example.com > page.md
echo "exit=$?"O playwright-service do Firecrawl controla um Chromium real, por isso renderiza o que um navegador renderiza. A versão self-hosted continua a não ser o produto alojado: a documentação informa que as instâncias self-hosted não têm acesso ao Fire Engine. Por isso, não incluem os mecanismos anti-bloqueio nem a rotação de IP do serviço cloud, e os endpoints /agent e /browser não são suportados. O Hound fica deliberadamente entre estas opções. Faz as requisições por HTTP e aumenta o nível de execução conforme cada pedido. O seu navegador ativo encerra depois de um período de inatividade, por isso um servidor sem atividade mantém-se próximo do consumo normal.
Instale o Draco com uma versão fixada
O README documenta um instalador de uma linha. Leia o que ele faz antes de o encaminhar para uma shell: instala em $HOME/.draco/bin/draco, usa sempre a versão latest e não verifica nenhuma assinatura ou hash. Num servidor, fixe a versão e verifique o download.
cd /tmp
curl -fsSLO https://github.com/0xchasercat/draco/releases/download/v0.20.5/draco-linux-x86-64.tar.gz
curl -fsSLO https://github.com/0xchasercat/draco/releases/download/v0.20.5/SHA256SUMS
sha256sum --ignore-missing -c SHA256SUMSIsto imprime draco-linux-x86-64.tar.gz: OK. Uma linha FAILED significa que os bytes que tem não são os bytes publicados pelo projeto. Elimine-os e comece novamente.
mkdir -p draco-v0.20.5
tar -xzf draco-linux-x86-64.tar.gz -C draco-v0.20.5
sudo install -m 755 "$(find draco-v0.20.5 -type f -name draco | head -n1)" /usr/local/bin/draco
draco scrape https://example.comO último comando imprime a página de exemplo como markdown em bem menos de um segundo. O find não é decorativo: a estrutura do arquivo não faz parte do contrato público do projeto, e o instalador oficial localiza o binário da mesma forma.
Execute o daemon com a sua própria conta, em vez de usar o utilizador com que iniciou sessão. Escreva /etc/systemd/system/draco.service:
[Unit]
Description=Draco fetch daemon
After=network-online.target
Wants=network-online.target
[Service]
User=draco
ExecStart=/usr/local/bin/draco serve --host 127.0.0.1 --port 3002 --max-concurrency 4
Restart=on-failure
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
[Install]
WantedBy=multi-user.targetsudo useradd --system --no-create-home --shell /usr/sbin/nologin draco
sudo systemctl daemon-reload
sudo systemctl enable --now draco
curl -s http://127.0.0.1:3002/health/health responde assim que o daemon está a escutar. Connection refused significa que não está, por isso leia journalctl -u draco -n 50. A causa habitual é outro processo já estar a utilizar a porta 3002, porque essa também é a porta predefinida do Firecrawl, e --port altera uma delas. Para mais informações sobre unit files: unit files e timers do systemd.
Agora faça o fetch da forma como o seu agente fará:
curl -X POST http://127.0.0.1:3002/v1/scrape \
-H 'content-type: application/json' \
-d '{"url": "https://example.com", "formats": ["markdown"]}'Mantenha o daemon de fetch fora da Internet pública
Uma API de fetch sem autenticação é um proxy aberto. Qualquer pessoa que consiga alcançar a porta pode fazer o seu servidor solicitar qualquer URL através do seu endereço IP, e a denúncia de abuso será enviada ao seu fornecedor, não a essa pessoa. As flags documentadas de serve do Draco não incluem uma chave de API, portanto a proteção tem de ser feita pela rede. Mantenha o bind predefinido 127.0.0.1 quando o agente executar no mesmo servidor. Quando o agente estiver noutro servidor, coloque ambas as extremidades num túnel privado; uma VPN WireGuard alojada por si é normalmente a opção adequada, e faça o bind ao endereço do túnel em vez de 0.0.0.0. Depois, verifique a partir de outra máquina se o IP público não responde a nada. noções básicas da firewall ufw e contas de utilizador com privilégios mínimos abrangem as duas partes dessa configuração.
O seu código de agente vai mudar? Compatibilidade da API na prática
Draco responde às rotas v1 do Firecrawl: /v1/scrape, /v1/map, /v1/crawl, /v1/batch/scrape e /v1/search, e o README informa que os campos desconhecidos são aceites e ignorados. Um agente que já envia pedidos para /v1/scrape precisa de um novo URL base e de mais nada. Verifique o que mudou do outro lado: a própria página de self-hosting do Firecrawl agora testa com /v2/crawl, e os SDKs atuais usam v2. Por isso, um cliente v2 apontado para o Draco solicita uma rota que o Draco não publica. Teste cada chamada com curl antes de editar o código do agente e leia o corpo JSON em vez de consultar apenas o código de estado, porque é nos nomes dos campos que estas implementações divergem.
Robots.txt, limites de pedidos e o limite que deve respeitar
O Draco lê robots.txt por predefinição, e --ignore-robots desativa esse comportamento. A documentação do Firecrawl indica a mesma predefinição. Mantenha ambos como estão. Depois, defina a sua própria cadência: --delay insere milissegundos entre pedidos e --max-concurrency limita as tarefas paralelas, com 8 como predefinição do daemon. Dois a quatro são mais adequados para uma ligação VPS partilhada e raramente tornam o processo mais lento no geral, porque um site que começa a aplicar limites de pedidos custa mais minutos do que os que a concorrência poupou. Coloque em cache o que obtém, para que uma segunda execução do agente não gere qualquer custo para a origem. Esse também é o item mais barato em controlar quanto um agente de IA lhe custa.
As páginas de desafio são um assunto separado, e o Trawl foi criado precisamente para lidar com Cloudflare Turnstile, reCAPTCHA, hCaptcha e GeeTest. Uma página de desafio é, em termos simples, um site a recusar tráfego automatizado. Contorná-la coloca-o contra os termos de utilização do site e, em alguns locais, contra a lei. Por isso, este guia abrange a infraestrutura de obtenção de dados e termina aí. As mesmas técnicas que ultrapassam uma página de desafio são as que os proprietários dos sites monitorizam e bloqueiam, o que também torna frágil e inadequado qualquer pipeline baseado nelas. Quando uma origem é assim tão importante, procure o respetivo feed RSS, a API pública ou uma exportação em massa. Cada opção é mais barata de executar, e nenhuma deixa de funcionar na semana em que a página de desafio muda.
Conecte-o a um agente através do MCP
MCP (model context protocol) é a interface que um agente utiliza para chamar uma ferramenta. Quais ferramentas chegam efetivamente ao modelo e se este pode chamar uma delas sem lhe pedir autorização primeiro são decisões tomadas num nível superior pelo harness onde o modelo é executado, pelo que colocar o daemon a escutar é apenas metade da configuração. O Draco inclui um servidor MCP no mesmo binário, através de stdio:
{ "mcpServers": { "draco": { "command": "draco", "args": ["mcp"] } } }As ferramentas aparecem então para o agente como draco_scrape, draco_search e o conjunto draco_interact_*. O stdio só funciona quando o processo do agente e o binário estão na mesma máquina, porque o transporte utiliza a entrada padrão desse processo. Para um agente noutro host, o Hound disponibiliza o MCP através de HTTP: hound --http --host 127.0.0.1 --port 8765 publica um endpoint em http://127.0.0.1:8765/mcp, ao qual acede através do túnel. As opções de transporte e os elementos a expor estão descritos em executar servidores MCP numa VPS.
Obter pares com pesquisa. Um agente que só consegue fazer fetch fica à espera que lhe forneça URLs. Adicione uma instância SearXNG de pesquisa self-hosted e ele poderá encontrá-los sozinho, com a mesma estrutura da skill de pesquisa no browser baseada no SearXNG. Depois de o daemon arrancar, torna-se um serviço partilhado por qualquer um dos agentes de IA self-hosted que executar. Se a parte do agente for aquela sobre a qual tem menos certezas, escrever primeiro um pequeno loop de agente à mão torna evidente onde uma ferramenta de fetch é ligada e o que o modelo faz com o markdown que recebe de volta.
FAQ
Preciso de um navegador headless para obter páginas para um agente de IA?
Não para a maioria das páginas. Documentação renderizada no servidor, blogs e artigos de notícias são devolvidos completos com uma simples obtenção HTTP seguida de uma conversão de HTML para Markdown. É isso que o Draco faz nos níveis inferiores, em cerca de 300 ms por página sem navegador, segundo os próprios números do projeto. Um navegador justifica o consumo de memória em aplicações renderizadas no cliente, nas quais o HTML entregue é apenas uma estrutura vazia. O isolamento V8 do Draco cobre grande parte desses casos sem um processo de navegador e termina com o código 3, needs_browser, quando não consegue fazê-lo.
Quanta RAM o Firecrawl self-hosted precisa numa VPS?
O ficheiro compose define um limite de 8 GB para o contentor api e de 4 GB para o contentor Playwright. A mesma stack também inicia Redis, RabbitMQ, PostgreSQL e FoundationDB. Planeie 8 GB. Numa máquina com 2 GB, o kernel termina contentores sob carga através do out-of-memory killer. O primeiro sinal é um contentor reiniciado em docker compose ps, sem informação útil no log da aplicação. Confirme-o com dmesg -T | tail.
O Draco é um substituto direto da API do Firecrawl?
Para os endpoints v1, é próximo. Ele disponibiliza /v1/scrape, /v1/map, /v1/crawl, /v1/batch/scrape e /v1/search. Também ignora os campos de pedido que não conhece. Por isso, um cliente escrito para o Firecrawl v1 normalmente precisa apenas de um novo URL base. Não é o produto alojado. Não existe um pool de proxy gerido por trás dele, e as rotas v2 mais recentes do Firecrawl não fazem parte da interface disponível. Confirme primeiro cada chamada feita pelo seu agente com curl.
O self-hosting de um scraper significa que posso ignorar o robots.txt?
Não. O local onde o código é executado não altera o que um site publicou nem o que os seus termos permitem. O Draco e o Firecrawl respeitam robots.txt por predefinição. A flag de substituição existe para sites que são seus ou para os quais tem autorização escrita para fazer crawling. Os limites de taxa continuam a ser aplicados pelo sistema remoto. Por isso, um --delay moderado, com baixa concorrência, mantém o seu endereço IP operacional. Uma stack que só funciona ao contornar uma página de desafio é uma stack que pode deixar de funcionar sem aviso.