بهترین جایگزینهای self-hosted برای Firecrawl روی VPS
مقایسه فنی Draco، Hound و نسخه self-hosted از Firecrawl برای تبدیل وب به Markdown. بررسی مصرف RAM، نیاز به headless browser و نحوه اتصال به MCP برای ایجنتها.
الزامات یک جایگزین self-hosted برای Firecrawl
یک جایگزین self-hosted برای Firecrawl تنها یک وظیفه دارد: دریافت یک URL و بازگرداندن محتوای صفحه به صورت markdown تمیز که برای یک agent قابل خواندن باشد. APIهای میزبانیشده (hosted) به ازای هر صفحه هزینه دریافت میکنند، بنابراین با افزایش کنجکاوی agent شما، صورتحساب نیز افزایش مییابد؛ در حالی که یک VPS که از قبل هزینهاش را پرداخت کردهاید، میتواند همان کار را انجام دهد. پروژهها بر سر یک پرسش اصلی تقسیم میشوند: آیا یک headless browser (موتور مرورگر واقعی که بدون پنجره اجرا میشود) باید روی سرور شما اجرا شود؟
پاسخ به این پرسش، میزان مصرف حافظه، هزینه هر صفحه و اینکه کدام صفحات به صورت خالی بازگردانده میشوند را تعیین میکند. این راهنما پروژههای Draco، Hound و نسخه self-hosted از Firecrawl را مقایسه کرده، سبکترین آنها را در یک نسخه ثابت (pinned version) نصب میکند و آن را از طریق MCP (پروتکل مدل کانتکست) به یک agent متصل مینماید.
چهار پروژه و ماهیت واقعی هر یک
Draco یک باینری است که با زبان Rust نوشته شده و تحت مجوز MIT یا Apache-2.0 منتشر میشود. نسخه v0.20.5 در تاریخ 16 July 2026 منتشر شد. draco scrape <url> خروجی مارکداون را در stdout چاپ میکند. draco serve یک دیمون را اجرا میکند که روی 127.0.0.1:3002، یعنی همان پورتی که Firecrawl استفاده میکند، پاسخ میدهد. این پروژه هیچ image کانتینری ارائه نمیدهد و هیچ مرورگری را اجرا نمیکند.
Firecrawl self-hosted موتور اصلی محصول میزبانیشده است که تحت مجوز AGPL-3.0 قرار دارد. فایل docker-compose.yaml آن هفت سرویس را تعریف میکند: playwright-service، api، redis، rabbitmq، nuq-postgres، foundationdb و foundationdb-init. شما در ازای اجرای یک سیستم توزیعشدهٔ کوچک، به صف واقعی خزش (crawl queue) دسترسی پیدا میکنید.
Hound در مخزن master-fetch قرار دارد و به عنوان hound-mcp در PyPI منتشر میشود؛ این پروژه تحت مجوز MIT است و نسخه 13.0.1 آن در تاریخ 3 August 2026 عرضه شده است. این ابزار به Python 3.11 یا جدیدتر نیاز دارد. Hound در درجه اول یک سرور MCP و در درجه دوم یک ابزار دریافتکننده (fetcher) است: ابتدا HTTP ساده را امتحان میکند و تنها زمانی که دریافت ساده مسدود شود، یک مرورگر Patchright را اجرا میکند.
Trawl به این دلیل در اینجا ذکر شده که کاربران هنگام جستجو برای سایر پروژهها با آن مواجه میشوند، اما وظیفه متفاوتی دارد. این ابزار چالشهای جاوااسکریپت و CAPTCHAها را با استفاده از یک مرورگر Firefox که اثر انگشت (fingerprint) آن تغییر یافته حل میکند و جایگزینی برای FlareSolverr در یک استک رسانهای *arr محسوب میشود. این ابزار یک استخراجکننده مارکداون نیست. بخش مربوط به آداب استفاده در ادامه توضیح میدهد که چرا این تفاوت تعیین میکند که آیا این ابزار اصلاً در استک عامل (agent stack) شما جایگاهی دارد یا خیر.
چرا استخر مرورگر عامل اصلی شکست VPSهای کوچک است
هر تب باز مرورگر یک پردازش رندرکننده مجزا است که DOM (مدل شیءگرای سند) و heap جاوااسکریپت اختصاصی خود را دارد. بنابراین، مصرف حافظه با تعداد صفحاتی که در یک لحظه باز هستند مقیاس میشود، نه با تعداد صفحاتی که در طول روز دریافت میشوند. دو مورد از این پروژهها این هزینه را در فایلهای 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
}
]فایل compose مربوط به Firecrawl، کانتینر api خود را روی 8 گیگابایت و کانتینر Playwright را روی 4 گیگابایت محدود کرده است که با محدودیتهای swap متناظر همراه است. فایل compose پروژه Hound مقدار 3 گیگابایت را برای کانتینری که شامل یک Chromium بستهبندیشده است، تعیین میکند. اینها سقفهایی هستند که خود پروژهها انتخاب کردهاند؛ ارقامی منتشرشده که نشاندهنده وضعیت سیستم در حالت بیکار نیستند. علاوه بر این، Redis، RabbitMQ، PostgreSQL و FoundationDB نیز سهم خود را علاوه بر اعداد اعلامی Firecrawl طلب میکنند.
سقفی که بالاتر از RAM فیزیکی شما باشد، عملاً بیاثر است. هنگامی که حافظه سرور تمام شود، مکانیزم OOM killer (قاتل حافظه) هسته سیستمعامل، یک پردازش را خاتمه میدهد؛ در نتیجه کانتینر از docker compose ps ناپدید میشود بدون آنکه خطایی در لاگ برنامه ثبت شود. پس از هر راهاندازی مجدد (restart) که دلیل آن را نمیدانید، dmesg -T | tail را بررسی کنید. برای کل پشته Firecrawl بودجه 8 گیگابایت RAM در نظر بگیرید و 4 گیگابایت را به عنوان حداقلِ لازم برای یک سرور آزمایشی لحاظ کنید. تنظیم این اعداد برای هر سرویس در محدودیتهای حافظه در Docker Compose توضیح داده شده است.
یک جزئیات دیگر در مورد مرورگرها وجود دارد که میتواند وقت زیادی از کاربران بگیرد. داکر به صورت پیشفرض 64 مگابایت حافظه اشتراکی (shared memory) در مسیر /dev/shm به کانتینر اختصاص میدهد، در حالی که Chromium بافرهای رندرکننده خود را در آنجا قرار میدهد؛ بنابراین در صفحات سنگین دچار کرش میشود. هر دو پشته مرورگر این مقدار را افزایش میدهند: فایل compose پروژه Hound شامل shm_size: "1gb" است. این خط را در هر ایمیجی که بر پایه Playwright میسازید، کپی کنید.
کیفیت استخراج در صفحات متکی به JavaScript
در صفحات HTML ایستا، وبلاگهای رندرشده در سمت سرور، صفحات مستندات یا مقالات خبری، خروجی Markdown تقریباً یکسان است و سریعترین ابزار برنده است. تفاوت زمانی آشکار میشود که با صفحات رندرشده در سمت کلاینت (Client-rendered) مواجه شویم؛ جایی که HTML تحویل داده شده یک پوسته خالی است و متن پس از بارگذاری توسط JavaScript اضافه میشود.
ابزار Draco در سطوح مختلف عمل میکند. سطح 0 و سطح 1، فایل HTML را بدون اجرای هیچگونه JavaScript تجزیه میکنند. سطح 2، کد JavaScript صفحه را درون یک V8 isolate داخلی اجرا میکند؛ این همان موتور JavaScript است که بدون محیط مرورگر اجرا میشود و طبق مستندات README، کد صفحه در این محیط به هیچگونه قابلیت میزبان (host capability) دسترسی ندارد. این روش بسیاری از برنامههای تکصفحهای (SPA) را با کسری از حافظه مصرفی یک مرورگر کامل پوشش میدهد. زمانی که Draco به بنبست میرسد و نمیتواند از آن عبور کند، draco scrape با کد خروجی 3 یعنی needs_browser متوقف میشود. این مورد را در اسکریپتهای خود بررسی کنید، زیرا یک فایل خالی با کد خروجی صفر، خطایی است که بهآرامی زمینه (context) عامل هوش مصنوعی را مسموم میکند:
draco scrape https://example.com > page.md
echo "exit=$?"سرویس playwright-service در Firecrawl یک نمونه واقعی از Chromium را هدایت میکند، بنابراین دقیقاً همان چیزی را رندر میکند که یک مرورگر نمایش میدهد. نسخه self-hosted با محصول ابری (hosted) متفاوت است: مستندات تأکید دارند که نمونههای self-hosted به Fire Engine دسترسی ندارند، بنابراین قابلیتهای ضد مسدودسازی و چرخش IP سرویس ابری در آنها وجود ندارد و نقاط پایانی /agent و /browser نیز پشتیبانی نمیشوند. Hound عمداً در جایگاهی میان این دو قرار گرفته است. این ابزار دادهها را از طریق HTTP دریافت کرده و در صورت نیاز، سطح پردازش را برای هر درخواست افزایش میدهد؛ همچنین مرورگر گرم (warm browser) آن پس از یک دوره عدم فعالیت (idle timeout) بسته میشود تا مصرف منابع در یک سرور کمترافیک نزدیک به حالت پایه باقی بماند.
نصب Draco با نسخه ثابت (Pinned)
فایل README یک اسکریپت نصب تکخطی را معرفی میکند. پیش از آنکه خروجی آن را مستقیماً به shell بفرستید، محتوای آن را بررسی کنید: این اسکریپت در مسیر $HOME/.draco/bin/draco نصب میشود، همیشه آخرین نسخه latest را دریافت میکند و هیچ امضا یا هشی را بررسی نمیکند. روی سرور، نسخه را ثابت (pin) کنید و صحت فایل دانلود شده را بسنجید.
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این دستور مقدار draco-linux-x86-64.tar.gz: OK را چاپ میکند. مشاهده خطای FAILED به این معناست که بایتهای موجود در فایل شما با بایتهای منتشر شده توسط پروژه مطابقت ندارد؛ بنابراین فایل را حذف کرده و دوباره اقدام کنید.
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دستور آخر، صفحه نمونه را در کمتر از یک ثانیه به صورت markdown چاپ میکند. بخش find صرفاً جنبه تزئینی ندارد: ساختار آرشیو بخشی از قرارداد عمومی پروژه نیست و اسکریپت نصب رسمی نیز فایل باینری را به همین روش پیدا میکند.
دیمون را به جای کاربر خودتان، با حساب کاربری اختصاصیاش اجرا کنید. فایل /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 پاسخ میدهد. خطای Connection refused به این معناست که دیمون در حال اجرا نیست، پس فایل journalctl -u draco -n 50 را مطالعه کنید. دلیل معمول این است که پردازش دیگری از قبل پورت 3002 را اشغال کرده است، زیرا این پورت پیشفرض Firecrawl نیز هست؛ با --port میتوانید پورت یکی از آنها را تغییر دهید. بررسی دقیقتر فایلهای unit: systemd service units and timers.
اکنون همانطور که عامل (agent) شما عمل میکند، دادهها را دریافت کنید:
curl -X POST http://127.0.0.1:3002/v1/scrape \
-H 'content-type: application/json' \
-d '{"url": "https://example.com", "formats": ["markdown"]}'دیمون fetch را از دسترس اینترنت عمومی خارج کنید
یک API از نوع fetch بدون احراز هویت، یک پروکسی باز محسوب میشود. هر کسی که به این پورت دسترسی داشته باشد، میتواند سرور شما را وادار کند تا هر URL دلخواهی را با IP شما درخواست کند؛ در این صورت گزارشهای سوءاستفاده به جای مهاجم، برای ارائهدهنده خدمات شما ارسال میشود. پرچمهای مستند شده برای Draco در serve شامل هیچ کلید API نیستند، بنابراین حفاظت باید در سطح شبکه اعمال شود. زمانی که agent روی همان ماشین اجرا میشود، از مقدار پیشفرض 127.0.0.1 برای bind استفاده کنید. اگر agent در جای دیگری قرار دارد، هر دو سمت را در یک تونل خصوصی قرار دهید؛ یک WireGuard VPN که خودتان میزبانی میکنید معمولترین راهکار است و باید به جای 0.0.0.0، روی آدرس تونل bind کنید. سپس از یک ماشین دیگر بررسی کنید که IP عمومی هیچ پاسخی نمیدهد. اصول اولیه فایروال ufw و حسابهای کاربری با حداقل دسترسی دو بخش اصلی این موضوع را پوشش میدهند.
آیا کد ایجنت شما تغییر خواهد کرد؟ سازگاری API در عمل
Draco به مسیرهای v1 در Firecrawl یعنی /v1/scrape، /v1/map، /v1/crawl، /v1/batch/scrape و /v1/search پاسخ میدهد و در فایل README آن ذکر شده که فیلدهای ناشناخته پذیرفته و نادیده گرفته میشوند. ایجنتی که در حال حاضر به /v1/scrape درخواست ارسال میکند، تنها به یک base URL جدید نیاز دارد و نه چیز دیگر. مراقب تغییرات در سمت مقابل باشید: صفحه self-hosting خودِ Firecrawl اکنون با /v2/crawl تست میشود و SDKهای فعلی از v2 استفاده میکنند؛ بنابراین یک کلاینت v2 که به سمت Draco تنظیم شده باشد، مسیری را درخواست میکند که Draco آن را ارائه نمیدهد. پیش از ویرایش کد ایجنت، هر فراخوانی را با curl تست کنید و بهجای تکیه بر status code، بدنه JSON را بخوانید؛ چرا که تفاوت پیادهسازیها معمولاً در نام فیلدها بروز میکند.
فایل Robots.txt، محدودیتهای نرخ و خط قرمز
ابزار Draco بهصورت پیشفرض robots.txt را میخواند و --ignore-robots این قابلیت را غیرفعال میکند. مستندات Firecrawl نیز همین رفتار پیشفرض را تأیید میکنند. هر دو را به حال خود رها کنید. سپس سرعت خود را تنظیم کنید: --delay میلیثانیه بین درخواستها فاصله میاندازد و --max-concurrency تعداد کارهای موازی را محدود میکند که مقدار پیشفرض آن در daemon برابر با 8 است. مقدار 2 تا 4 برای یک لینک VPS اشتراکی مناسبتر است و بهندرت باعث کندی کلی میشود، زیرا سایتی که شما را محدود (rate limit) میکند، زمان بیشتری نسبت به صرفهجویی در concurrency از شما میگیرد. آنچه دریافت میکنید را Cache کنید تا اجرای دوم agent هزینهای برای منبع نداشته باشد. این مورد همچنین ارزانترین ردیف در کنترل هزینههای یک AI agent است.
دیوارهای چالش (Challenge walls) موضوعی جداگانه هستند و Trawl دقیقاً برای همین ساخته شده است: Cloudflare Turnstile، reCAPTCHA، hCaptcha و GeeTest. دیوار چالش به این معناست که یک سایت صراحتاً از پذیرش ترافیک خودکار خودداری میکند. دور زدن این دیوارها شما را در برابر شرایط استفاده از سایت و در برخی نقاط در برابر قانون قرار میدهد، بنابراین این راهنما فقط زیرساخت دریافت داده را پوشش میدهد و در همانجا متوقف میشود. همان تکنیکهایی که از یک دیوار عبور میکنند، مواردی هستند که مالکان سایت آنها را رصد و مسدود میکنند، که باعث میشود هر خط لولهای که بر پایه آنها ساخته شده، هم شکننده و هم غیراخلاقی باشد. وقتی یک منبع اهمیت زیادی دارد، به دنبال RSS feed، API عمومی یا خروجی انبوه (bulk export) آن باشید. اجرای هرکدام از اینها ارزانتر است و هیچکدام با تغییر دیوار چالش از کار نمیافتند.
اتصال به یک عامل از طریق MCP
پروتکل MCP (مخفف Model Context Protocol) رابطی است که یک عامل (Agent) برای فراخوانی ابزارها از آن استفاده میکند. Draco یک سرور MCP را در همان فایل اجرایی و از طریق stdio به همراه دارد:
{ "mcpServers": { "draco": { "command": "draco", "args": ["mcp"] } } }سپس ابزارها برای عامل به شکل draco_scrape، draco_search و مجموعه draco_interact_* ظاهر میشوند. استفاده از stdio تنها زمانی ممکن است که پردازش عامل و فایل اجرایی روی یک ماشین باشند، زیرا بستر انتقال، ورودی استاندارد (standard input) همان پردازش است. برای عاملی که روی میزبان دیگری قرار دارد، Hound پروتکل MCP را از طریق HTTP ارائه میدهد: hound --http --host 127.0.0.1 --port 8765 یک نقطه پایانی (endpoint) را در http://127.0.0.1:8765/mcp منتشر میکند که میتوانید از طریق تونل به آن دسترسی پیدا کنید. انتخابهای مربوط به بستر انتقال و آنچه باید در معرض دید قرار گیرد، در اجرای سرورهای MCP روی یک VPS آمده است.
بازیابی جفتها با جستجو. عاملی که فقط قابلیت بازیابی دارد، منتظر میماند تا شما URLها را در اختیارش قرار دهید. با افزودن یک نمونه SearXNG خودمیزبان برای جستجو، عامل میتواند خودش آنها را پیدا کند؛ این کار مشابه مهارت جستجوی مرورگر مبتنی بر SearXNG است. هنگامی که دیمون (daemon) بالا بیاید، به عنوان یک سرویس مشترک برای هر کدام از عوامل هوش مصنوعی خودمیزبان که اجرا میکنید، عمل خواهد کرد.
FAQ
آیا برای دریافت صفحات توسط یک AI agent به مرورگر headless نیاز دارم؟
برای اکثر صفحات خیر. مستندات، وبلاگها و مقالات خبری که سمت سرور رندر میشوند، با یک درخواست HTTP ساده و تبدیل HTML به markdown بهطور کامل دریافت میشوند. این همان کاری است که Draco در سطوح پایینتر خود با سرعت تقریبی 300 میلیثانیه برای هر صفحه (بدون نیاز به مرورگر) انجام میدهد. استفاده از مرورگر تنها برای برنامههایی که سمت کلاینت رندر میشوند (جایی که HTML ارسالی یک پوسته خالی است) توجیه دارد و حافظه مصرف میکند. ایزوله V8 در Draco بخش بزرگی از این نیاز را بدون اجرای پروسه مرورگر پوشش میدهد و در صورت عدم موفقیت، با کد خروجی 3 و needs_browser متوقف میشود.
برای اجرای Firecrawl به صورت self-hosted روی یک VPS به چه مقدار RAM نیاز دارم؟
فایل compose این سرویس، سقف 8 گیگابایت را برای کانتینر api و 4 گیگابایت را برای کانتینر Playwright تعیین میکند. این پشته (stack) همچنین Redis، RabbitMQ، PostgreSQL و FoundationDB را اجرا میکند. برای 8 گیگابایت RAM برنامهریزی کنید. روی یک سرور 2 گیگابایتی، قابلیت out-of-memory killer در هسته سیستمعامل، کانتینرها را تحت فشار بار کاری حذف میکند. اولین نشانه این اتفاق، ریاستارت شدن کانتینر در docker compose ps است که در لاگ برنامه هیچ مورد مفیدی ثبت نمیشود؛ بنابراین وضعیت را با dmesg -T | tail تأیید کنید.
آیا Draco جایگزین مستقیم برای Firecrawl API است؟
برای endpointهای نسخه v1، شباهت زیادی دارد. این سرویس /v1/scrape، /v1/map، /v1/crawl، /v1/batch/scrape و /v1/search را ارائه میدهد و فیلدهای درخواستی ناشناخته را نادیده میگیرد؛ بنابراین کلاینتی که برای Firecrawl v1 نوشته شده، معمولاً فقط به تغییر base URL نیاز دارد. این محصول، نسخه میزبانیشده (hosted) نیست: هیچ pool پروکسی مدیریتشدهای پشت آن وجود ندارد و مسیرهای جدیدتر v2 در Firecrawl بخشی از قابلیتهای آن نیستند. ابتدا هر فراخوانی که agent شما انجام میدهد را با curl بررسی کنید.
آیا self-hosting یک scraper به این معنی است که میتوانم robots.txt را نادیده بگیرم؟
خیر. محل اجرای کد، تغییری در آنچه یک سایت منتشر کرده یا آنچه شرایط استفادهاش اجازه میدهد، ایجاد نمیکند. هم Draco و هم Firecrawl بهطور پیشفرض به robots.txt احترام میگذارند و پرچم (flag) نادیدهگرفتن آن فقط برای سایتهایی است که مالک آنها هستید یا اجازه کتبی برای خزش (crawl) آنها دارید. محدودیتهای نرخ (rate limits) در هر صورت توسط مقصد اعمال میشوند، بنابراین یک --delay مؤدبانه با همزمانی (concurrency) پایین، باعث میشود IP شما همچنان فعال بماند. پشتهای که فقط با دور زدن دیوارههای امنیتی (challenge wall) کار میکند، پشتهای است که بدون هشدار قبلی از کار میافتد.