SSD Nodes Learn 🎉 VPS từ $4.99/tháng
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-08-07

Tự host KiroCrew trên VPS chạy 24/7 với Docker

Chạy KiroCrew trên VPS bằng Docker và systemd để session, memory, lịch job sống qua reboot. Có SSH, backup, rollback và giới hạn gateway port 5476.

Vì sao nên tự host KiroCrew trên VPS thay vì laptop

Tự host KiroCrew chỉ hiệu quả trên một máy không bao giờ ngủ, vì vậy VPS là nơi phù hợp còn laptop thì không. KiroCrew lưu lịch sử session, bộ nhớ ngữ nghĩa, các job đã lên lịch và hàng đợi phê duyệt trên disk, rồi nạp lại toàn bộ khi process khởi động lại. Những dữ liệu này không có tác dụng nếu process không chạy vào lúc 03:00 khi đến hạn một job đã lên lịch, và laptop đã đóng thì không chạy process đó.

KiroCrew là agent workspace mã nguồn mở của nhóm Kiro, được cấp phép theo Apache 2.0, với các bản phát hành công khai đầu tiên xuất hiện vào đầu tháng 08 năm 2026. Một process có tên gateway quản lý state và cung cấp web dashboard trên port 5476. Bạn truy cập gateway đó từ dashboard, từ kirocrew CLI hoặc từ một kênh chat như Slack. Gateway là thành phần duy nhất bạn tự host, vì vậy hướng dẫn này tập trung vào việc giữ gateway luôn chạy, không cho gateway tiếp xúc với Internet công cộng và có thể khôi phục gateway sau một lần upgrade lỗi.

Có 2 điều cần biết trước khi bắt đầu. KiroCrew điều khiển kiro-cli, công cụ này cần đăng nhập một lần bằng tài khoản Kiro, còn việc inference của agent được tính phí theo Kiro plan, nên tính đến tháng 08 năm 2026 đây không phải là một setup offline. Project này cũng mới chỉ tồn tại vài tuần. Hãy giả định rằng đến một lúc nào đó bạn sẽ cần rollback, và cài đặt theo cách cho phép bạn rollback. Nếu trước đây bạn chưa chạy agent trên server, chạy coding agent trên VPS trình bày các nguyên tắc cơ bản mà hướng dẫn này sử dụng.

Những gì KiroCrew cần và nơi lưu state

Cài native cần Python 3.10 trở lên (project khuyến nghị 3.12), Node.js 18 trở lên nếu bạn build dashboard từ source, và kiro-cli. Lần chạy đầu tiên sẽ cài đặt và đăng nhập kiro-cli cho bạn. Cài bằng container không cần các thành phần đó trên host. Cách này cần Docker. Đây là lý do chính để ưu tiên cài bằng container.

State được lưu trong ~/.kiro/crew. Biến môi trường KIROCREW_HOME cho phép chuyển state sang nơi khác. Bên trong có:

  • config.json: cấu hình gateway và credential của các kênh chat.
  • .env: secret.
  • workspace/memory/: preference, ghi chú project và lịch sử chat.
  • memory.dbmemory_index.db: index semantic và full-text.
  • models/: embedding model, được download ở lần chạy đầu tiên.
  • gateway.logsecurity_events.jsonl: log runtime và security event log.

Thư mục đó chính là bản cài đặt. Copy nó sang một VPS mới là bạn đã chuyển agent sang đó. Vì vậy, phần backup bên dưới quan trọng hơn phần cài đặt.

Hãy dự trù disk thay vì RAM. Gateway là một process Python. Thành phần thực sự tải cho máy là bất cứ thứ gì agent chạy, chẳng hạn một build hoặc một test suite. Thư mục state sẽ tăng theo lịch sử chat. Embedding model được tải ở lần khởi động đầu tiên. Vì vậy, sau vài tuần hãy dùng du -sh ~/.kiro/crew để đo trực tiếp trên máy của bạn, thay vì tin vào bất kỳ con số nào được công bố trong tháng đầu tiên của một project.

Nên dùng đường dẫn cài đặt nào trong ba đường dẫn

Dự án cung cấp ba cách cài đặt. Trình cài đặt một dòng tải một wheel và thêm kirocrew vào PATH của bạn:

curl -fsSL https://download.crew.kiro.dev/cli.sh | sh

Trình cài đặt nhận flag channel và flag version:

curl -fsSL https://download.crew.kiro.dev/cli.sh | sh -s -- --channel insider
curl -fsSL https://download.crew.kiro.dev/cli.sh | sh -s -- --version 0.1.3

Container image được publish tại ghcr.io/kirodotdev/kirocrew, dành cho linux/amd64linux/arm64 ở mọi tag. Cách build từ source cần git clone cùng với make build, phù hợp với người thay đổi code, không phù hợp với người chỉ chạy ứng dụng.

Hãy dùng container. Cài đặt native đặt các Python package, Node và kiro-cli trên cùng host đang chạy các service khác của bạn. Vì vậy, nếu quá trình nâng cấp gặp lỗi, bạn phải tự xử lý và khôi phục từng phần. Container giữ runtime trong một image và state trong một volume. Khi đó, rollback chỉ cần đổi tag rồi restart.

Ghim image vào release tag, không ghim vào stable

Ví dụ của chính dự án sử dụng tag stable:

docker run -d --name kirocrew \
  -p 127.0.0.1:5476:5476 \
  -v kirocrew-home:/home/kirocrew \
  ghcr.io/kirodotdev/kirocrew:stable

stable là một moving tag. Tag này trỏ đến release stable mới nhất tại mỗi thời điểm. Vì vậy, lần pull tiếp theo có thể thay đổi version đang chạy mà bạn không chủ động chọn, và tag không cho biết đó là version nào. Version tag là immutable, nên hãy ghim vào một version cụ thể. Release mới nhất tính đến ngày 6 August 2026 là 0.1.3, được phát hành ngày 5 August 2026. Ngoài ra còn có tag nightly. Với một dự án còn mới như vậy, điều này có nghĩa là code đã thay đổi vào sáng nay.

Viết /opt/kirocrew/compose.yaml:

services:
  kirocrew:
    image: ghcr.io/kirodotdev/kirocrew:0.1.3
    container_name: kirocrew
    restart: unless-stopped
    ports:
      - "127.0.0.1:5476:5476"
    volumes:
      - kirocrew-home:/home/kirocrew

volumes:
  kirocrew-home:

Khởi động container, rồi kiểm tra health endpoint mà image cũng dùng cho HEALTHCHECK của chính nó:

cd /opt/kirocrew
docker compose up -d
docker compose ps
curl -s http://127.0.0.1:5476/api/health

docker compose ps sẽ báo container ở trạng thái healthy trong khoảng một phút, và /api/health trả lời mà không cần token. /api/live/api/ready cũng vậy, nên có thể dùng chúng làm probe. Nếu trạng thái vẫn là starting, hãy đọc docker logs kirocrew trước khi thay đổi bất cứ thứ gì. Lần chạy đầu tiên sẽ tải embedding model, nên đường truyền chậm có thể khiến lần khởi động đầu tiên mất nhiều thời gian.

Giữ KiroCrew luôn chạy bằng systemd

restart: unless-stopped sẽ khởi động lại container sau khi bị crash và sau khi reboot, miễn là Docker tự khởi động cùng hệ thống. File unit làm rõ dependency này và cung cấp một lệnh duy nhất để dừng toàn bộ stack trước khi backup. Khởi động stack Docker Compose cùng hệ thống trình bày mẫu cấu hình chung. Đây là cấu trúc dành cho KiroCrew, trong /etc/systemd/system/kirocrew.service:

[Unit]
Description=KiroCrew gateway
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/kirocrew
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now kirocrew
systemctl status kirocrew

systemctl status kirocrew phải hiển thị active (exited). Đây là kết quả bình thường của unit này. Dùng Type=oneshot với RemainAfterExit=yes là đúng trong trường hợp này vì docker compose up -d trả về ngay khi container được khởi động: systemd theo dõi việc stack đã chạy, không theo dõi một tiến trình foreground. Nếu viết Type=simple, systemd sẽ thấy lệnh kết thúc ngay lập tức, đánh dấu service là đã dừng, rồi hoặc bỏ cuộc hoặc liên tục restart tùy theo thiết lập Restart= của bạn. Với bản cài native, project cung cấp thành phần tương đương là kirocrew service install. Thành phần này ghi /etc/systemd/system/kirocrew.service và chạy gateway bằng user của bạn. Không chạy cả hai unit. Phần trình bày rộng hơn về chủ đề này có tại service và timer của systemd trên VPS.

Lần đầu chạy: đăng nhập và lấy dashboard token

Container khởi động gateway, nhưng agent runtime chưa đăng nhập. Hãy đăng nhập bên trong container:

docker exec -it kirocrew kiro-cli login

Lệnh này in ra device code và một URL. Mở URL đó bằng browser của bạn. Sau đó tạo dashboard token:

docker exec kirocrew kirocrew token --ttl 2h

URL của dashboard là http://localhost:5476/?token=<the token>. Token sẽ hết hạn: session mặc định kéo dài một giờ và thời hạn tối đa được tài liệu ghi nhận là hai mươi giờ. Nếu dashboard tải lên nhưng để trống hoặc ngay lập tức chuyển bạn quay lại trang đăng nhập, nguyên nhân thường là token đã hết hạn. Hãy tạo token mới. Không bao giờ dán token vào ticket hoặc tin nhắn chat, vì ai giữ token thì người đó kiểm soát agent của bạn.

Truy cập dashboard qua SSH và không bao giờ public port 5476

Xem lại địa chỉ bind trong ví dụ của project: -p 127.0.0.1:5476:5476. Bên trong container, gateway lắng nghe trên 0.0.0.0 vì nó phải nhận được traffic thông qua port mapping, nhưng mapping này chỉ public port trên loopback của host. Xóa tiền tố 127.0.0.1: là gateway sẽ được public trên Internet cho bất kỳ ai quét port đó. Rule của firewall cũng không bảo vệ được bạn: Docker public port bằng cách ghi các rule DNAT, được xử lý trước bộ lọc của ufw, nên ufw deny 5476 không có tác dụng với port đã public. Docker bypass ufw qua port giải thích cơ chế này.

Forward port qua SSH từ laptop của bạn:

ssh -N -L 5476:127.0.0.1:5476 you@your-server.example.com

Giữ kết nối đó chạy rồi mở http://localhost:5476/?token=<the token> trên máy local. Để tự động tạo forward mỗi lần kết nối, thêm nó vào ~/.ssh/config:

Host your-server.example.com
    LocalForward 5476 127.0.0.1:5476

Nếu port 5476 đã được sử dụng trên laptop, chỉ đổi số bên trái: ssh -N -L 45476:127.0.0.1:5476 you@your-server.example.com, rồi truy cập http://localhost:45476/?token=....

Có một hành vi đã được ghi nhận khi sử dụng tunnel: gateway xem các request được forward là request từ xa, nên các endpoint ghi cấu hình và tiết lộ secret trong dashboard sẽ từ chối chúng. Một thay đổi setting không thể lưu qua SSH là do hành vi này, không phải bug. Hãy sửa config trực tiếp trên host:

docker cp kirocrew:/home/kirocrew/.kiro/crew/config.json .
# edit config.json here
docker cp config.json kirocrew:/home/kirocrew/.kiro/crew/config.json
docker exec -u 0 kirocrew chown kirocrew:kirocrew /home/kirocrew/.kiro/crew/config.json
docker restart kirocrew

Để truy cập từ điện thoại, project hướng dẫn dùng tailscale serve của Tailscale. Cách này giữ dashboard bên trong tailnet của bạn thay vì public trên một hostname. Hãy ưu tiên cách này thay cho reverse proxy public. Token nằm trong URL, và URL sẽ được ghi vào mọi access log trên đường đi của request.

Cấp cho agent phạm vi ảnh hưởng nhỏ nhất có thể

Container sẽ kiểm tra khả năng hỗ trợ sandbox trong lần khởi động đầu tiên. Kết quả này quyết định agent có được phép thực thi hay không. Nếu có isolation bằng namespace, các subprocess của agent sẽ chạy trong môi trường isolated. Nếu không có và KIROCREW_ALLOW_UNSANDBOXED=1 chưa được thiết lập, hệ thống sẽ từ chối thực thi thay vì chạy unconfined. Vì vậy, nếu gateway trông vẫn hoạt động nhưng mọi task đều bị treo, đây thường là nguyên nhân. Quyết định này được lưu trong docker logs kirocrew sau lần chạy đầu tiên. Project cũng cung cấp profile seccomp (secure computing mode) để bạn áp dụng:

curl -fsSL https://raw.githubusercontent.com/kirodotdev/KiroCrew/main/docker/seccomp/kirocrew-seccomp.json \
  -o /opt/kirocrew/kirocrew-seccomp.json
    security_opt:
      - seccomp:./kirocrew-seccomp.json

Nếu bạn thiết lập KIROCREW_ALLOW_UNSANDBOXED=1, cần hiểu rõ thay đổi đã xảy ra: container giờ là boundary duy nhất giữa agent và server của bạn. Cảnh báo của project đáng được nhắc lại đầy đủ. Không mount các path trên host mà bạn sẽ không giao trực tiếp cho agent. Trên thực tế, điều này loại trừ Docker socket, mọi bind mount của / và mọi directory chứa dữ liệu của service khác.

Phần còn lại là khung bảo vệ áp dụng cho mọi agent được phép chạy command. Giới hạn credential của agent vào đúng repository hoặc bucket mà nó cần. Tuyệt đối không dùng personal token có quyền trên toàn account. Chạy agent bằng một user riêng, có home không chứa dữ liệu nào khác. Đây là mục đích của user có quyền tối thiểu trên VPS. Khi agent ghi code rồi chạy chính code đó, hãy cung cấp một máy mà nó được phép làm hỏng: VM dùng một lần cho coding agent tạo boundary mạnh hơn bất kỳ flag nào trong compose file này, vì bạn chỉ cần xóa VM thay vì dọn dẹp nó. Cùng cách suy luận này áp dụng cho chạy OpenClaw an toàn trên VPStự host agent Hermes trên VPS. Công việc được schedule cũng tiêu tốn tiền trong lúc bạn ngủ, vì chi phí inference được tính vào Kiro plan của bạn. Do đó, hãy thiết lập các giới hạn được mô tả trong kiểm soát chi phí của AI agent trên VPS trước khi thêm job chạy hằng đêm.

Sao lưu volume state trước mỗi lần nâng cấp

Trước tiên, tìm tên volume thực tế. Compose thêm tên project vào trước tên named volume. Tên project mặc định là tên thư mục. Vì vậy, volume được khai báo là kirocrew-home trong /opt/kirocrew/compose.yaml sẽ được tạo với tên kirocrew_kirocrew-home:

docker volume ls

Dừng gateway trước khi sao chép. memory.dbmemory_index.db là các database SQLite. Sao chép database khi đang được ghi có thể lấy phải transaction chưa ghi xong, khiến file bị hỏng sau khi restore. Hướng dẫn migration của project cũng nêu rõ điều này: chỉ di chuyển memory khi các gateway đã dừng.

sudo systemctl stop kirocrew
docker run --rm -v kirocrew_kirocrew-home:/data:ro -v "$PWD":/backup \
  alpine tar czf /backup/kirocrew-2026-08-06.tgz -C /data .
sudo systemctl start kirocrew

Sao chép archive ra khỏi máy chủ. Để restore, dùng cùng lệnh với container đã dừng và thay tar czf bằng tar xzf:

sudo systemctl stop kirocrew
docker run --rm -v kirocrew_kirocrew-home:/data -v "$PWD":/backup \
  alpine tar xzf /backup/kirocrew-2026-08-06.tgz -C /data
sudo systemctl start kirocrew

Di chuyển sang host mới là công việc khác với restore tại chỗ, và project có hướng dẫn cụ thể cho việc này. Lịch sử chat và ghi chú project trong workspace/memory/ sẽ được chuyển sang. Hai file database và config.json cũng được chuyển sang. PID file, security event log và .env gắn với host cũ, nên không chuyển chúng. Hãy nhập lại các secret trên máy chủ mới.

Cách rollback sau một lần nâng cấp lỗi

Nâng cấp diễn ra nhanh và chỉ an toàn vì bạn đã cố định version. Hãy tạo backup trước, sau đó đổi tag:

sudo systemctl stop kirocrew
# take the backup here, as above
sudo nano /opt/kirocrew/compose.yaml   # set the new image tag
sudo systemctl start kirocrew
docker compose -f /opt/kirocrew/compose.yaml ps
curl -s http://127.0.0.1:5476/api/health

docker compose up -d sẽ pull image nếu image chưa có trên máy, nên sửa tag là toàn bộ quy trình nâng cấp. Rollback cũng thực hiện theo trình tự đó với số version cũ. Cách này cung cấp chính xác image bạn đã dùng trước đó vì các version tag là bất biến.

Binary sẽ rollback sạch. Phần state có thể không như vậy. Gateway mới hơn có thể ghi lại config.json hoặc migrate các database trong memory sang định dạng mà gateway cũ không đọc được. Tính đến tháng 8 năm 2026, chưa có downgrade path nào được tài liệu hóa. Vì vậy, nếu image cũ khởi động rồi hoạt động bất thường, đừng debug. Hãy stop image đó, restore backup đã tạo trước khi nâng cấp, rồi khởi động lại. Đó là toàn bộ lý do backup phải được thực hiện trước. Đây cũng là lý do thói quen nâng cấp trước rồi mới backup không phù hợp với một project còn mới như thế này.

Điều chưa được chứng minh ở đây

Hãy đánh giá đúng tuổi đời của phần mềm này. Version 0.1.3 mới ra mắt được vài ngày tại thời điểm viết bài. Release notes của nó chỉ là các liên kết changelog được tạo tự động, không phải ghi chú migration. Phần mềm cũng chưa có lịch sử nâng cấp thực tế. Không có nội dung nào trong hướng dẫn này là kết quả đã được kiểm chứng trong thời gian dài. Vì vậy, hãy tự đo mức sử dụng memory, kích thước database và độ tin cậy của scheduler trên máy chủ của bạn, thay vì mặc định rằng chúng sẽ ổn định.

Có 2 hành vi bạn nên tự kiểm tra trước khi phụ thuộc vào chúng. Thứ nhất là liệu bản downgrade có đọc được state do version mới hơn ghi hay không. Hãy thử trên một bản sao của volume khi việc thử nghiệm chưa gây ảnh hưởng, không thực hiện trong lúc đang xử lý outage. Thứ hai là gateway xử lý thế nào khi phiên đăng nhập Kiro hết hạn đúng lúc scheduled job đến hạn chạy. Đây đều là những vấn đề thường được dự án còn mới âm thầm khắc phục giữa các lần release, và hiện tại bạn có thể kiểm tra cả 2 vấn đề này với rất ít công sức.

FAQ

Vì sao dashboard KiroCrew không mở được trên public IP của server?

Vì ví dụ được công bố bind cổng vào loopback. -p 127.0.0.1:5476:5476 chỉ map cổng của container vào địa chỉ loopback của host, và đây là chủ ý thiết kế. Hãy truy cập bằng cách forward cổng qua SSH với ssh -N -L 5476:127.0.0.1:5476 you@your-server, rồi mở http://localhost:5476/?token=<token> trên laptop. Xóa tiền tố 127.0.0.1: để cho phép truy cập từ bên ngoài sẽ đưa gateway lên public Internet. Một rule của firewall cũng không ngăn được việc này, vì các rule DNAT cho published port của Docker được đánh giá trước khi ufw lọc traffic.

KiroCrew lưu dữ liệu ở đâu và tôi cần backup những gì?

Mọi dữ liệu nằm dưới ~/.kiro/crew, tương ứng với /home/kirocrew/.kiro/crew bên trong container image, và KIROCREW_HOME dùng để chuyển vị trí này. Hãy backup toàn bộ thư mục hoặc toàn bộ Docker volume khi gateway đã dừng. memory.dbmemory_index.db là các database SQLite, nên bản sao được tạo trong lúc gateway đang ghi có thể không nhất quán. Khi chuyển sang host mới, workspace/memory/, 2 file database và config.json sẽ được chuyển theo. PID file, security event log và .env thuộc về host cũ.

Tôi nên dùng tag stable hay tag phiên bản?

Hãy dùng tag phiên bản. stable thay đổi mỗi khi có release mới, nên phiên bản đang chạy có thể tự thay đổi ở lần pull tiếp theo. Bản thân tag này cũng không cho biết image nào đang chạy. Các tag phiên bản như 0.1.3 là immutable. Đây chính là điều giúp rollback hoạt động: khôi phục số phiên bản cũ và nhận lại image giống hệt. Tính đến ngày 6 August 2026, release mới nhất là 0.1.3.

Vì sao agent của tôi từ chối chạy mọi command?

Container kiểm tra khả năng hỗ trợ sandbox trong lần khởi động đầu tiên. Nếu container không thể cô lập các subprocess của agent và KIROCREW_ALLOW_UNSANDBOXED=1 chưa được set, nó sẽ từ chối thực thi thay vì chạy chúng mà không có sandbox. Vì vậy gateway vẫn có vẻ healthy nhưng mọi task đều bị treo. docker logs kirocrew hiển thị quyết định sandbox từ lần chạy đầu tiên đó. Việc set biến này khiến container trở thành ranh giới duy nhất giữa agent và host. Vì vậy, nếu set biến, không mount bất kỳ thứ gì mà bạn không sẵn sàng giao trực tiếp cho agent.

Tôi có cần tài khoản Kiro để self-host KiroCrew không?

Có, tính đến August 2026. KiroCrew là free software theo giấy phép Apache 2.0, nhưng nó điều khiển kiro-cli. Thành phần này yêu cầu sign-in một lần, còn việc inference của agent được tính phí vào Kiro plan. Trong container, chạy docker exec -it kirocrew kiro-cli login rồi approve device code trong browser. Cho đến khi hoàn tất sign-in, gateway vẫn khởi động và dashboard vẫn tải được, nhưng agent không có model để kết nối.