VPS پر AI agents کے لیے headless Chromium چلائیں
VPS پر headless Chromium میں /dev/shm کم، sandbox flags، missing fonts اور leaked processes عام خرابیاں ہیں۔ Agent چلانے سے پہلے limits اور private endpoint طے کریں۔
آپ کیا چلا رہے ہیں
VPS پر headless browser دراصل Chromium ہوتا ہے، جس میں کوئی window نہیں ہوتی۔ اسے کسی شخص کے بجائے آپ کا code چلاتا ہے۔ server پر یہ ایک طویل مدت تک چلنے والا process tree ہوتا ہے، جس سے آپ کا agent local socket کے ذریعے رابطہ کرتا ہے۔ اسے install کرنے کے لیے ایک command کافی ہے۔ اصل کام اس کے بعد شروع ہوتا ہے۔ آپ browser کے machine سے استعمال کرنے والے وسائل محدود کرتے ہیں اور اس کے control endpoint کو public internet سے دور رکھتے ہیں۔
یہ guide فرض کرتی ہے کہ tool کا انتخاب پہلے ہی ہو چکا ہے اور اب آپ کو اسے operate کرنا ہے۔ اگر آپ ابھی crawlers اور extractors کا تقابلی جائزہ لے رہے ہیں تو self-hosted Firecrawl کے متبادل سے شروع کریں اور پھر واپس آئیں۔ ذیل کی تمام ہدایات Playwright کے Chromium کو استعمال کرتی ہیں، کیونکہ Playwright اپنا browser build اور اپنا dependency installer فراہم کرتا ہے۔ اس لیے یہی commands ایک bare Ubuntu VPS اور container کے اندر یکساں طور پر کام کرتی ہیں۔ Versions August 2026 تک موجودہ ہیں۔
انحصارات کا اندازہ لگائے بغیر Chromium انسٹال کریں
npm i -D playwright@1.62.0
npx playwright install --with-deps chromium--with-deps ان shared libraries اور fonts کے لیے apt چلاتا ہے جن کی Chromium کو ضرورت ہوتی ہے، اور وہاں پہنچنے پر root کی اجازت طلب کرتا ہے۔ Browser build خود اس صارف کے لیے ~/.cache/ms-playwright میں download ہوتا ہے جس نے command چلائی ہو۔ Server پر یہ بات اہم ہے، کیونکہ service user عموماً وہ صارف نہیں ہوتا جس سے آپ login کرتے ہیں۔ sudo npx playwright install-deps chromium کے ذریعے admin کے طور پر system packages ایک بار انسٹال کریں، پھر install command اور service unit دونوں میں PLAYWRIGHT_BROWSERS_PATH=/opt/pw-browsers مقرر کریں تاکہ ایک ہی copy مشترکہ طور پر استعمال ہو۔ جو service اپنے browser تک رسائی نہ حاصل کر سکے، وہ launch کے وقت اس path کا نام دینے والے message کے ساتھ fail ہو جاتی ہے جسے اس نے تلاش کیا تھا۔
Playwright version کو pin کریں۔ ہر release ایک browser build سے منسلک ہوتی ہے، اس لیے غیر مقررہ npm update چلتی ہوئی service کے تحت browser تبدیل کر سکتا ہے۔ August 2026 تک Playwright 1.62 موجودہ version ہے۔
Chromium کے 2 builds موجود ہیں، اور یہ ایک ہی program نہیں ہیں۔ Default download headless shell ہوتا ہے، جو ایک چھوٹا binary ہے اور صرف headless mode میں چلتا ہے، جبکہ npx playwright install --with-deps --only-shell صرف یہی انسٹال کرتا ہے۔ Full browser آپ کو chromium channel کے ذریعے ملتا ہے، جسے Playwright کی browser documentation میں "اصل Chrome browser، اس لیے زیادہ authentic، زیادہ reliable، اور زیادہ features فراہم کرنے والا" کہا گیا ہے۔ Bulk fetching کے لیے shell استعمال کریں۔ جب کوئی site مختلف انداز میں کام کرے اور آپ کو وجہ معلوم کرنی ہو تو full browser استعمال کریں۔
کنٹینر میں headless browser کیوں crash ہوتا ہے
Docker ہر container کو 64 MB /dev/shm دیتا ہے۔ Docker documentation واضح ہے: "If you omit the size entirely, the system uses 64m"۔ Chromium اپنے processes کے درمیان rendered content اسی shared memory area کے ذریعے منتقل کرتا ہے، اس لیے ایک بھاری page اسے بھر سکتا ہے۔ اس کے بعد renderer بند ہو جاتا ہے اور آپ کا client crashed target کی اطلاع دیتا ہے، حالانکہ یہی page آپ کے laptop پر درست کام کرتا ہے۔ کوئی تبدیلی کرنے سے پہلے container کے اندر سے size کی تصدیق کریں۔
df -h /dev/shmاس مسئلے کے دو حقیقی حل ہیں، اور یہ ایک دوسرے کے متبادل ہیں، باہم لازم نہیں۔ --ipc=host container کو host کے IPC namespace میں شامل کرتا ہے، اس لیے وہ host کا /dev/shm استعمال کرتا ہے، جو عموماً RAM کا نصف ہوتا ہے۔ Playwright's Docker guide اس کی تجویز دیتی ہے، کیونکہ اس کے بغیر "Chromium can run out of memory and crash"۔ اس کی قیمت یہ ہے کہ container اور host کے درمیان IPC isolation ختم ہو جاتی ہے۔ --shm-size=1g private namespace برقرار رکھتا ہے اور mount کو بڑا کر دیتا ہے۔
docker run --rm -it --init --ipc=host --user pwuser mcr.microsoft.com/playwright:v1.62.0-noble /bin/bash--disable-dev-shm-usage flag وہ حل ہے جو زیادہ تر search results میں ملے گا، لیکن یہ مختلف کام کرتا ہے: یہ ان files کو /dev/shm سے نکال کر ایک temporary directory میں منتقل کرتا ہے۔ اگر /tmp disk پر موجود ہو تو crash کے بدلے سست rendering اور disk writes ملیں گی۔ اگر /tmp ایک tmpfs ہو تو data دوبارہ RAM میں چلا جاتا ہے اور اس پر کوئی size limit نہیں رہتی؛ یوں browser ایک چھوٹے VPS کی memory ختم کر سکتا ہے۔ اس کے بجائے /dev/shm کو درست طور پر size دیں۔
--no-sandbox کی اصل قیمت
Chromium ہر renderer کو Linux user namespaces پر مبنی sandbox میں الگ تھلگ کرتا ہے۔ یہ sandbox ایک نقصان دہ صفحے اور آپ کے server کے درمیان حفاظتی حد ہے۔ جب یہ شروع نہیں ہو پاتا تو Chromium چلنے سے انکار کر دیتا ہے، اور log میں اس جیسی سطر موجود ہوتی ہے:
Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permittedعام مشورہ --no-sandbox ہے۔ Chromium کی اپنی security documentation اس کی قیمت واضح طور پر بیان کرتی ہے: یہ flag "Chromium کی اہم security features کو غیر فعال کرتا ہے اور open web براؤز کرتے وقت اسے کبھی استعمال نہیں کرنا چاہیے"۔ Links کی پیروی کرنے والا agent لازماً open web براؤز کر رہا ہوتا ہے۔ اصل وجہ تلاش کریں۔
تقریباً ہر case میں دو وجوہات کافی ہوتی ہیں۔ Browser کو root کے طور پر چلانے سے sandbox غیر فعال ہو جاتا ہے، کیونکہ وہ پہلے سے حاصل privileges کو drop نہیں کر سکتا۔ اسی لیے Playwright کی image میں pwuser نام کا عام user شامل ہوتا ہے۔ Ubuntu 24.04 اور اس کے بعد کے versions میں AppArmor غیر مراعات یافتہ user namespaces کو محدود کرتا ہے، اور جس path پر موجود Chromium binary کو کوئی shipped profile cover نہیں کرتا، اسے deny کر دیا جاتا ہے۔ ~/.cache/ms-playwright کے تحت Playwright کا download بالکل ایسا ہی path ہے۔ دونوں کی جانچ کریں:
id -u
sysctl kernel.apparmor_restrict_unprivileged_userns
sudo dmesg | grep -i userns_createsysctl سے حاصل ہونے والی 1 اور apparmor="DENIED" operation="userns_create" پر مشتمل kernel line دوسری وجہ کی تصدیق کرتی ہیں۔ /etc/apparmor.d/pw-chromium میں صرف اسی binary کو allow کریں، تاکہ باقی system کے لیے restriction برقرار رہے:
abi <abi/4.0>,
include <tunables/global>
profile pw-chromium /home/*/.cache/ms-playwright/*/chrome-linux/{chrome,headless_shell} flags=(unconfined) {
userns,
}اسے sudo apparmor_parser -r /etc/apparmor.d/pw-chromium کے ذریعے load کریں۔ Path میں browser revision شامل ہوتی ہے، اس لیے ہر Playwright upgrade پر یہ بدل جاتا ہے۔ اوپر دیے گئے globs اس تبدیلی کے باوجود کام کرتے رہتے ہیں۔ کسی ایک exact path کے خلاف لکھا گیا profile خاموشی سے match کرنا بند کر دیتا ہے، اور بظاہر غیر متعلق update کے بعد browser دوبارہ fail ہونے لگتا ہے۔
اسکرین شاٹس خالی یا خانوں سے بھرے ہوئے کیوں آتے ہیں
خالی اسکرین شاٹ، یا خالی مستطیل خانوں سے بھرا ہوا اسکرین شاٹ، عموماً rendering bug کے بجائے fonts کا مسئلہ ہوتا ہے۔ install-deps ایک فعال بنیادی set حاصل کرتا ہے: fonts-liberation، fonts-freefont-ttf، fonts-noto-color-emoji، fonts-unifont، جاپانی کے لیے fonts-ipafont-gothic، چینی کے لیے fonts-wqy-zenhei، اور تھائی کے لیے fonts-tlwg-loma-otf۔ اس set میں Noto CJK شامل نہیں، اس لیے Korean اور کئی دیگر scripts کے لیے fontconfig کو جو font ملے، وہ fallback کے طور پر استعمال ہوتا ہے۔ اندازہ لگانے کے بجائے fontconfig سے معلوم کریں:
fc-match "sans-serif:lang=ko"
fc-match "sans-serif:lang=ar"
fc-list | wc -lاگر آپ کی مطلوبہ زبان unifont یا ایسے fallback پر resolve ہو جو حقیقی glyphs فراہم نہ کرتا ہو، تو fonts-noto-core اور fonts-noto-cjk install کریں، پھر یہ check دوبارہ چلائیں۔ Fontconfig اپنے نتائج cache کرتا ہے، اس لیے fonts install کرنے کے بعد browser restart کریں۔ ایسی stripped image جس میں کوئی fonts موجود نہ ہوں، startup پر Fontconfig error: Cannot load default config file log کرتی ہے اور ہر page کو خالی render کرتی ہے۔
Locale اور time zone، fonts سے الگ settings ہیں، اور یہ صرف page کی ظاہری شکل نہیں بلکہ اس کے متن کو بھی تبدیل کرتی ہیں۔ Container میں عموماً LANG unset ہوتا ہے اور TZ UTC پر set ہوتا ہے، اس لیے sites English میں content فراہم کرتی ہیں اور UTC timestamps دکھاتی ہیں، جبکہ آپ کا agent ایسے اوقات report کرتا ہے جو اس ملک میں موجود شخص کے دیکھے ہوئے اوقات سے مطابقت نہیں رکھتے۔ انہیں machine کے بجائے ہر browser context کے لیے الگ set کریں، تاکہ ایک browser مختلف regions کے tasks انجام دے سکے۔
const context = await browser.newContext({
locale: 'en-GB',
timezoneId: 'Europe/Paris',
});لیک ہونے والے browser processes server کو swap پر کیوں لے جاتے ہیں
"zombie" نام سے دو مختلف مسائل مراد لیے جاتے ہیں۔ حقیقی zombie ایک مکمل ہو چکا process ہوتا ہے، جس کے parent نے کبھی wait() نہیں چلایا ہوتا۔ یہ صرف PID entry رکھتا ہے اور اس کے علاوہ کچھ نہیں، اس لیے memory استعمال نہیں کرتا۔ جب browser container میں PID 1 کے طور پر چلتا ہے تو ایسے processes جمع ہو سکتے ہیں، کیونکہ PID 1 میں default reaper نہیں ہوتا۔ Docker کا --init flag عین اسی مسئلے کو حل کرتا ہے۔ یہ ایک چھوٹا init چلاتا ہے جو "forwards signals and reaps processes"۔ Compose میں اسی کے لیے init: true استعمال ہوتا ہے۔
جو leak واقعی server کو swap پر لے جاتا ہے، وہ مختلف ہے: یہ ایسے live Chromium processes ہوتے ہیں جنہیں کسی نے بند نہیں کیا ہوتا۔ یہ اس وقت ہوتا ہے جب newContext() اور close() کے درمیان کوئی task exception دے، یا controlling script kill ہو جائے اور اس کا browser tree orphaned رہ جائے۔ اس کی بدترین صورت وہ code ہے جو ہر request کے لیے نیا browser شروع کرتا ہے۔ انہیں شمار کریں:
pgrep -c -f 'headless_shell|chrome'
ps -eo pid,ppid,rss,etime,comm --sort=-rss | head -20Tasks کے درمیان یہ count اپنی idle value پر واپس آنا چاہیے۔ اگر یہ ایک دن کے دوران بڑھتا رہے تو مسئلہ launch flags میں نہیں بلکہ آپ کے code میں ہے۔ finally block میں context بند کریں، SIGTERM پر browser بند کریں، اور browser کو ایک ماہ تک چلانے کے بجائے مقررہ تعداد میں tasks کے بعد اسے دوبارہ شروع کریں۔ systemd کے تحت stop یا restart unit کے cgroup میں موجود ہر چیز کو kill کر دیتا ہے، اس لیے sudo systemctl restart browser.service ایک قابل اعتماد reset ہے۔ terminal multiplexer کے اندر ہاتھ سے شروع کیے گئے browser کے لیے ایسی ضمانت نہیں ہوتی، اور اس کے orphaned processes session ختم ہونے کے بعد بھی چلتے رہتے ہیں۔
ایک browser context کے لیے کتنی RAM درکار ہوتی ہے
یہ سوال درست طور پر پوچھیں، کیونکہ "ایک browser" سے مراد ایک process نہیں ہوتی۔ Chromium ایک browser process، ایک GPU process، utility processes، اور ہر site کے لیے ایک renderer process چلاتا ہے۔ Site isolation کی وجہ سے cross-site iframes کے لیے بھی الگ renderer درکار ہوتا ہے۔ ایک BrowserContext اسی process tree کے اندر الگ cookie jar اور storage area ہوتا ہے، اس لیے دوسرا context کم اضافی وسائل لیتا ہے۔ دوسرا page ایسا نہیں کرتا، کیونکہ اس سے renderer processes شروع ہوتے ہیں، اور اشتہارات سے بھرے page سے کئی processes شروع ہو سکتے ہیں۔
اس لیے جس عدد کی پیمائش کرنی ہے وہ آپ کے اپنے workload کے تحت پورے process tree کی peak memory ہے۔ کسی دوسرے شخص کے blog میں دیا گیا عدد یہاں بے فائدہ ہے، کیونکہ آپ کا agent جن pages کو کھولتا ہے وہی نتیجہ طے کرتے ہیں۔ اس machine پر پیمائش کریں جسے آپ استعمال کریں گے، اور انہی sites کے خلاف کریں جنہیں آپ visit کریں گے:
sudo systemd-run --unit=browser-probe -p MemoryMax=2G -p MemorySwapMax=0 -p WorkingDirectory=/srv/agent /usr/bin/node worker.js
systemctl status browser-probeUbuntu 24.04 پر اس output میں Memory: لائن unit کے لیے موجودہ اور peak دونوں استعمال دکھاتی ہے۔ Worker کو ایک وقت میں ایک page کے ساتھ چلائیں، peak نوٹ کریں، پھر دو pages کھلے رکھ کر دوبارہ پیمائش کریں تاکہ معلوم ہو سکے کہ دوسرا page حقیقت میں کتنی memory لیتا ہے۔ اس کے بعد concurrency کا حساب سادہ ہے: کل RAM میں سے باقی system کی ضرورت منہا کریں، چند سو MB headroom باقی رکھیں، اور حاصل شدہ مقدار کو ہر worker کی measured peak سے تقسیم کریں۔ اس machine کے sizing کے لیے جس پر یہ service چلے گی، agent VPS کے لیے کتنی RAM اور CPU درکار ہے دیکھیں۔
اس تعداد کو دو مقامات پر نافذ کریں۔ اپنے code میں fixed worker pool یا semaphore استعمال کریں، تاکہ agent requests کا burst نئے browsers شروع کرنے کے بجائے queue میں چلا جائے۔ OS میں cgroup limit استعمال کریں، تاکہ queue میں موجود bug پوری machine کو اپنے ساتھ بند نہ کر دے:
[Service]
MemoryMax=2G
MemorySwapMax=0
TasksMax=512
Restart=alwaysMemorySwapMax=0 کی اہمیت بظاہر زیادہ محسوس نہیں ہوتی، لیکن یہ ضروری ہے۔ اس کے بغیر cgroup limit تک پہنچنے پر pages کو swap میں منتقل کر دیتا ہے۔ اس طرح box چلتا رہتا ہے، مگر ہر request سست ہو جاتی ہے، اور اس مسئلے کی تشخیص صاف failure کے مقابلے میں زیادہ مشکل ہوتی ہے۔ اس کے ساتھ kernel اسی cgroup کے اندر browser tree کو kill کر دیتا ہے، systemd unit کو restart کر دیتا ہے، اور sshd برقرار رہتا ہے۔ Compose میں یہی controls mem_limit، shm_size اور init ہیں۔ ان کی وضاحت Docker Compose میں memory limits مقرر کرنا میں کی گئی ہے۔
عوامی انٹرنیٹ سے browser endpoint کو الگ رکھیں
Playwright browser کو server کے طور پر چلا سکتا ہے اور آپ کے agent کو WebSocket URL فراہم کر سکتا ہے:
const { chromium } = require('playwright');
const server = await chromium.launchServer({ port: 3000 });
console.log(server.wsEndpoint());اس endpoint پر login موجود نہیں ہوتا۔ Playwright کی API documentation میں یہ بات براہِ راست لکھی ہے: "wsPath سے واقف کوئی بھی process یا web page، بشمول Playwright میں چلنے والے process یا web page، OS user کا کنٹرول حاصل کر سکتا ہے۔" Default host localhost ہے، جو "صرف loopback interface سے connections قبول کرتا ہے"، اور documentation خبردار کرتی ہے کہ 0.0.0.0 جیسا explicit address دینے سے "browser RPC ہر اس چیز کے لیے exposed ہو جاتا ہے جو listening port تک پہنچ سکتی ہے۔" Chrome کا اپنا --remote-debugging-port اس سے بھی زیادہ خطرناک ہے۔ DevTools protocol میں کسی بھی قسم کی authentication نہیں ہوتی اور یہ مکمل طور پر loopback سے bind ہونے پر منحصر ہے۔
دیکھیں کہ آپ نے حقیقت میں کیا publish کیا ہے۔ اسے دوسری machine سے بھی check کریں، صرف VPS سے نہیں:
ss -ltnp0.0.0.0 سے bind browser port پر موجود ہر چیز ایک security finding ہے۔ یاد رکھیں کہ زیادہ تر providers اپنے control panel میں الگ network firewall چلاتے ہیں۔ آپ کے ufw rules اس firewall سے واقف نہیں ہوتے۔ endpoint تک کسی دوسری machine سے SSH tunnel یا private VPN کے ذریعے پہنچیں:
ssh -N -L 3000:127.0.0.1:3000 you@your-vpsیہ خطرہ صرف browser time چوری ہونے تک محدود نہیں۔ جس browser کو remotely drive کیا جا سکے، وہ آپ کے network کے اندر موجود request-forgery machine ہے۔ جو بھی اس socket تک پہنچ سکتا ہے، وہ اسے http://127.0.0.1:8080، آپ کے database admin page، یا 169.254.169.254 پر موجود cloud metadata address کو fetch کرنے کے لیے استعمال کر سکتا ہے، اور پھر page کے ذریعے response پڑھ سکتا ہے۔ آپ کا firewall اس request کو VPS سے آنے والی request سمجھتا ہے، اس لیے اسے اجازت مل جاتی ہے۔ اس control endpoint کو اس machine پر shell access کے برابر سمجھیں۔
MCP servers بھی اسی نوعیت کے ہوتے ہیں۔ npx @playwright/mcp@latest --headless --port 8931 localhost پر HTTP کے ذریعے service فراہم کرتا ہے، اور --host 0.0.0.0 وہ flag ہے جو local tool کو public بنا دیتا ہے۔ Project کی README میں واضح طور پر لکھا ہے کہ Playwright MCP "security boundary نہیں ہے"۔ Port کو loopback پر رکھیں اور agent کو اسی tunnel کے ذریعے اس تک پہنچنے دیں۔
آپ کا agent جن صفحات کو پڑھتا ہے، وہ ناقابلِ اعتماد input ہیں
جو agent open web کو browse کرتا ہے، وہ اجنبی افراد کا لکھا ہوا متن ایسے model کو فراہم کرتا ہے جس میں آپ کی instructions بھی موجود ہوتی ہیں۔ کوئی صفحہ اس model کے لیے ہدایات شامل کر سکتا ہے، مثلاً task ترک کرنے، tool چلانے یا کسی URL پر data پوسٹ کرنے کا حکم۔ model دونوں چیزیں بطور text وصول کرتا ہے، اس لیے اس کے پاس صفحے کے الفاظ اور آپ کی ہدایات میں فرق کرنے کا قابلِ اعتماد طریقہ نہیں ہوتا۔ setup اس طرح بنائیں کہ malicious صفحے کے پاس نقصان پہنچانے کے مواقع بہت کم ہوں۔
- browser کو اپنے الگ OS user کے تحت چلائیں۔ اس user کے پاس SSH keys نہ ہوں اور اس کے environment میں cloud credentials بھی نہ ہوں۔
- ہر task کے لیے نیا context استعمال کریں، اور Playwright MCP کے ساتھ
--isolatedکریں، تاکہ ایک site کا session اگلے صفحے کو دستیاب نہ ہو۔ - جہاں job اس کی اجازت دے، وہاں origin allowlist برقرار رکھیں۔ Playwright MCP میں
--allowed-originsاور--blocked-originsکو semicolon-separated lists کے طور پر دیا جاتا ہے۔ - state تبدیل کرنے والی ہر کارروائی سے پہلے انسانی منظوری لازم کریں، مثلاً mail بھیجنے یا رقم خرچ کرنے سے پہلے۔
اس سے بھی بہتر یہ ہے کہ پورا browser ایسی machine پر چلائیں جسے ضائع کرکے دوبارہ build کیا جا سکے۔ یہی اصول disposable VM میں coding agents چلانے پر بھی لاگو ہوتا ہے۔ اگر agent کا اصل کام open-ended browsing کے بجائے search ہے تو full browser کے مقابلے میں محدود tool زیادہ محفوظ ہے: اپنے SearXNG سے منسلک search skill نتائج واپس کرتی ہے، مگر hostile صفحہ کبھی load نہیں کرتی۔
FAQ
Chromium Docker میں crash کیوں ہوتا ہے، جبکہ اسی VPS پر براہِ راست ٹھیک چلتا ہے؟
اس کی وجہ یہ ہے کہ container کو default طور پر 64 MB کا /dev/shm ملتا ہے، جبکہ host کے پاس اس سے کہیں بڑا حصہ ہوتا ہے۔ Chromium rendered content کو اسی shared memory area کے ذریعے منتقل کرتا ہے۔ اس لیے بھاری page اسے بھر دیتا ہے اور renderer بند ہو جاتا ہے۔ تصدیق کے لیے container کے اندر df -h /dev/shm چلائیں۔ پھر browser کو یا تو --ipc=host کے ساتھ شروع کریں، جو host کی shared memory استعمال کرتا ہے، یا --shm-size=1g کے ساتھ، جو container کی اپنی shared memory بڑھاتا ہے۔ --disable-dev-shm-usage صرف مسئلے کو /tmp میں منتقل کرتا ہے۔
اگر VPS پر کوئی اور چیز نہیں چل رہی تو کیا --no-sandbox محفوظ ہے؟
نہیں۔ Sandbox malicious page کو machine کے باقی حصوں تک رسائی سے روکتا ہے۔ Chromium کی documentation کے مطابق یہ flag "Chromium کی اہم security features کو غیر فعال کرتا ہے اور open web براؤز کرتے وقت اسے کبھی استعمال نہیں کرنا چاہیے"۔ Links follow کرنے والا agent open web براؤز کر رہا ہوتا ہے۔ اس کے بجائے اصل وجہ درست کریں: browser کو root کے طور پر نہ چلائیں۔ Ubuntu 24.04 پر browser binary path کے لیے userns, رکھنے والا AppArmor profile شامل کریں، تاکہ unprivileged user namespaces صرف اسی program کے لیے اجازت یافتہ ہوں۔
چھوٹے VPS پر میں کتنے browsers چلا سکتا ہوں؟
کوئی مقررہ تعداد نقل نہ کریں؛ پہلے پیمائش کریں۔ Chromium ہر site کے لیے ایک renderer process شروع کرتا ہے، اس لیے جواب ان pages پر منحصر ہے جنہیں آپ کھولتے ہیں۔ MemoryMax set کے ساتھ systemd-run کے تحت ایک worker چلائیں۔ پھر systemctl status میں Memory: line سے peak پڑھیں، اپنی free RAM کو اس peak سے تقسیم کریں، اور کچھ headroom باقی رکھیں۔ اس حد کو دو جگہ نافذ کریں: اپنے code میں queue کے ذریعے، اور unit file میں MemoryMax کے ذریعے۔ اس طرح requests کا burst machine کو swapping پر مجبور کرنے کے بجائے انتظار کرے گا۔
کیا میرا agent کسی دوسری machine سے browser سے connect ہو سکتا ہے؟
ہاں، لیکن port کو کبھی 0.0.0.0 پر bind نہ کریں۔ Playwright server endpoint اور Chrome DevTools port دونوں ہر ایسے client کو قبول کرتے ہیں جو ان تک پہنچ سکتا ہو، اور ان میں password نہیں ہوتا۔ Listener کو 127.0.0.1 پر رکھیں اور connection کو SSH tunnel یا private VPN کے ذریعے منتقل کریں۔ Server پر ss -ltnp سے تصدیق کریں، باہر سے port check کریں، اور اپنے provider کے الگ network firewall کو بھی دیکھیں۔
جب page واضح طور پر load ہو جائے تو میرے screenshots blank کیوں ہوتے ہیں؟
Fonts موجود نہیں ہیں۔ اگر page کے script کو cover کرنے والا font موجود نہ ہو تو text خالی boxes کی صورت میں render ہوتا ہے یا بالکل render نہیں ہوتا۔ اس لیے image-light page کا screenshot blank نظر آتا ہے۔ ہر اس language کے لیے جسے آپ scrape کرتے ہیں، fc-match "sans-serif:lang=ko" چلائیں۔ اگر نتیجہ generic fallback ہو تو fonts-noto-core اور fonts-noto-cjk install کریں۔ پھر browser restart کریں تاکہ fontconfig اپنا cache دوبارہ load کرے۔ جس container میں کوئی font موجود نہ ہو، وہ startup پر Fontconfig error: Cannot load default config file log کرتا ہے۔