Setup browserless self-host trên VPS: headless Chrome cho AI agent

Chia sẻ bài viết

Mục lục
TL;DR
  • Browserless là service self-host Chrome headless qua REST/WebSocket API, dùng cho AI agent, scraping, PDF generation, screenshot.
  • Setup Docker compose 5 phút, expose endpoint /chrome/playwright và /pdf. Cần VPS 4GB RAM cho concurrent 5-10 session.
  • Khác Puppeteer/Playwright cài trực tiếp: tách Chrome ra service riêng, app gọi WebSocket connect tới, không bị conflict dependency.
  • Use case: agent AI scrape, screenshot for OG image, render PDF từ HTML, test E2E từ CI runner không có Chrome.
  • Bài này hướng dẫn full setup, gọi từ Node/Python, optimize concurrency, đặt sau Caddy auth, monitor session.

Khi build AI agent điều khiển trình duyệt hoặc scraper Python, một câu hỏi sớm xuất hiện: cài Chrome ở đâu? Trên VPS chính cùng app dễ conflict dependency, mỗi lần update libnss có thể vỡ. Mỗi process Chrome khởi động ngốn 200-400MB RAM, scale rất khó. Browserless giải quyết bài toán này: chạy một service Chrome dedicated, app từ mọi nơi kết nối qua WebSocket, không cần cài Chrome local.

Bài này hướng dẫn deploy Browserless v2 trên Cloud VPS 50 (4GB RAM), expose endpoint qua Caddy HTTPS với token auth, gọi từ Node.js Puppeteer và Python Playwright, generate screenshot và PDF từ HTML, scale concurrency cho team AI agent. Test trên Ubuntu 24.04.

Browserless là gì?

Browserless (browserless.io) là một container chạy Chrome headless + WebSocket server. Mở port 3000 với 2 endpoint chính:

  • WebSocket /: kết nối Puppeteer hoặc Playwright qua wsEndpoint. Code app y hệt như chạy local.
  • REST /pdf, /screenshot, /scrape, /function: các endpoint sẵn để generate PDF, capture screenshot, scrape HTML, chạy custom JS.

Có 2 bản: Browserless v1 (free, basic) và v2 (open-core, có session manager nâng cao). Bản v2 image tag browserless/chrome:latest từ Docker Hub là open-source phù hợp self-host.

Tại sao dùng Browserless thay cài Chrome local?

  • Tách dependency: Chrome trong container, không đụng vào app host.
  • Scale concurrent: queue và session manager tự handle khi nhiều request.
  • Multi-language: Node, Python, Ruby, Go đều connect được qua WebSocket.
  • Auto cleanup: session timeout tự kill, không leak Chrome zombie process.
  • Built-in stealth: bypass detect headless cho một số use case.

Yêu cầu VPS

  • 2-4 vCPU, 4 GB RAM cho 5-10 concurrent session.
  • 4-8 vCPU, 8 GB RAM cho 15-30 concurrent.
  • 30 GB SSD trở lên (download tệp tạm cho screenshot/PDF có thể lớn).
  • Ubuntu 22.04+ hoặc AlmaLinux 9.

Bước 1: Docker compose setup

mkdir -p ~/browserless && cd ~/browserless

Tạo docker-compose.yaml:

services:
  browserless:
    image: ghcr.io/browserless/chrome:latest
    container_name: browserless
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      TOKEN: $YOUR_LONG_RANDOM_TOKEN
      CONCURRENT: "10"
      QUEUE_LENGTH: "20"
      TIMEOUT: "60000"
      MAX_CONCURRENT_SESSIONS: "10"
      CONNECTION_TIMEOUT: "60000"
      DOWNLOAD_DIR: "/downloads"
    shm_size: 2gb
    volumes:
      - ./downloads:/downloads

shm_size 2GB quan trọng cho Chrome render trang nặng. CONCURRENT 10 đủ cho team nhỏ. TIMEOUT 60s đủ cho hầu hết task scrape.

Khởi động:

docker compose up -d
docker compose logs -f browserless

Khi log thấy "Browserless is running on http://0.0.0.0:3000", service đã sẵn. Test:

curl "http://server-ip:3000/json/version?token=$YOUR_TOKEN"

Trả về JSON version Chrome, webSocketDebuggerUrl. Sẵn sàng gọi.

Bước 2: Đặt sau Caddy HTTPS

browserless.your-domain.com {
    reverse_proxy localhost:3000
    request_body {
        max_size 50MB
    }
}

max_size 50MB cho PDF render từ HTML lớn. Reload Caddy. Token đã bảo vệ trong env, Caddy chỉ proxy.

Bước 3: Gọi từ Node.js Puppeteer

// npm install puppeteer-core
const puppeteer = require('puppeteer-core');

(async () => {
  const browser = await puppeteer.connect({
    browserWSEndpoint: `wss://browserless.your-domain.com?token=${process.env.BL_TOKEN}`,
  });
  const page = await browser.newPage();
  await page.goto('https://example.com');
  const title = await page.title();
  await page.screenshot({ path: 'example.png', fullPage: true });
  console.log(title);
  await browser.close();
})();

Code y hệt như chạy local, chỉ thay launch thành connect. Chrome chạy trên VPS Browserless, không tốn RAM máy chạy app.

Bước 4: Gọi từ Python Playwright

# pip install playwright
import asyncio
import os
from playwright.async_api import async_playwright

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.connect_over_cdp(
            f"wss://browserless.your-domain.com?token={os.getenv('BL_TOKEN')}"
        )
        context = await browser.new_context()
        page = await context.new_page()
        await page.goto("https://example.com")
        print(await page.title())
        await page.screenshot(path="example.png", full_page=True)
        await browser.close()

asyncio.run(main())

connect_over_cdp cho phép Playwright nói chuyện với Chrome qua Chrome DevTools Protocol, tương thích Browserless.

Bước 5: REST endpoint /pdf

curl -X POST "https://browserless.your-domain.com/pdf?token=$BL_TOKEN" 
  -H "Content-Type: application/json" 
  -d '{
    "url": "https://example.com",
    "options": { "format": "A4", "printBackground": true }
  }' 
  -o output.pdf

Generate PDF từ URL. Cũng có thể truyền HTML trực tiếp:

curl -X POST "https://browserless.your-domain.com/pdf?token=$BL_TOKEN" 
  -H "Content-Type: application/json" 
  -d '{
    "html": "

Invoice #001

Hello

", "options": { "format": "A5" } }' -o invoice.pdf

Use case: invoice generation, report PDF, OG image preview.

Bước 6: REST endpoint /screenshot

curl -X POST "https://browserless.your-domain.com/screenshot?token=$BL_TOKEN" 
  -H "Content-Type: application/json" 
  -d '{
    "url": "https://example.com",
    "options": {
      "type": "png",
      "fullPage": true,
      "viewport": { "width": 1280, "height": 720 }
    }
  }' 
  -o screenshot.png

Use case: OG image cho blog, preview thumbnail, snapshot competitor landing để compare design.

Bước 7: REST endpoint /function (custom JS)

curl -X POST "https://browserless.your-domain.com/function?token=$BL_TOKEN" 
  -H "Content-Type: application/json" 
  -d '{
    "code": "module.exports = async ({page}) => { await page.goto("https://example.com"); return await page.evaluate(() => document.title); }"
  }'

Cho phép app gửi function JS, browserless execute trên Chrome, trả về kết quả. Hữu ích cho serverless function ngắn không cần WebSocket connection dài.

Concurrency và queue management

CONCURRENT định số session đồng thời chạy. QUEUE_LENGTH là số request chờ. Vượt CONCURRENT + QUEUE_LENGTH, request 429 Too Many.

Recommendation theo VPS:

  • VPS 4GB RAM: CONCURRENT 5-8, QUEUE 10.
  • VPS 8GB RAM: CONCURRENT 10-15, QUEUE 20.
  • VPS 16GB RAM: CONCURRENT 20-30, QUEUE 40.

Vượt mức này dễ OOM. Monitor RAM qua docker stats. Nếu thường xuyên đầy queue, scale ngang: chạy 2-3 instance Browserless sau load balancer (Caddy round-robin).

Stealth mode chống detect bot

Browserless v2 có flag stealth=true trong query string:

wss://browserless.your-domain.com?token=$TOKEN&stealth=true

Tự inject puppeteer-extra-plugin-stealth, đổi navigator.webdriver=false, chrome.runtime, plugin list. Pass 80 phần trăm site detect bot cơ bản. Site detect nâng cao (Cloudflare Turnstile, Datadome) vẫn block.

Use case AI agent

Kết hợp Browserless + browser-use + Claude:

from browser_use import Agent, Browser, BrowserConfig
from langchain_anthropic import ChatAnthropic

browser = Browser(config=BrowserConfig(
    cdp_url=f"wss://browserless.your-domain.com?token={TOKEN}",
))

agent = Agent(
    task="Vào tnd.vn, tìm gói Cloud VPS 50, lấy giá",
    llm=ChatAnthropic(model_name="claude-3-5-sonnet-20241022"),
    browser=browser,
)
result = await agent.run()

Agent dùng browser trên Browserless service thay vì launch Chromium local. App gọi từ container/serverless, không phải worry Chrome dependency.

Monitor session

curl "https://browserless.your-domain.com/sessions?token=$BL_TOKEN" | jq

Trả về list session active: id, started, duration. Nếu thấy session zombie (running > timeout), POST /kill/{id} để force close.

Browserless cũng expose /metrics theo format Prometheus. Scrape vào Grafana để dashboard concurrent, queue depth, error rate.

Update version mới

cd ~/browserless
docker compose pull
docker compose down
docker compose up -d

Browserless theo Chrome stable, update mỗi 1-2 tháng. Đọc release note để biết breaking change. Backup config docker-compose.yaml vào git.

So sánh với alternative

  • Cài Chrome trực tiếp: rẻ nhất, không có queue management, dễ conflict.
  • BrightData Browser API: SaaS cao cấp, proxy rotation, anti-bot nâng cao. Đắt 0.5-1 USD/giờ.
  • Browserbase: SaaS có session record cho debug. Khoảng 0.10-0.30 USD/session.
  • Chrome Compute Cluster tự dựng: phức tạp, không đáng cho team nhỏ.

Self-host Browserless free, đủ cho 95 phần trăm use case team Việt Nam. Chỉ khi cần anti-bot rất mạnh hoặc residential proxy mới cần SaaS chuyên dụng.

FAQ

Browserless có support Firefox/WebKit không?

Có image ghcr.io/browserless/firefox và ghcr.io/browserless/webkit nhưng ít stable hơn Chrome. Cho production khuyên dùng Chrome. Firefox/WebKit dùng khi cần test cross-browser specific.

Có thể chạy Browserless trên ARM (M1, Raspberry Pi) không?

Có. Image multi-arch hỗ trợ arm64. Performance tốt trên Apple Silicon, ổn trên Pi 5 8GB cho concurrent 2-3.

Browserless có lưu cookie session giữa các request không?

Mặc định mỗi session ephemeral, đóng là mất. Để persist, dùng context với user data dir mounted vào volume. Hoặc đặt option keepalive=true trong query, browserless giữ context cho request tiếp theo.

Browserless có hỗ trợ chrome extension không?

Có. Mount thư mục extension vào /opt/extensions, set CHROME_REFRESH_TIME. Chrome load extension khi start. Phù hợp cài uBlock, captcha solver auto.

Latency từ VN tới Browserless self-host so với SaaS?

Self-host trên VPS VN: 5-15ms. SaaS thường US: 200-300ms. Cho mỗi request, latency add up nhanh. Self-host 1 trang scrape mất 2 giây, SaaS có thể 3-5 giây cho cùng task.

Cloud VPS cho vibe coder

Cloud VPS đủ RAM cho Browserless headless Chrome concurrent

Cloud VPS TND sẵn AlmaLinux 9, Ubuntu 22/24, Debian 12/13. SSD CEPH, snapshot 1-click, backup hằng ngày, network 200Mbps trong nước. Cloud VPS 50 chạy 5-10 concurrent Chrome session, VPS 80 chạy 15-20.

Xem 8 cấu hình Cloud VPS →