SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-08-27

Draco, Hound hay Firecrawl self-hosted cho VPS?

So sánh Draco, Hound và Firecrawl self-hosted về RAM, headless browser, API và MCP. Cài Draco v0.20.5 cố định, không cần container image hay browser.

Một lựa chọn thay thế Firecrawl tự host phải làm được gì

Một lựa chọn thay thế Firecrawl tự host chỉ có một nhiệm vụ: nhận URL và trả về nội dung trang dưới dạng markdown sạch để agent có thể đọc. Các API hosted tính phí theo từng trang, nên chi phí tăng theo mức độ tìm hiểu của agent. VPS bạn đã trả phí có thể xử lý công việc tương tự. Các project khác nhau ở một câu hỏi: trên máy của bạn có cần khởi động headless browser (browser engine thực chạy mà không mở cửa sổ) hay không?

Câu trả lời này quyết định footprint bộ nhớ, chi phí xử lý từng trang và những trang nào sẽ trả về nội dung rỗng. Hướng dẫn này so sánh Draco, Hound và bản release Firecrawl tự host, cài lựa chọn nhẹ nhất ở một version cố định, rồi kết nối nó với agent qua MCP (model context protocol).

Bốn dự án và bản chất của từng dự án

Draco là một binary duy nhất, được viết bằng Rust và cấp phép theo MIT hoặc Apache-2.0. Bản phát hành v0.20.5 được công bố vào ngày 16 July 2026. draco scrape <url> in markdown ra stdout. draco serve chạy một daemon phản hồi trên 127.0.0.1:3002, là cổng mà Firecrawl sử dụng. Dự án không cung cấp container image và không khởi động browser.

Firecrawl self-hosted là engine đứng sau sản phẩm hosted, được cấp phép theo AGPL-3.0. File docker-compose.yaml định nghĩa 7 service: playwright-service, api, redis, rabbitmq, nuq-postgres, foundationdb và foundationdb-init. Bạn có đầy đủ crawl queue thực tế, nhưng phải vận hành một distributed system nhỏ.

Hound nằm trong repository master-fetch và được phát hành lên PyPI với tên hound-mcp, cấp phép MIT, phiên bản 13.0.1 tính đến ngày 3 August 2026. Hound cần Python 3.11 trở lên. Đây trước hết là một MCP server, sau đó mới là fetcher: nó thử HTTP thuần trước và chỉ khởi động browser Patchright khi lần fetch thuần bị chặn.

Trawl được đề cập ở đây vì người dùng thường gặp nó khi tìm các dự án còn lại, nhưng nó thực hiện một công việc khác. Trawl giải các challenge JavaScript và CAPTCHA bằng Firefox đã patch fingerprint, thay thế cho FlareSolverr trong một media stack *arr. Nó không phải markdown extractor. Phần nói về cách sử dụng có trách nhiệm bên dưới giải thích vì sao điểm khác biệt này quyết định Trawl có phù hợp với agent stack của bạn hay không.

Vì sao browser pool là nơi các VPS nhỏ thường cạn tài nguyên

Mỗi tab browser đang mở là một renderer process riêng, giữ DOM (document object model) và JavaScript heap riêng. Vì vậy, mức dùng memory tăng theo số page mở cùng lúc, không phải theo số page được fetch trong ngày. Hai project này ghi rõ chi phí đó trong file compose của chúng.

ChartMemory ceilings each project sets in its own compose file (GB)
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
  }
]

File compose của Firecrawl giới hạn api container ở 8 GB và Playwright container ở 4 GB, kèm swap limit tương ứng. Compose của Hound đặt giới hạn 3 GB cho một container chứa Chromium tích hợp sẵn. Đây là các mức trần do project tự chọn và công bố, không phải số đo của một system đang nhàn rỗi. Redis, RabbitMQ, PostgreSQL và FoundationDB vẫn cần phần memory riêng ngoài các con số của Firecrawl.

Mức trần cao hơn lượng RAM bạn sở hữu không giúp được gì. Khi máy cạn memory, kernel sẽ kích hoạt out-of-memory killer để kết thúc một process. Vì vậy, container có thể biến mất khỏi docker compose ps mà không có lỗi nào được ghi trong application log. Hãy đọc dmesg -T | tail sau mọi lần restart mà bạn không giải thích được nguyên nhân. Hãy dành 8 GB cho toàn bộ Firecrawl stack và xem 4 GB là mức tối thiểu cho một test box. Cách đặt các con số theo từng service được trình bày trong memory limit trong Docker Compose.

Một chi tiết khác của browser có thể khiến bạn mất cả buổi tối. Docker cấp cho container 64 MB shared memory tại /dev/shm, còn Chromium đặt các renderer buffer ở đó nên sẽ crash khi xử lý page nặng. Cả hai browser stack đều tăng mức này. Compose của Hound có shm_size: "1gb". Hãy copy dòng đó vào mọi image bạn build quanh Playwright.

Chất lượng trích xuất trên các trang phụ thuộc nhiều vào JavaScript

Với HTML tĩnh, blog render phía server, trang tài liệu hoặc bài báo, kết quả markdown gần như giống hệt nhau và công cụ nhanh nhất sẽ thắng. Khác biệt xuất hiện trên các trang render phía client, nơi HTML được gửi đến chỉ là một shell rỗng còn nội dung văn bản được JavaScript tải xuống sau khi trang load.

Draco tăng cấp theo từng tier. Tier 0 và tier 1 parse HTML hoàn toàn không dùng JavaScript. Tier 2 chạy JavaScript của trang bên trong một V8 isolate trong cùng tiến trình. Đây là JavaScript engine không có browser bao quanh, và README nêu rõ code của trang không được cấp các host capability binding trong môi trường đó. Cách này xử lý được nhiều single-page application với mức dùng memory chỉ bằng một phần so với browser. Khi Draco gặp trở ngại không thể vượt qua, draco scrape thoát với exit code 3, needs_browser. Hãy kiểm tra mã này trong các script, vì một file rỗng với exit code 0 là kiểu lỗi âm thầm làm hỏng context của agent:

draco scrape https://example.com > page.md
echo "exit=$?"

playwright-service của Firecrawl điều khiển một Chromium thật, nên nó render đúng những gì browser render. Bản self-hosted vẫn không phải hosted product: tài liệu nêu rõ các instance self-hosted không có quyền truy cập Fire Engine, vì vậy không có tính năng chống block và xoay IP của cloud service, đồng thời các endpoint /agent và /browser không được hỗ trợ. Hound được thiết kế để nằm ở giữa hai cách này. Nó fetch qua HTTP và tăng cấp theo từng request. Browser được giữ nóng sẽ đóng sau một khoảng thời gian không có hoạt động, nên một máy ít tải vẫn duy trì mức tài nguyên gần baseline.

Cài Draco với phiên bản được cố định

README có hướng dẫn cài đặt bằng một dòng lệnh. Hãy đọc nội dung script trước khi pipe nó vào shell: script cài vào $HOME/.draco/bin/draco, luôn lấy bản release latest và không kiểm tra signature hoặc hash. Trên server, hãy cố định phiên bản và xác minh file tải xuống.

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 SHA256SUMS

Lệnh này in ra draco-linux-x86-64.tar.gz: OK. Dòng FAILED có nghĩa là các byte bạn đang giữ không giống các byte mà project đã phát hành. Hãy xóa chúng và thực hiện lại từ đầu.

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.com

Lệnh cuối in trang ví dụ dưới dạng markdown trong thời gian chưa đến một giây. find không phải phần trang trí: layout của archive không thuộc public contract của project, và installer chính thức cũng tìm binary theo cách tương tự.

Chạy daemon bằng account riêng thay vì user đăng nhập của bạn. Tạo /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.target
sudo 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 trả lời ngay khi daemon bắt đầu listening. Connection refused có nghĩa là daemon chưa listening, vì vậy hãy đọc journalctl -u draco -n 50. Nguyên nhân thường gặp là một process khác đang giữ cổng 3002, vì đây cũng là cổng mặc định của Firecrawl; --port sẽ đổi cổng của một trong hai process. Xem chi tiết hơn về unit file: systemd service unit và timer.

Bây giờ hãy fetch theo cách agent của bạn sẽ dùng:

curl -X POST http://127.0.0.1:3002/v1/scrape \
  -H 'content-type: application/json' \
  -d '{"url": "https://example.com", "formats": ["markdown"]}'

Tắt fetch daemon khỏi Internet công cộng

Fetch API không có authentication là một open proxy. Bất kỳ ai truy cập được cổng này đều có thể khiến server của bạn request bất kỳ URL nào dưới IP của bạn. Báo cáo abuse sẽ được gửi đến nhà cung cấp của bạn, không phải người thực hiện hành vi đó. Các serve flags được Draco ghi nhận không bao gồm API key, nên network phải đảm nhiệm việc bảo vệ. Giữ bind mặc định 127.0.0.1 khi agent chạy trên cùng máy. Khi agent chạy ở nơi khác, hãy đặt hai đầu trên một private tunnel. WireGuard VPN tự host thường là lựa chọn phù hợp. Bind vào địa chỉ của tunnel thay vì 0.0.0.0. Sau đó, dùng một máy khác để kiểm tra rằng public IP không trả lời gì. Kiến thức cơ bản về ufw firewall và tài khoản user với least privilege bao quát hai phần của việc này.

Agent của bạn có phải thay đổi code không? Tính tương thích API trong thực tế

Draco đáp ứng các route v1 của Firecrawl: /v1/scrape, /v1/map, /v1/crawl, /v1/batch/scrape và /v1/search, đồng thời README của Draco nêu rõ rằng các field không xác định sẽ được chấp nhận và bỏ qua. Agent đã gửi request đến /v1/scrape chỉ cần base URL mới, không cần thay đổi gì khác. Hãy chú ý phần đã thay đổi ở phía bên kia: trang self-hosting của Firecrawl hiện kiểm tra bằng /v2/crawl, còn các SDK hiện tại sử dụng v2. Vì vậy, client v2 trỏ đến Draco sẽ yêu cầu một route mà Draco không cung cấp. Hãy kiểm tra từng request bằng curl trước khi sửa code của agent. Đọc cả JSON body, không chỉ status code, vì tên field là điểm khác nhau giữa các implementation này.

Robots.txt, giới hạn tốc độ và ranh giới không nên vượt qua

Draco đọc robots.txt theo mặc định, còn --ignore-robots sẽ tắt tùy chọn đó. Tài liệu của Firecrawl cũng ghi cùng mặc định này. Hãy giữ nguyên cả hai. Sau đó tự đặt tốc độ: --delay chèn số mili giây giữa các request, còn --max-concurrency giới hạn số job chạy song song, với 8 là mặc định của daemon. Đặt từ 2 đến 4 sẽ ít gây ảnh hưởng hơn trên đường truyền VPS dùng chung và hiếm khi chậm hơn về tổng thể, vì một website bắt đầu rate limit bạn sẽ làm mất nhiều phút hơn số thời gian tiết kiệm được nhờ chạy đồng thời. Hãy cache dữ liệu đã fetch để lần chạy thứ hai của agent không tạo thêm tải cho nguồn. Đây cũng là khoản rẻ nhất trong kiểm soát chi phí của AI agent.

Challenge wall là một chủ đề riêng, và Trawl được xây dựng chính xác cho việc đó: Cloudflare Turnstile, reCAPTCHA, hCaptcha và GeeTest. Challenge wall là khi một website từ chối network traffic tự động một cách rõ ràng. Việc vượt qua challenge wall có thể vi phạm điều khoản sử dụng của website và ở một số nơi còn vi phạm pháp luật, nên hướng dẫn này chỉ đề cập đến hạ tầng fetch rồi dừng ở đó. Những kỹ thuật vượt qua challenge wall cũng chính là các dấu hiệu mà chủ website theo dõi và chặn, khiến mọi pipeline dựa trên chúng vừa mong manh vừa thiếu tôn trọng. Khi một nguồn quan trọng đến mức đó, hãy tìm RSS feed, public API hoặc bản export hàng loạt của nguồn. Mỗi lựa chọn đều tốn ít tài nguyên hơn để vận hành, và không lựa chọn nào bị hỏng chỉ vì challenge wall thay đổi trong tuần đó.

Kết nối với agent qua MCP

MCP (model context protocol) là interface mà agent dùng để gọi tool. Việc tool nào được đưa đến model và model có được phép gọi tool đó mà không hỏi bạn trước hay không được quyết định ở cấp cao hơn bởi harness chạy model bên trong nó, vì vậy để daemon listening mới chỉ hoàn tất một nửa cấu hình kết nối. Draco tích hợp sẵn một MCP server trong cùng binary và giao tiếp qua stdio:

{ "mcpServers": { "draco": { "command": "draco", "args": ["mcp"] } } }

Các tool sau đó xuất hiện với agent dưới dạng draco_scrape, draco_search và bộ draco_interact_*. Stdio chỉ hoạt động khi tiến trình agent và binary nằm trên cùng một máy, vì transport sử dụng standard input của tiến trình đó. Với agent chạy trên host khác, Hound phục vụ MCP qua HTTP: hound --http --host 127.0.0.1 --port 8765 công bố một endpoint tại http://127.0.0.1:8765/mcp, và bạn truy cập endpoint này qua tunnel. Các lựa chọn transport và nội dung nên expose được trình bày trong chạy MCP server trên VPS.

Kết hợp fetch với search. Agent chỉ có khả năng fetch sẽ phải chờ bạn cung cấp URL. Thêm một search instance SearXNG tự host để agent tự tìm URL, theo cùng mô hình với skill browser search xây dựng trên SearXNG. Khi daemon đã chạy, đây là một service dùng chung cho bất kỳ agent nào trong số các AI agent tự host mà bạn chạy. Nếu phần agent là phần bạn chưa chắc nhất, tự viết một agent loop nhỏ trước sẽ giúp bạn thấy rõ fetch tool được gắn vào đâu và model xử lý markdown nhận được như thế nào.

FAQ

Tôi có cần headless browser để tải trang cho AI agent không?

Không cần với phần lớn trang. Tài liệu, blog và bài báo được render ở server thường trả về đầy đủ khi dùng HTTP fetch thông thường kết hợp với bước chuyển HTML sang markdown. Đây là cách Draco hoạt động ở các tier thấp hơn, với thời gian khoảng 300 ms mỗi trang và không cần browser, theo số liệu của dự án. Browser chỉ đáng dùng với các ứng dụng render ở client, nơi HTML được trả về chỉ là shell rỗng. V8 isolate của Draco xử lý được phần lớn trường hợp trung gian này mà không cần tiến trình browser. Khi không xử lý được, nó thoát với code 3, needs_browser.

Self-hosted Firecrawl cần bao nhiêu RAM trên VPS?

File compose đặt giới hạn 8 GB cho api container và 4 GB cho Playwright container. Cùng stack đó cũng khởi động Redis, RabbitMQ, PostgreSQL và FoundationDB. Hãy chuẩn bị 8 GB. Trên máy 2 GB, kernel out-of-memory killer sẽ xóa các container khi tải tăng. Dấu hiệu đầu tiên là container được restart trong docker compose ps nhưng application log không có thông tin hữu ích. Hãy xác nhận bằng dmesg -T | tail.

Draco có phải là bản thay thế drop-in cho Firecrawl API không?

Với các endpoint v1, Draco khá tương thích. Nó cung cấp /v1/scrape, /v1/map, /v1/crawl, /v1/batch/scrape và /v1/search. Nó bỏ qua các request field không nhận biết, vì vậy client được viết cho Firecrawl v1 thường chỉ cần đổi base URL. Draco không phải hosted product. Nó không có managed proxy pool phía sau, và các route v2 mới hơn của Firecrawl không nằm trong surface này. Trước tiên, hãy xác minh từng call mà agent của bạn thực hiện bằng curl.

Self-hosting scraper có nghĩa là tôi có thể bỏ qua robots.txt không?

Không. Code chạy ở đâu không thay đổi nội dung site đã công bố hoặc những gì điều khoản của site cho phép. Draco và Firecrawl đều mặc định tuân thủ robots.txt. Override flag chỉ dành cho các site bạn sở hữu hoặc đã có văn bản cho phép crawl. Rate limit vẫn được áp dụng ở phía máy chủ đích, vì vậy một --delay lịch sự với concurrency thấp sẽ giúp IP address của bạn tiếp tục hoạt động. Một stack chỉ hoạt động khi vượt qua challenge wall là một stack có thể hỏng mà không cảnh báo.