Tự host OpenBot trên VPS: mỗi bot cần bao nhiêu RAM?
Tự host OpenBot trên VPS với một container và Chromium riêng cho từng AI coworker. Xem gateway kiểm soát hành động thế nào và chi phí RAM thực tế.
Bạn nhận được gì khi tự host các AI coworker của OpenBot
Bạn tự host các AI coworker của OpenBot bằng cách chạy một gateway server và một container cho mỗi bot trên phần cứng do bạn kiểm soát. Mỗi container của bot có Chromium riêng và volume workspace riêng, cùng một browser profile được lưu giữ giữa các session. Mọi hành động bot thực hiện trên máy tính, file, MCP (model context protocol) server hoặc thành phần UI đều đi qua gateway đó. Gateway kiểm tra hành động theo policy trước khi thực thi và ghi log sau đó. Nếu agent loop mà gateway bao bọc vẫn còn xa lạ với bạn, lộ trình từng bước trong học AI agent từ đầu sẽ hướng dẫn bạn tự viết một agent loop nhỏ trước khi cấp cho bot quyền dùng browser và thông tin đăng nhập của bạn.
OpenBot được CopilotKit phát hành theo giấy phép MIT tại github.com/CopilotKit/openbot. Bản release đầu tiên có tag, v0.0.1, được phát hành vào ngày 17 August 2026. Project tự mô tả là alpha và vẫn đang được phát triển tích cực. Hãy xem đây là một thiết kế nghiêm túc nhưng vẫn còn những điểm chưa hoàn thiện ở giai đoạn đầu.
Điểm đáng chú ý trong kiến trúc này cũng là phần tốn kém nhất. Mỗi agent cần một browser, và chi phí memory là phần mà nhiều người quên lên kế hoạch. Vì vậy, hãy sizing trước khi cài đặt.
Cách gateway quyết định mọi hành động
API server trên port 3001 là đường duy nhất đến máy tính của bot. Trước khi chạy một hành động trên trình duyệt, gateway lấy target từ page snapshot, đánh giá các rule policy CEL (common expression language) dựa trên context, ghi một dòng audit chứa quyết định, rồi mới gọi container. Nếu quá trình thực thi thất bại sau đó, gateway ghi thêm một dòng thứ hai. Tài liệu nêu rõ ranh giới này: máy tính không quyết định policy; server gateway là ranh giới thực thi hành động. Bên ngoài OpenBot, mô hình phân tách này có tên gọi riêng, vì loop, tool definition, permission check và session state hợp thành harness bao quanh model, còn gateway này là phần xử lý quyền của harness đó.
Policy mặc định là deny, và các deny rule được đánh giá trước allow rule. Hướng xử lý khi lỗi quan trọng hơn cú pháp của rule. Policy bị thiếu sẽ không cho phép gì, còn rule bị lỗi sẽ dẫn đến block bất kể đó là deny rule hay allow rule. Vì vậy, một lỗi trong policy sẽ khiến bot bị kẹt thay vì để bot tự do truy cập các account của bạn. Lớp này kiểm soát bot làm gì, không kiểm soát bot đọc gì. Vì thế, một page chứa instruction nhắm vào agent vẫn là vấn đề riêng. Đây cũng là prompt injection surface mà bạn gặp khi đưa cho agent kết quả từ SearXNG instance của chính bạn.
Audit trail được lưu trong PostgreSQL nên vẫn còn sau khi restart. Các lần chuyển quyền điều khiển được ghi là computer.help_requested, computer.control_taken và computer.control_released. Nhờ đó, bạn biết khi bot yêu cầu con người tiếp quản và khi con người trả quyền điều khiển lại cho bot. Secret được ghi dưới dạng số lượng ký tự, không bao giờ ghi giá trị. File operation ghi path và size, không ghi nội dung. Nếu muốn có cùng ranh giới kiểm soát nhưng không cần browser phía sau, đặt bước phê duyệt trước hành động của AI agent trình bày trường hợp hẹp hơn đó.
Chi phí RAM và disk của một bot
Dự án công bố số liệu đo được cho một Bot trên arm64. Đây là những số liệu sizing duy nhất OpenBot cung cấp. Chúng mô tả một bot trên một kiến trúc, vì vậy hãy xem chúng là điểm bắt đầu, không phải kế hoạch dung lượng.
The data behind this chart
[
{
"label": "Measured, one Bot",
"memory_gb": 0.55,
"disk_gb": 5.3,
"vcpu": 0.06
},
{
"label": "Documented minimum",
"memory_gb": 2,
"disk_gb": 8,
"vcpu": 1
},
{
"label": "Documented recommended",
"memory_gb": 4,
"disk_gb": 10,
"vcpu": 2
}
]Mức sử dụng memory đỉnh được đo ở 0.55 GB cho một Bot. Mức tối thiểu được ghi nhận là 2 GB và mức khuyến nghị là 4 GB. Chênh lệch giữa số đo và mức tối thiểu là phần dự phòng cho Chromium tăng mức sử dụng khi có tải, vì memory của browser phụ thuộc vào các page đang mở, không phải trạng thái process khi idle. CPU khi idle gần như không đáng kể, ở mức 0.06 core tại đầu trên của khoảng đo được. Vì vậy, CPU không phải tài nguyên chính bạn cần mua. Disk mới là tài nguyên đó. Riêng image đã chiếm 5.3 GB, trong khi volume khuyến nghị là 10 GB. Image lớn như vậy vì nó chứa binary Firefox và WebKit của Playwright cùng với Chromium.
Những số liệu trên không cho biết chi phí khi chạy nhiều bot cùng lúc, và dự án không công bố số liệu cho trường hợp đó. Mức tối thiểu được ghi nhận là con số mà dự án thấy đủ an toàn để công bố, không phải con số đã được theo dõi trong điều kiện tải thực tế. Vì vậy, chọn giữa PhotoPrism và Immich cũng phải dựa trên mức RAM tối thiểu đo được thay vì mức được công bố. Hãy tự đo trên hệ thống của bạn. Khởi động một bot, giao cho nó một tác vụ thực tế với một page đang mở, rồi monitor container trong lúc bot hoạt động.
docker stats --no-stream
free -mLấy cột MEM USAGE của container bot làm số liệu cho mỗi bot. Sau đó cộng thêm gateway và PostgreSQL, rồi nhân số liệu cho mỗi bot với số bot bạn dự kiến sẽ chạy đồng thời. Bot khi idle vẫn giữ một browser process, nên hệ số nhân áp dụng cho tất cả bot đang tồn tại, không chỉ các bot đang bận. Cách tính này giống cách dùng trong sizing RAM và CPU cho coding agent trên VPS, còn phần browser được trình bày trong chạy headless browser cho agent trên VPS.
Có một chi tiết về Chromium ảnh hưởng đến các plan nhỏ. OpenBot khởi chạy Chromium với --disable-dev-shm-usage, nên browser ghi dữ liệu vào /tmp thay vì /dev/shm. Điều này tránh lỗi crash trên các host có /dev/shm nhỏ, nhưng chuyển áp lực sang root filesystem. Đây là một lý do nữa khiến disk khuyến nghị lớn hơn image.
Tự host OpenBot trên VPS như thế nào?
Bạn cần Docker, Bun 1.3 trở lên, một project Intelligence của CopilotKit và model API key. Tài liệu phát triển cũng yêu cầu lsof, python3 và curl trên máy chủ. Hãy clone một bản release đã gắn tag thay vì main, vì main trong một project alpha có thể thay đổi mà không báo trước.
git clone --branch v0.0.1 https://github.com/CopilotKit/openbot.git
cd openbot
cp .env.example .envProvision project Intelligence. Ba lệnh này ghi runtime key và license token vào file môi trường của bạn.
npx --yes copilotkit@latest login
npx --yes copilotkit@latest project select
npx --yes copilotkit@latest license --writeTạo key dùng để mã hóa credential đã lưu, rồi ghi output vào .env dưới dạng KEY_ENCRYPTION_KEY. Thêm OPENAI_API_KEY vào cùng file, hoặc đặt BOT_PROVIDER thành anthropic hoặc google cùng với key tương ứng.
openssl rand -base64 32Sau đó cài đặt và khởi động.
bun install
bash scripts/start.shscripts/start.sh khởi động các Docker service, chạy database migration, khởi động server và app, rồi kiểm tra health của chúng. Khi hoàn tất, app sẽ trả lời trên port 3010 và API trên port 3001. Script sẽ báo xung đột port và giữ nguyên service tương ứng đang chạy, nên chạy script hai lần vẫn an toàn.
Kiểm tra từ chính server trước khi public bất kỳ dịch vụ nào.
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3010
ss -ltnp | grep -E ':(3010|3001|4100|4500|5432)'200 từ lệnh đầu tiên có nghĩa là app đang phục vụ request. Lệnh thứ hai cho biết các port đó đang bind vào địa chỉ nào; đây mới là thông tin cần quan tâm trên VPS. Dòng có nội dung 127.0.0.1:3001 chỉ cho phép truy cập từ chính máy chủ. Dòng có nội dung 0.0.0.0:3001 nghĩa là bất kỳ ai có route đến server đều có thể truy cập.
Image container đơn
Tài liệu triển khai cũng cung cấp một image duy nhất chứa app, API và Chromium, được phục vụ tại cổng 3001.
docker build -t openbot .
docker run -p 127.0.0.1:3001:3001 --env-file .env \
-e EMBEDDED_POSTGRES=on -v openbot-data:/var/lib/postgresql/data openbotEMBEDDED_POSTGRES=on chạy PostgreSQL bên trong container và áp dụng migration khi khởi động. Named volume giữ lại audit history qua các lần redeploy. Nếu không có volume này, mỗi lần rebuild sẽ xóa toàn bộ history đó. Nếu trỏ DATABASE_URL đến một database managed thay thế, phải bật extension vector trên database đó. Các dịch vụ managed như RDS, Cloud SQL và Azure Database đều hỗ trợ extension này, nhưng không dịch vụ nào tự bật cho bạn. Vì vậy, migration trên một managed database mới sẽ fail vì kiểu cột vector chưa tồn tại.
Hãy chạy migration như một release step khi database nằm bên ngoài.
docker run --rm --env-file .env openbot \
sh -c "cd /app/server && bun x drizzle-kit migrate --config=drizzle.config.ts"Image này cố ý không publish cổng browser. Image cũng không chứa supervisor vì supervisor cần Docker socket, trong khi các nền tảng serverless không cung cấp socket này. Không có supervisor, mọi bot dùng chung một browser và cùng một bộ thông tin đăng nhập. Điều này loại bỏ cơ chế isolation vốn là lý do chạy container riêng cho từng bot. Nếu mục đích của bạn là dùng login riêng cho từng bot, hãy chạy compose stack với COMPUTER_SUPERVISOR_URL và SUPERVISOR_TOKEN được thiết lập, trên một host mà bạn chấp nhận trade-off này. Process có thể giao tiếp với Docker socket có thể start một privileged container, nên trên thực tế process đó có quyền root trên host. Đây là lý do hợp lý để chạy OpenBot trên một máy riêng, tương tự như cấp cho coding agent một VM dùng một lần.
Vì sao OPENBOT_SINGLE_USER chỉ phù hợp với laptop
.env.example được phát hành kèm OPENBOT_SINGLE_USER=true. Thiết lập này xem mọi request là do một administrator gửi và bỏ qua hoàn toàn bước sign-in. Trên laptop, đây là cách tiện lợi vì chỉ bạn mới có thể truy cập port đó. Trên VPS, người đầu tiên truy cập port 3010 sẽ trở thành administrator của một hệ thống lưu credential đã mã hóa và điều khiển một browser đã sign-in vào các account của bạn.
Có 2 cách chạy phù hợp. Giữ OPENBOT_SINGLE_USER=true, bind mọi port vào 127.0.0.1, rồi chỉ truy cập app qua SSH tunnel hoặc private network interface.
ssh -N -L 3010:127.0.0.1:3010 -L 3001:127.0.0.1:3001 you@your-vpsKhi đó, app nằm tại http://localhost:3010 trong browser của bạn. Đây được tính là secure context, nên sign-in cookie và các tính năng của browser mà live screen cần đều hoạt động. Cách còn lại là tắt single-user mode và cấu hình một identity provider thực sự. Google, Microsoft Entra, Okta, SAML và OIDC được hỗ trợ. Mọi provider cũng cần BETTER_AUTH_SECRET có độ dài từ 32 ký tự trở lên, BETTER_AUTH_URL được đặt thành public API base URL để nhận OAuth callback, INITIAL_ADMIN_EMAILS và TRUSTED_ORIGINS. Credential của provider phải đầy đủ. Provider cấu hình dở dang sẽ khiến quá trình khởi động dừng lại thay vì chuyển sang open access. Nếu bạn thêm account vì mỗi người trong team muốn có agent riêng thay vì browser riêng, OneCLI được thiết kế ngay từ đầu cho mô hình đó, với một agent được sandbox riêng cho mỗi người và các model key được giữ trong một gateway duy nhất.
Nếu app có thể truy cập bằng một public name, hãy đặt TLS (transport layer security) phía trước app. Một trang được phục vụ qua http:// thuần trên bất kỳ địa chỉ nào ngoài localhost không phải là secure context. Vì vậy, cookie có thuộc tính Secure sẽ không được lưu và sign-in sẽ fail theo cách dễ bị hiểu nhầm là lỗi trong OpenBot.
Thiết lập firewall cho các cổng cấp thấp
Ghi chú bảo mật của OpenBot nêu rõ rằng các endpoint dịch vụ cấp thấp được bảo vệ bằng token, bạn nên giữ chúng ở chế độ private và không được dùng chúng để bypass gateway. Token là lớp bảo vệ thứ hai. Lớp đầu tiên là không thể truy cập cổng đó.
agent-computer lắng nghe trên cổng 4100 và yêu cầu COMPUTER_TOKEN. Các endpoint của bot lắng nghe trên cổng 4200 và 4201. supervisor lắng nghe trên cổng 4500 trên host và cổng 4300 bên trong container. PostgreSQL lắng nghe trên cổng 5432. Không cổng nào trong số đó nên nằm trên interface public. Với deployment chỉ dành cho một người dùng, app và API cũng không nên nằm trên interface public.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verboseCó một bẫy ở đây thường khiến những người cho rằng chỉ cần firewall là đủ gặp lỗi. Việc publish một cổng của container bằng -p 3001:3001 khiến Docker cài một rule DNAT. Vì vậy, traffic được xử lý trong đường đi FORWARD và không bao giờ đi qua chain INPUT, nơi áp dụng chính sách deny mặc định của ufw. Cổng vẫn mở dù ufw status vẫn in ra Status: active. Hãy bind cổng đã publish vào loopback ngay trong mapping bằng -p 127.0.0.1:3001:3001, hoặc đặt địa chỉ host trong file compose. Hãy xác minh bằng ss -ltnp, không phải bằng ufw status. Bẫy này không riêng gì OpenBot, nên hãy kiểm tra tương tự với mọi container khác mà bạn đã publish trên máy, bao gồm cả dịch vụ đang phục vụ thư viện Jellyfin được dựng lại như một cửa hàng video thập niên 90.
OpenBot không phải là một stack offline
Hãy xác định điều này trước khi lập kế hoạch triển khai. OpenBot phụ thuộc vào một project Intelligence của CopilotKit. Project này lưu các thread lâu dài và memory của cuộc trò chuyện bên ngoài máy chủ của bạn. Server xác thực INTELLIGENCE_API_URL, INTELLIGENCE_GATEWAY_WS_URL, INTELLIGENCE_API_KEY và COPILOTKIT_LICENSE_TOKEN khi khởi động. Cả 4 giá trị phải cùng tồn tại, nếu không quá trình khởi động sẽ fail. Tính đến August 2026, có một free plan. Intelligence cũng có thể tự host, nên vẫn có thể triển khai hoàn toàn nội bộ, nhưng sẽ cần nhiều công sức hơn so với quickstart.
Model là dependency bên ngoài thứ hai. Sản phẩm không đi kèm model. BOT_PROVIDER chấp nhận openai, anthropic hoặc google. OPENAI_BASE_URL trỏ OpenAI path đến bất kỳ endpoint tương thích nào. Đây là cách chạy Ollama trên VPS để tự host một LLM nếu bạn muốn token nằm trên phần cứng của mình. Tác vụ điều khiển trình duyệt đòi hỏi nhiều ở model. Vì vậy, hãy kiểm tra một model local bằng tác vụ thực tế trước khi quyết định sử dụng model đó.
Chạy 1 replica trong giai đoạn hiện tại
Gateway lưu cache snapshot của trang trong bộ nhớ của tiến trình server. Khi có 2 replica, snapshot do một tiến trình tạo ra sẽ không hiển thị với tiến trình còn lại. Vì vậy, các action thỉnh thoảng thất bại với lỗi không tìm thấy element và có vẻ xảy ra ngẫu nhiên. Tài liệu triển khai nêu rõ: chỉ chạy 1 replica và đặt giới hạn số instance tối đa của platform là 1. Giới hạn này sẽ được gỡ bỏ khi việc cache snapshot chuyển sang database. Cho đến lúc đó, bạn scale OpenBot bằng cách nâng cấp máy chủ, không phải thêm máy chủ. Các bot vẫn được cô lập bằng các container riêng cho từng bot, tương tự như sandbox agent tự host giúp ngăn lỗi của một agent ảnh hưởng đến các agent khác.
Các dạng lỗi và dấu hiệu bạn sẽ thấy
Startup thoát ngay sau khi bạn điền .env. Server xác thực cấu hình trước khi phục vụ bất kỳ yêu cầu nào. Một block Intelligence chưa đầy đủ, thiếu KEY_ENCRYPTION_KEY hoặc OAuth provider có client ID nhưng không có secret đều khiến startup dừng thay vì âm thầm chạy tiếp. Đọc lỗi đầu tiên, sửa đúng field đó rồi khởi động lại.
Migration thất bại trên managed database. Extension vector không được bật mặc định, nên migration gặp kiểu cột mà PostgreSQL không biết. Kết nối bằng superuser, chạy CREATE EXTENSION vector; rồi chạy lại bước migration.
App tải được nhưng đăng nhập không bao giờ được giữ lại. Bạn đang phục vụ qua http:// thuần trên địa chỉ public. Đây không phải secure context nên cookie Secure bị loại bỏ. Đặt TLS ở phía trước hoặc dùng SSH tunnel để browser nhìn thấy localhost.
Các bot dùng chung những login mà bạn nghĩ phải tách riêng. Supervisor chưa chạy nên không có máy tính riêng cho từng bot, và mọi bot đều dùng browser dùng chung. Xác nhận COMPUTER_SUPERVISOR_URL đã được set và supervisor có thể truy cập Docker socket.
Bot dừng và yêu cầu trợ giúp. Đó là thiết kế đang hoạt động đúng. Audit trail ghi lại computer.help_requested, bạn tiếp quản trên màn hình trực tiếp, và việc bàn giao được ghi lại ở cả hai phía.
FAQ
Có an toàn khi để OPENBOT_SINGLE_USER bật trong môi trường triển khai trên VPS không?
Chỉ an toàn khi không thể truy cập gateway từ Internet. OPENBOT_SINGLE_USER=true chấp nhận mọi request dưới danh nghĩa một administrator mà không cần sign-in, nên bất kỳ ai mở được cổng đều có toàn quyền với deployment, credentials đã lưu và browser đã sign-in của deployment đó. Cấu hình này chấp nhận được khi mọi cổng đều bind vào 127.0.0.1 và bạn truy cập app qua SSH tunnel hoặc private network interface. Trên public interface, hãy tắt tùy chọn này và cấu hình Google, Microsoft Entra, Okta hoặc OIDC cùng với BETTER_AUTH_SECRET, BETTER_AUTH_URL, INITIAL_ADMIN_EMAILS và TRUSTED_ORIGINS.
Một OpenBot bot cần bao nhiêu RAM?
Số liệu do project công bố cho một Bot trên arm64 cho thấy mức memory cao nhất là 0.55 GB, mức tối thiểu được tài liệu ghi nhận là 2 GB và mức khuyến nghị là 4 GB. Chưa có số liệu được công bố cho trường hợp chạy nhiều bot cùng lúc, vì mỗi bot có một Chromium riêng. Hãy chạy một bot với tác vụ thực tế, đọc memory của container đó trong docker stats, cộng thêm gateway và database, rồi nhân với số bot dự kiến chạy đồng thời.
Tôi có cần tài khoản CopilotKit để self-host OpenBot không?
Có. OpenBot phụ thuộc vào một project CopilotKit Intelligence để lưu threads và memory lâu dài. Server sẽ từ chối khởi động nếu chưa đặt Intelligence API URL, gateway WebSocket URL, API key và license token. Tính đến August 2026, CopilotKit có free plan. Intelligence cũng có thể self-host, nên có thể loại bỏ dependency hosted này nếu chấp nhận cấu hình thêm. Bạn cũng phải cung cấp model API key của mình, vì OpenBot không đi kèm model nào.
Vì sao mỗi bot có browser riêng thay vì dùng chung?
Vì browser profile là một identity. Browser dùng chung đồng nghĩa với cookies và sessions dùng chung, nên khi một bot sign-in vào một account thì mọi bot đều đã sign-in vào account đó. Container riêng cho từng bot cấp cho mỗi coworker một profile riêng và các thông tin đăng nhập riêng. Đổi lại, hệ thống tốn thêm memory, vì một Chromium cho mỗi bot là thành phần chiếm nhiều tài nguyên nhất trong sizing.
Những cổng OpenBot nào nên được mở trên firewall?
Không mở các cổng bên dưới này. Agent-computer trên 4100, các bot endpoint trên 4200 và 4201, supervisor trên 4500 và PostgreSQL trên 5432 đều phải giữ private. Project bảo vệ chúng bằng token và yêu cầu bạn vẫn giữ chúng ở trạng thái không thể truy cập từ bên ngoài. Chỉ publish những gì người dùng cần mở. Lưu ý rằng container port được publish bằng -p 3001:3001 vẫn có thể truy cập bất kể rule default-deny của ufw, vì rule DNAT của Docker đưa traffic đó vào path FORWARD thay vì INPUT.