Bot 的電腦 can run under gVisor: its own kernel, Chromium's sandbox back on
容器隔離 in 設定 › 電腦: standard (runc, the container is the only wall, Chromium runs
--no-sandbox) or hardened (runsc: a virtualized kernel, all capabilities dropped but the few
the desktop needs, ANYBOT_BOX_SANDBOX=1 turns Chromium's own sandbox back on). Box image v7.
deploy/mac/gvisor-vm.sh makes a Lima VM with Docker + gVisor for a Mac (started at login),
gvisor-migrate.sh moves the box's files and logins there.
Checked and finished before committing:
- the hardened choice is offered only on a Docker host that has runsc; a box set to it on a
host without it opens the standard way and says so (it used to not start at all)
- the settings row shows what the box really runs on, and when 更新 is needed
- no swap only under gVisor (a standard box keeps Docker's default)
- the migrate script sees the running Mac app ("AnyBot", not "anybot")
- the VM script starts an existing VM by name, checks runsc and the kernel from the Mac
- the version test says 7
Real run in the Lima VM: desktop, VNC, numbered controls, xdotool and screenshots work; no
Chromium process has --no-sandbox, renderers run with seccomp and their own namespaces.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha2RVfSYmrhqNnqx9Z4
2026-11-06 16:03:25 +00:00
|
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
# 強隔離 on this Mac: macOS can't run gVisor directly, and OrbStack/Docker Desktop's Linux VM
|
|
|
|
|
|
# can't take it. This makes a small Ubuntu VM (Lima, Apple Virtualization) with its OWN Docker
|
|
|
|
|
|
# and gVisor (runsc): Bot 的電腦 runs there on a virtualized kernel, verified by a sandboxed
|
|
|
|
|
|
# Chromium — the Mac's kernel is a whole VM away.
|
|
|
|
|
|
#
|
|
|
|
|
|
# ./gvisor-vm.sh create + start the VM (idempotent; re-run to fix/update)
|
|
|
|
|
|
# ./gvisor-vm.sh --rm remove the VM (the box's files live in a volume inside it)
|
|
|
|
|
|
#
|
|
|
|
|
|
# Afterwards, in AnyBot 設定 › 電腦 › 在哪裡執行:
|
|
|
|
|
|
# Docker 主機: ssh://lima-anybot-gvisor
|
|
|
|
|
|
# 容器隔離: 強隔離(gVisor)
|
|
|
|
|
|
# and press 更新 on the computer card. (AnyBot's Docker host accepts ssh://, the VNC viewer
|
|
|
|
|
|
# forwards through it.)
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
VM=anybot-gvisor
|
|
|
|
|
|
CPUS=4
|
2026-11-09 07:24:28 +00:00
|
|
|
|
MEM=4 # GiB: the box is capped at 2 GB, Docker and the system take ~0.5 GB.
|
|
|
|
|
|
# The Mac never gets back memory the VM once used, so a bigger VM
|
|
|
|
|
|
# just grows bigger (it reached all of 6 GB).
|
Bot 的電腦 can run under gVisor: its own kernel, Chromium's sandbox back on
容器隔離 in 設定 › 電腦: standard (runc, the container is the only wall, Chromium runs
--no-sandbox) or hardened (runsc: a virtualized kernel, all capabilities dropped but the few
the desktop needs, ANYBOT_BOX_SANDBOX=1 turns Chromium's own sandbox back on). Box image v7.
deploy/mac/gvisor-vm.sh makes a Lima VM with Docker + gVisor for a Mac (started at login),
gvisor-migrate.sh moves the box's files and logins there.
Checked and finished before committing:
- the hardened choice is offered only on a Docker host that has runsc; a box set to it on a
host without it opens the standard way and says so (it used to not start at all)
- the settings row shows what the box really runs on, and when 更新 is needed
- no swap only under gVisor (a standard box keeps Docker's default)
- the migrate script sees the running Mac app ("AnyBot", not "anybot")
- the VM script starts an existing VM by name, checks runsc and the kernel from the Mac
- the version test says 7
Real run in the Lima VM: desktop, VNC, numbered controls, xdotool and screenshots work; no
Chromium process has --no-sandbox, renderers run with seccomp and their own namespaces.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha2RVfSYmrhqNnqx9Z4
2026-11-06 16:03:25 +00:00
|
|
|
|
DISK=60 # GiB
|
|
|
|
|
|
|
|
|
|
|
|
if [ "${1:-}" = "--rm" ]; then
|
|
|
|
|
|
limactl delete --force "$VM" 2>/dev/null || true
|
2026-11-06 16:19:56 +00:00
|
|
|
|
echo "已移除 VM ${VM}。"
|
Bot 的電腦 can run under gVisor: its own kernel, Chromium's sandbox back on
容器隔離 in 設定 › 電腦: standard (runc, the container is the only wall, Chromium runs
--no-sandbox) or hardened (runsc: a virtualized kernel, all capabilities dropped but the few
the desktop needs, ANYBOT_BOX_SANDBOX=1 turns Chromium's own sandbox back on). Box image v7.
deploy/mac/gvisor-vm.sh makes a Lima VM with Docker + gVisor for a Mac (started at login),
gvisor-migrate.sh moves the box's files and logins there.
Checked and finished before committing:
- the hardened choice is offered only on a Docker host that has runsc; a box set to it on a
host without it opens the standard way and says so (it used to not start at all)
- the settings row shows what the box really runs on, and when 更新 is needed
- no swap only under gVisor (a standard box keeps Docker's default)
- the migrate script sees the running Mac app ("AnyBot", not "anybot")
- the VM script starts an existing VM by name, checks runsc and the kernel from the Mac
- the version test says 7
Real run in the Lima VM: desktop, VNC, numbered controls, xdotool and screenshots work; no
Chromium process has --no-sandbox, renderers run with seccomp and their own namespaces.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha2RVfSYmrhqNnqx9Z4
2026-11-06 16:03:25 +00:00
|
|
|
|
exit 0
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
command -v limactl >/dev/null 2>&1 || { echo "先裝 Lima:brew install lima"; exit 1; }
|
|
|
|
|
|
|
|
|
|
|
|
STATUS=$(limactl list "$VM" --format '{{.Status}}' 2>/dev/null || true)
|
|
|
|
|
|
if [ "$STATUS" = "Running" ]; then
|
|
|
|
|
|
echo "VM $VM 已在執行。"
|
|
|
|
|
|
elif [ -n "$STATUS" ]; then
|
2026-11-06 16:19:56 +00:00
|
|
|
|
echo "VM $VM 是 ${STATUS},啟動中…"
|
Bot 的電腦 can run under gVisor: its own kernel, Chromium's sandbox back on
容器隔離 in 設定 › 電腦: standard (runc, the container is the only wall, Chromium runs
--no-sandbox) or hardened (runsc: a virtualized kernel, all capabilities dropped but the few
the desktop needs, ANYBOT_BOX_SANDBOX=1 turns Chromium's own sandbox back on). Box image v7.
deploy/mac/gvisor-vm.sh makes a Lima VM with Docker + gVisor for a Mac (started at login),
gvisor-migrate.sh moves the box's files and logins there.
Checked and finished before committing:
- the hardened choice is offered only on a Docker host that has runsc; a box set to it on a
host without it opens the standard way and says so (it used to not start at all)
- the settings row shows what the box really runs on, and when 更新 is needed
- no swap only under gVisor (a standard box keeps Docker's default)
- the migrate script sees the running Mac app ("AnyBot", not "anybot")
- the VM script starts an existing VM by name, checks runsc and the kernel from the Mac
- the version test says 7
Real run in the Lima VM: desktop, VNC, numbered controls, xdotool and screenshots work; no
Chromium process has --no-sandbox, renderers run with seccomp and their own namespaces.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha2RVfSYmrhqNnqx9Z4
2026-11-06 16:03:25 +00:00
|
|
|
|
limactl start --tty=false "$VM"
|
|
|
|
|
|
else
|
|
|
|
|
|
echo "建立 VM ${VM}($CPUS CPU / ${MEM}GB / ${DISK}GB,第一次要下載映像檔,幾分鐘)…"
|
|
|
|
|
|
# template:docker-rootful = Lima's rootful Docker template (runsc wants a plain root daemon;
|
|
|
|
|
|
# the rootless docker template runs the daemon in a user namespace).
|
|
|
|
|
|
limactl start --name="$VM" --tty=false --cpus "$CPUS" --memory "$MEM" --disk "$DISK" template:docker-rootful
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
echo "VM 裡安裝 gVisor(runsc,systrap 平台:不需要 KVM,ARM VM 可用)…"
|
|
|
|
|
|
limactl shell "$VM" -- bash -ec '
|
|
|
|
|
|
set -e
|
|
|
|
|
|
if ! command -v runsc >/dev/null 2>&1; then
|
|
|
|
|
|
sudo mkdir -p /etc/apt/keyrings
|
|
|
|
|
|
curl -fsSL https://gvisor.dev/archive.key | sudo gpg --dearmor -o /usr/share/keyrings/gvisor-archive-keyring.gpg
|
|
|
|
|
|
echo "deb [signed-by=/usr/share/keyrings/gvisor-archive-keyring.gpg] https://storage.googleapis.com/gvisor/releases release main" | sudo tee /etc/apt/sources.list.d/gvisor.list >/dev/null
|
|
|
|
|
|
sudo apt-get update -qq
|
|
|
|
|
|
sudo apt-get install -y -qq runsc
|
|
|
|
|
|
fi
|
|
|
|
|
|
# Register the runtime in the VM'\''s Docker daemon (merge, do not clobber other settings).
|
2026-11-06 16:19:56 +00:00
|
|
|
|
# Restart Docker only when that changed: a restart stops Bot 的電腦 running in this VM.
|
|
|
|
|
|
CHANGED=$(sudo python3 - <<EOF
|
Bot 的電腦 can run under gVisor: its own kernel, Chromium's sandbox back on
容器隔離 in 設定 › 電腦: standard (runc, the container is the only wall, Chromium runs
--no-sandbox) or hardened (runsc: a virtualized kernel, all capabilities dropped but the few
the desktop needs, ANYBOT_BOX_SANDBOX=1 turns Chromium's own sandbox back on). Box image v7.
deploy/mac/gvisor-vm.sh makes a Lima VM with Docker + gVisor for a Mac (started at login),
gvisor-migrate.sh moves the box's files and logins there.
Checked and finished before committing:
- the hardened choice is offered only on a Docker host that has runsc; a box set to it on a
host without it opens the standard way and says so (it used to not start at all)
- the settings row shows what the box really runs on, and when 更新 is needed
- no swap only under gVisor (a standard box keeps Docker's default)
- the migrate script sees the running Mac app ("AnyBot", not "anybot")
- the VM script starts an existing VM by name, checks runsc and the kernel from the Mac
- the version test says 7
Real run in the Lima VM: desktop, VNC, numbered controls, xdotool and screenshots work; no
Chromium process has --no-sandbox, renderers run with seccomp and their own namespaces.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha2RVfSYmrhqNnqx9Z4
2026-11-06 16:03:25 +00:00
|
|
|
|
import json, os
|
|
|
|
|
|
p = "/etc/docker/daemon.json"
|
|
|
|
|
|
d = json.load(open(p)) if os.path.exists(p) else {}
|
2026-11-06 16:19:56 +00:00
|
|
|
|
if d.get("runtimes", {}).get("runsc", {}).get("path") != "runsc":
|
|
|
|
|
|
d.setdefault("runtimes", {})["runsc"] = {"path": "runsc"}
|
|
|
|
|
|
os.makedirs("/etc/docker", exist_ok=True)
|
|
|
|
|
|
json.dump(d, open(p, "w"), indent=2)
|
|
|
|
|
|
print("changed")
|
Bot 的電腦 can run under gVisor: its own kernel, Chromium's sandbox back on
容器隔離 in 設定 › 電腦: standard (runc, the container is the only wall, Chromium runs
--no-sandbox) or hardened (runsc: a virtualized kernel, all capabilities dropped but the few
the desktop needs, ANYBOT_BOX_SANDBOX=1 turns Chromium's own sandbox back on). Box image v7.
deploy/mac/gvisor-vm.sh makes a Lima VM with Docker + gVisor for a Mac (started at login),
gvisor-migrate.sh moves the box's files and logins there.
Checked and finished before committing:
- the hardened choice is offered only on a Docker host that has runsc; a box set to it on a
host without it opens the standard way and says so (it used to not start at all)
- the settings row shows what the box really runs on, and when 更新 is needed
- no swap only under gVisor (a standard box keeps Docker's default)
- the migrate script sees the running Mac app ("AnyBot", not "anybot")
- the VM script starts an existing VM by name, checks runsc and the kernel from the Mac
- the version test says 7
Real run in the Lima VM: desktop, VNC, numbered controls, xdotool and screenshots work; no
Chromium process has --no-sandbox, renderers run with seccomp and their own namespaces.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha2RVfSYmrhqNnqx9Z4
2026-11-06 16:03:25 +00:00
|
|
|
|
EOF
|
2026-11-06 16:19:56 +00:00
|
|
|
|
)
|
|
|
|
|
|
if [ "$CHANGED" = changed ]; then sudo systemctl restart docker; fi
|
2026-11-09 07:24:28 +00:00
|
|
|
|
# Services a VM without modems, removable disks or SAN storage never uses (~70 MB).
|
|
|
|
|
|
sudo systemctl disable --now ModemManager.service udisks2.service multipathd.service multipathd.socket >/dev/null 2>&1 || true
|
Bot 的電腦 can run under gVisor: its own kernel, Chromium's sandbox back on
容器隔離 in 設定 › 電腦: standard (runc, the container is the only wall, Chromium runs
--no-sandbox) or hardened (runsc: a virtualized kernel, all capabilities dropped but the few
the desktop needs, ANYBOT_BOX_SANDBOX=1 turns Chromium's own sandbox back on). Box image v7.
deploy/mac/gvisor-vm.sh makes a Lima VM with Docker + gVisor for a Mac (started at login),
gvisor-migrate.sh moves the box's files and logins there.
Checked and finished before committing:
- the hardened choice is offered only on a Docker host that has runsc; a box set to it on a
host without it opens the standard way and says so (it used to not start at all)
- the settings row shows what the box really runs on, and when 更新 is needed
- no swap only under gVisor (a standard box keeps Docker's default)
- the migrate script sees the running Mac app ("AnyBot", not "anybot")
- the VM script starts an existing VM by name, checks runsc and the kernel from the Mac
- the version test says 7
Real run in the Lima VM: desktop, VNC, numbered controls, xdotool and screenshots work; no
Chromium process has --no-sandbox, renderers run with seccomp and their own namespaces.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha2RVfSYmrhqNnqx9Z4
2026-11-06 16:03:25 +00:00
|
|
|
|
# Prove the wall works: a container whose kernel really is gVisor.
|
|
|
|
|
|
docker run --rm --runtime=runsc --entrypoint sh alpine:3.20 -c "grep -q gVisor /proc/version && uname -r" | sed "s/^/runsc 容器核心: /"
|
|
|
|
|
|
'
|
|
|
|
|
|
|
|
|
|
|
|
# Bot 的電腦 lives in this VM: start it with the Mac, or after a restart the computer is gone
|
|
|
|
|
|
# until someone runs this again.
|
|
|
|
|
|
limactl autostart enable "$VM" >/dev/null 2>&1 || limactl start-at-login "$VM" --enabled >/dev/null 2>&1 || echo "(沒能設定開機自動啟動:Mac 重開機後要再跑一次這個腳本)"
|
|
|
|
|
|
|
|
|
|
|
|
# Lima forwards the VM's Docker socket to the Mac: AnyBot's Docker 主機用這個 unix:// 位址,
|
|
|
|
|
|
# 不用 ssh、不用碰 ~/.ssh/config。
|
|
|
|
|
|
SOCK="$HOME/.lima/$VM/sock/docker.sock"
|
|
|
|
|
|
DOCKER_HOST="unix://$SOCK" docker info --format '{{range $k, $v := .Runtimes}}{{$k}} {{end}}' | grep -qw runsc || { echo "從 Mac 連到 VM 的 Docker 看不到 runsc"; exit 1; }
|
|
|
|
|
|
KERNEL=$(DOCKER_HOST="unix://$SOCK" docker run --rm --runtime=runsc --entrypoint cat alpine:3.20 /proc/version | cut -d' ' -f3)
|
|
|
|
|
|
|
|
|
|
|
|
cat <<EOF
|
|
|
|
|
|
|
2026-11-06 16:19:56 +00:00
|
|
|
|
都好了(從 Mac 驗證:runsc 容器的核心是 ${KERNEL})。AnyBot 設定 › 電腦 › 在哪裡執行:
|
Bot 的電腦 can run under gVisor: its own kernel, Chromium's sandbox back on
容器隔離 in 設定 › 電腦: standard (runc, the container is the only wall, Chromium runs
--no-sandbox) or hardened (runsc: a virtualized kernel, all capabilities dropped but the few
the desktop needs, ANYBOT_BOX_SANDBOX=1 turns Chromium's own sandbox back on). Box image v7.
deploy/mac/gvisor-vm.sh makes a Lima VM with Docker + gVisor for a Mac (started at login),
gvisor-migrate.sh moves the box's files and logins there.
Checked and finished before committing:
- the hardened choice is offered only on a Docker host that has runsc; a box set to it on a
host without it opens the standard way and says so (it used to not start at all)
- the settings row shows what the box really runs on, and when 更新 is needed
- no swap only under gVisor (a standard box keeps Docker's default)
- the migrate script sees the running Mac app ("AnyBot", not "anybot")
- the VM script starts an existing VM by name, checks runsc and the kernel from the Mac
- the version test says 7
Real run in the Lima VM: desktop, VNC, numbered controls, xdotool and screenshots work; no
Chromium process has --no-sandbox, renderers run with seccomp and their own namespaces.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha2RVfSYmrhqNnqx9Z4
2026-11-06 16:03:25 +00:00
|
|
|
|
Docker 主機: unix://$SOCK
|
|
|
|
|
|
容器隔離: 強隔離(gVisor)
|
|
|
|
|
|
然後在電腦卡片按「建立/更新」。要讓舊 box 的檔案與登入跟著走,
|
|
|
|
|
|
先完全退出 AnyBot、跑同資料夾的 gvisor-migrate.sh,再回來開。
|
|
|
|
|
|
EOF
|