mcpField
E
exe-dev

exe-dev

github.com/kylelundstedt云与 DevOps58 次安装
代码仓库

关于 exe-dev

通过 SSH、SSH API 和 HTTPS API 管理 exe.dev Linux VM 的技能。内容涵盖连接方式、VM 访问,以及供脚本、Agent 或 CI 作业使用的受限签名令牌。

主要功能

  1. 01通过三种文档接口管理 VM
  2. 02使用 SSH 交互式访问 VM
  3. 03通过 SSH API 或 HTTPS API 自动执行命令
  4. 04创建受限且有时效的 Bearer 令牌
  5. 05通过 SSH 端点连接 VM

适用场景

  1. 01通过 SSH 交互式管理 VM
  2. 02在脚本或 CI 中自动执行 VM 命令
  3. 03用受限令牌限制 Agent 权限

MCP 相关

README 提及 MCP OAuth 流程,并建议使用 `ssh .exe.xyz` 建立隧道;未说明 MCP 服务或 MCP 工具。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kylelundstedt/dotfiles --skill exe-dev

安装后在 Claude Code 中输入/exe-dev确认已加载。

详细介绍

exe.dev

exe.dev 提供带持久化磁盘、即时 HTTPS 和内置身份验证的 Linux VM。

文档

三种接口

exe.dev 官方文档将三种同等的 VM 管理接口列出:SSH、SSH API(程序化 SSH)和 HTTPS API。它们使用完全相同的命令语法——HTTPS API 就是“塞进 POST 请求体里的 SSH API”。官方没有将任何一种标为首选;请根据上下文选择。

接口使用场景
SSH交互式大厅操作;熟悉的类 Unix 体验
SSH API已加载 SSH Agent 的脚本
HTTPS API限定范围/有时效的令牌;出站端口 22 被阻止的环境;强化自动化安全性
连接速率限制

当超过每个源 IP 的连接速率限制(确切阈值未公开)时,exe.dev 大厅和直接 VM SSH(*.exe.xyz)都会静默丢弃入站 TCP SYN。2026-04-21 的确认仅针对大厅——5 次突发 ssh exe.dev 调用中有 5 次超时。2026-04-23 的复测扩展了这一发现:在 VM 引导期间突发发起新的 ssh <vm>.exe.xyz 调用,在 VM 端点重现了持续数分钟的 22 端口阻断。这些端点共用某种正在生效的 SYN 丢弃防护。

避免触发此限制:

  • 为 Host exe.dev *.exe.xyz 启用 SSH 多路复用(见下文“SSH 配置”)——一个持久连接即可承载多个命令,并保持在阈值以下。这是交互式和脚本化使用中最重要的配置。
  • 对于需要执行大量大厅命令的脚本或 Agent,请使用 HTTPS API。其速率限制按 SSH 密钥计算(有文档说明),而不是静默的按 IP 阻断。
  • VM 上启用 Tailscale 后,后续访问 VM 时优先使用 Tailscale SSH(见下文“设置开发 VM”)。Tailnet 流量使用 WireGuard,而非 exe.dev 的边缘网络,因此完全绕过速率限制。
直接访问 VM(仅限 SSH)
ssh <vm>.exe.xyz              # shell
scp file.txt <vm>.exe.xyz:~/  # transfer file

每个 VM 都会获得一个带自动 TLS 的 https://<vm>.exe.xyz/。

HTTPS API 和限定范围的令牌

HTTPS API 的显著特点是使用 SSH 签名的持有者令牌,并具有限定范围的权限——适合将有限权限授予 Agent、脚本或 CI 任务,而无需交出完整的 SSH 密钥。

令牌格式:exe0.<base64url-payload>.<base64url-signature>。负载是经过签名的 JSON,包含四个字段:

字段用途
cmds明确的命令允许列表。父级命令不会授权子命令(ssh-key ≠ ssh-key list)
expUnix 过期时间戳。文档“强烈建议始终设置 exp”,尽管默认值为永不过期
nbf生效时间戳(用于定时令牌)
ctx任意签名 JSON,通过 X-ExeDev-Token-Ctx 传递给 VM;应用级授权数据

速率限制按 SSH 密钥计算——独立工作负载请使用不同的密钥。不提供重放保护,因此请使用短时有效的令牌。最大 8 KB。

创建令牌
PERMS='{"cmds":["ls","new","rm","whoami"],"exp":1800000000}'
PAYLOAD=$(printf '%s' "$PERMS" | base64 | tr -d '\n=' | tr '+/' '-_')
SIG=$(printf '%s' "$PERMS" | ssh-keygen -Y sign -f ~/.ssh/exe_dev.pub -n [email protected] 2>/dev/null | sed '1d;$d' | tr -d '\n' | tr '+/' '-_' | tr -d '=')
TOKEN="exe0.$PAYLOAD.$SIG"

ssh-keygen -Y sign 可与 1Password 的 SSH Agent 配合使用——传入公钥文件,由 Agent 负责签名。

使用令牌
curl -s -X POST https://exe.dev/exec -H "Authorization: Bearer $TOKEN" -d "ls"
curl -s -X POST https://exe.dev/exec -H "Authorization: Bearer $TOKEN" -d "new --name myvm --image ubuntu:24.04"
curl -s -X POST https://exe.dev/exec -H "Authorization: Bearer $TOKEN" -d "rm myvm"

响应始终为 JSON。

VM 默认设置

  • **镜像:**默认使用 boldsoftware/exeuntu — ssh exe.dev new(不带 --image)会创建 exeuntu VM。如需纯 Ubuntu,请使用 --image=ubuntu:24.04。exeuntu 是带有 Bold 覆盖层的 Ubuntu 24.04(Shelley/Pi Agent 技术栈位于 ~/.config/shelley/ 和 ~/.pi/,~/.zed_server/ 已预先暂存,apt 列表包含各种软件包,其中包括 Python 构建依赖项;在纯 Ubuntu 上,这些依赖项曾导致 uv tool install snowflake-cli 失败)。
  • **默认用户:**视镜像而定。
    • exeuntu:exedev(uid 1000,属于 sudo 和 docker 组,sudo 无需密码)。$HOME=/home/exedev。采用标准的非 root 开发模式。
    • ubuntu:24.04:root,未安装 sudo。要创建非 root 用户:ssh <vm>.exe.xyz "apt-get update -qq && apt-get install -y -qq sudo && useradd -m -s /bin/bash myuser && echo 'myuser ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/myuser"。
  • exeuntu 上预先存在的 ~/.claude/CLAUDE.md 和 ~/.codex/AGENTS.md 是指向 ~/.config/shelley/AGENTS.md 的绝对符号链接。dotfiles 的 install.sh 会检测到它们,并在暂存 agents 软件包前备份(文件名为 *.pre-dotfiles.<timestamp>)。Bold 的底层文件 ~/.config/shelley/AGENTS.md 会保留。

VM 命名规则

  • 名称不能以 -<digits> 结尾(例如,test-123 会被拒绝,test-abc 可用)
  • 名称的其他位置可以使用连字符
  • 名称会成为子域名:<name>.exe.xyz

SSH 配置

必须固定 exe.dev 密钥(以避免 1Password 的 Agent 提供其他密钥),并为 lobby 和直接 VM 主机启用连接复用(以避免上文所述的速率限制封锁):

Host exe.dev *.exe.xyz
  IdentitiesOnly yes
  IdentityFile ~/.ssh/exe_dev.pub
  ControlMaster auto
  ControlPath ~/.ssh/sockets/%r@%h-%p
  ControlPersist 600

私钥存储在 1Password 的 Employee 保管库中(“SSH Key - exe.dev”)。磁盘上只有公钥,路径为 ~/.ssh/exe_dev.pub。

install.sh(macOS 分支)会添加以下相关配置段:

Host *.exe.xyz
  User exedev
  LocalForward 8765 localhost:8765

Match host *.ts.net exec "$HOME/.local/bin/ssh-tailnet-tagged %h tag:dev"
  User exedev
  IdentitiesOnly yes
  IdentityFile ~/.ssh/exe_dev.pub
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  LogLevel ERROR

Host *.ts.net
  ForwardAgent yes

*.exe.xyz 配置段始终生效 — 这是 lobby 路径。Match host *.ts.net exec 配置段是动态部分:它会运行 ssh-tailnet-tagged(install.sh 写入 ~/.local/bin 的小型辅助工具),查询 tailscale status --json,并且仅当规范化后的主机名对应的节点带有 tag:dev 时才以 0 退出。因此,新建并完成引导的 exe.dev VM 一加入 tailnet,ssh <new-vm> 就能立即使用 — 无需为每台 VM 添加 ssh_config 条目,也无需在其他每台机器上重新运行 install.sh。Mac 和其他 tailnet 节点(没有 tag:dev)会落到普通的 Host *.ts.net 配置段(仅设置 ForwardAgent yes)— 这就是为什么在所有 *.ts.net 主机上不加区分地设置 User exedev 是错误的(它会尝试以 exedev 身份登录 Mac)。

对匹配的主机会禁用主机密钥检查,因为 WireGuard 已在网络层验证节点身份 — 在 tailnet 上,普通 SSH 主机密钥没有额外作用,而且每次重建 VM 都会轮换。

LocalForward 8765 仅适用于 *.exe.xyz 形式 — 刻意不包含 Tailscale 名称,以免日常 ssh <vm> 连接争抢端口 8765。Zed 的远程服务 SSH 会保持持久连接;如果 Tailscale 模式也启用了 LocalForward,那么之后每次终端执行 ssh <vm> 都会记录 bind: Address already in use,且隧道会失效。

对于 MCP OAuth 流程,请使用 ssh <vm>.exe.xyz — 这样才能建立隧道。日常工作使用 ssh <vm>(Tailscale),不会受到影响。

在脚本和 Agent 中工作

  • 用于大厅自动化时,HTTPS API 通常更顺手——你可以限定令牌的 cmds,让 Agent 仅拥有所需权限。
  • SSH 多路复用配置在 ~/.ssh/config 中(由 install.sh 添加),因此重复调用 ssh <vm>.exe.xyz 会复用同一个 TCP 连接。不要使用每次调用单独设置的 ControlPath 标志覆盖它——这会分散套接字池,削弱速率限制缓解效果。
  • 首次连接时以非交互方式接受新的主机密钥:-o StrictHostKeyChecking=accept-new。
  • **连接超时:**对 VM SSH 使用 -o ConnectTimeout=30——新 VM 需要几秒钟才能变得可连接。
  • **Tailscale 启动后,后续工作都切换到 Tailscale SSH。**参见下文的“SSH 端点”。

SSH 端点——何时使用哪个

安装 dotfiles 后,运行中的 VM 可通过两个 SSH 端点访问:

端点使用时机
ssh <vm>.exe.xyz (exe.dev)**仅用于引导。**Tailscale 启动前必须使用(curl 安装和 install.sh 阶段)。如果 VM 上的 Tailscale 出现故障,或使用未加入 tailnet 的 Mac,也可将其用作备用方案。
ssh <vm> / ssh <vm>.dojo-sun.ts.net**引导后的所有工作默认使用此端点。**转发 1Password SSH Agent(克隆私有仓库、推送、签名——VM 上无需令牌),绕过 exe.dev 的逐 IP 速率限制,重建 VM 时不会发生 SSH 主机密钥变更(Tailscale 通过 WireGuard 而非 OpenSSH 主机密钥处理身份验证),并且与 Apple Containers 和 Sprites 使用相同模式,便于跨平台养成习惯。

**经验法则:**如果 VM 上的 Tailscale 已启动,优先使用 ssh <vm>。仅在引导期间和紧急情况下使用 ssh <vm>.exe.xyz。

ssh <vm> 如何知道使用 User exedev:install.sh 会在 ~/.ssh/config 中写入一个 Match host *.ts.net exec "..." 块,在连接时运行 ~/.local/bin/ssh-tailnet-tagged。此辅助程序会查询 tailscale status --json,并且仅当对端带有 tag:dev 时才以状态码 0 退出。因此,新 exe.dev VM 加入 tailnet 后即可立即使用——无需逐台配置 VM,也无需在添加 VM 时于其他每台机器上重新运行 install.sh。Mac 和其他 tailnet 对端(没有 tag:dev)则会回退到普通的 Host *.ts.net 块(仅设置 ForwardAgent yes)。

VM 到 VM 的访问

exe.dev VM 提供 /dev/net/tun 和 CAP_NET_ADMIN,因此 install.sh 会以内核模式运行 tailscaled——使用真实的 tailscale0 接口、针对 100.0.0.0/8 的内核路由,以及接入系统解析器的 MagicDNS。VM 之间可以像从 Mac 访问时一样,直接使用 ssh <vm>。

# from inside any exe.dev VM (use the username that matches the destination's image)
ssh exedev@gitlake 'cd ~/dotfiles && git pull && ./install.sh'   # exeuntu
ssh root@gitlake 'cd ~/dotfiles && git pull && ./install.sh'     # ubuntu:24.04

这要求 Tailscale ACL 允许 tag:dev → tag:dev,同时适用于网络授权和 SSH 规则(管理控制台)。SSH 规则的 users 列表必须包含你登录时使用的目标用户——通常 exeuntu 使用 exedev,ubuntu:24.04 使用 root。

用户空间模式回退方案。 如果无法使用 /dev/net/tun(某些 Apple Containers 配置、Sprite),install.sh 会回退到 tailscaled --tun=userspace-networking。此模式下无法使用普通的 ssh <vm>(没有指向 tailnet IP 的内核路由);应改用 tailscale ssh <vm>,它会通过 tailscaled 的用户空间 TCP 协议栈进行代理。

重命名后的 Tailnet 身份——重启无法修复

VM 的 tailnet 名称是运行 tailscale up 时记录的 --hostname,之后不会从操作系统重新读取。因此,如果操作系统主机名发生变化(例如,重建时以 <name>-next 加入,之后又重命名为 <name>),节点仍会使用旧名称,其他节点无法通过其规范名称访问它——看起来就像“已加入 tailnet,却无法通信”。以下两种操作无法修复此问题(2026-08-02 在 canary 上测得):hostnamectl set-hostname 和 systemctl restart tailscaled——重启会重新通告已保存的同一名称。修复方法是重新注册:运行 sudo tailscale logout,然后重新加入(join-tailnet.sh <vm>,此脚本会幂等地使用请求的主机名,并先清除任何占用该名称的过期节点)。重新注册会创建一个新节点,因此 tailnet IP 也会变化——所有固定使用旧 IP 的地方都必须更新。切勿建议通过“重启 tailscaled”来修复 tailnet 连通性;应重新注册。

设置开发 VM

默认设置脚本(exe-setup.sh)通过 ssh exe.dev defaults write 注册,因此每台新 VM 都会自动安装 Tailscale 和 dotfiles。只需两条命令即可获得可用的代码仓库:

1. 创建 VM 并克隆代码仓库(约 4 秒)
ssh exe.dev new --name=<vm> --tag=iv \
  --integration=github-<org>-<repo>
ssh -o ConnectTimeout=30 -o StrictHostKeyChecking=accept-new <vm>.exe.xyz \
  "git clone https://github-<org>-<repo>.int.exe.xyz/<org>/<repo>.git ~/<repo>"
  • --tag=iv 授予 VM 访问 IV 范围集成(工作用 GitHub MCP、MotherDuck)的权限
  • --integration=github-<org>-<repo> 附加该代码仓库专用的克隆/推送集成
  • 对于个人 VM,还应在创建后附加 github-mcp-home:ssh exe.dev integrations attach github-mcp-home vm:<vm>

GitHub 集成的命名格式为 github-<org>-<repo>(例如 github-kylelundstedt-gitlake)。注册新代码仓库的方法:

ssh exe.dev integrations add github --name github-<org>-<repo> --repository <org>/<repo>
集成范围

集成的范围经过限制,以尽量减少凭据在不同 VM 之间的暴露:

集成范围授予权限
tailscale-apiauto:all(个人)Tailscale API——启动时设置脚本所需
github-mcp-worktag:iv工作用 GitHub API(议题、PR、代码搜索)
motherduck-mcptag:ivMotherDuck SQL 查询
github-mcp-homevm:(每台 VM)个人 GitHub API——仅限你的 VM
github-<org>-<repo>vm:(每台 VM)单个代码仓库的 Git 克隆/推送
reflectionauto:allVM 元数据(无害)

团队成员通过 SSO 加入后,将看不到个人集成。团队集成(--team 标志)仅支持附加 tag:——应使用客户端专属标签(例如 iv、usaa)来限定访问范围。

设置脚本

默认设置脚本(dotfiles 仓库中的 exe-setup.sh)会在首次启动时运行,并执行以下操作:

  • 删除主机名相同的过期 Tailscale 节点(防止出现 -2 后缀)
  • 通过 tailscale-api HTTP 代理集成生成一个一次性临时身份验证密钥
  • 启动 tailscaled 并完成身份验证(ssh exe.dev new 返回后约 6 秒,节点会显示在 tailscale status 中;约 10–12 秒后即可通过短名称运行 ssh <vm>)
  • Tailscale 启动后,在前台运行 install.sh(约 60 秒)

exe-setup.sh 的用途就是让 Tailscale 在完整安装之前启动。同一套身份验证密钥/代理逻辑也位于 install.sh 的 setup_tailscale 中(在单独调用 install.sh 时作为回退方案),但通过 exe-setup.sh 运行可让 VM 提前约 3 分钟加入 tailnet。

设置默认脚本(一次性操作,已完成;如果更改文件名或位置,请重新运行):

ssh exe.dev "defaults write dev.exe new.setup-script 'curl -fsSL https://raw.githubusercontent.com/kylelundstedt/dotfiles/master/exe-setup.sh | bash'"

与 exe.dev 钩子系统之间的两项约定都必须正确:

  1. 注册所指向的 URL 必须存在。 raw.githubusercontent.com/.../master/exe-setup.sh 必须返回 200。
  2. 注册必须指向 exe-setup.sh,而不是 install.sh。 两者都能运行,但 install.sh 只有在 apt 和 CLI 工具安装后才会启动 Tailscale(Tailscale 启动前会延迟约 30 秒;实测节点可见需要 34–36 秒)。exe-setup.sh 会优先启动 Tailscale(节点约 6 秒后可见)。注册指向哪个文件出现偏差时不会有任何提示——VM 仍会完成引导,只是速度较慢。

同时验证这两项:

ssh exe.dev "defaults read dev.exe new.setup-script"   # should contain exe-setup.sh, not install.sh
./test-install.sh hook                                  # verifies URL returns 200

如果注册指向的文件发生偏差,请使用上面的 defaults write 命令重新设置。test-install.sh hook 会检查 URL,但不会检查注册了哪个文件。偏差对用户的影响是:“VM 出现在 tailnet 上需要 30 秒,而不是 6 秒。”

2. 提交签名

要进行提交签名,请使用 Tailscale SSH(ssh <vm>),它会转发 1Password SSH Agent。.zshrc 会在登录时检测转发的 Agent,并自动启用提交签名。

3. MCP 服务

五个 MCP 服务中,有三个通过 exe.dev HTTP 代理集成自动连接——新 VM 无需设置:

服务代理集成身份验证
motherduckmotherduck-mcp.int.exe.xyz静态 Bearer 令牌(自动)
github-homegithub-mcp-home.int.exe.xyz静态 Bearer 令牌(自动)
github-workgithub-mcp-work.int.exe.xyz静态 Bearer 令牌(自动)
tigris—OAuth(一次性浏览器授权流程)
readwise—OAuth(一次性浏览器授权流程)

install.sh 会自动注册全部五个服务。基于代理的三个服务在安装后会立即显示“已连接”;Tigris 和 Readwise 则会显示“需要身份验证”,直到完成 OAuth 流程。

Tigris/Readwise 的 OAuth 流程(每台 VM 执行一次):

ssh <vm>.exe.xyz                # use the .exe.xyz form — carries LocalForward 8765
claude                          # inside the VM, start an interactive session
# /mcp → pick a server marked "Needs authentication" → Authenticate
# claude prints an http://localhost:8765/... URL — open it in the Mac browser

Tailscale 形式(ssh <vm>)不会转发 LocalForward,这是有意为之——否则 Zed 持久运行的远程服务 SSH 每次常规连接时都会争用端口 8765。由于端口 8765 只能绑定一次,请在不同 VM 上依次完成 OAuth 流程。令牌会缓存在每台 VM 的 ~/.claude/ 下,因此每个服务在每台 VM 上只需执行一次。

4. 从 Zed 连接

使用 Tailscale 主机名(由于 ~/.ssh/config 中的规范化配置块,短名称也可用)。用户名和主目录路径取决于镜像:

zed ssh://exedev@<vm>/home/exedev/<repo>   # exeuntu (default)
zed ssh://root@<vm>/root/<repo>            # ubuntu:24.04

对象存储集成(Tigris / S3)

exe.dev“对象存储”集成属于 s3 类型,可通过 https://<integration>.int.exe.xyz 提供兼容 S3 的路径式代理,由 Tigris 存储桶(t3.storage.dev)提供支持。凭据由边缘注入——虚拟机发送的是占位符凭据,代理会使用真实的 Tigris 密钥重新签名,因此虚拟机上不会留存任何密钥材料。

端点主机名是集成名称,而非存储桶名称。 代理位于 https://<integration>.int.exe.xyz,其中 <integration> 是集成名称——它不一定与存储桶名称相同。请务必查询名称,不要自行假定:ssh exe.dev integrations list 会显示 <name> s3 endpoint=… bucket=…。例如,集成 bucket-gitlake-examples 指向存储桶 gitlake-examples,因此主机名是 bucket-gitlake-examples.int.exe.xyz,但路径中使用的是 gitlake-examples。使用 ssh exe.dev integrations attach <name> vm:<vm> 将集成附加到每台虚拟机。

仅支持路径式寻址。 代理会从 URL 路径 中读取存储桶(.../<bucket>/<key>)。虚拟主机式寻址(将存储桶作为子域名)会失败:<bucket>.<name>.int.exe.xyz 会导致 *.int.exe.xyz TLS 证书失效,而将存储桶放在主机名中并使用路径 / 则会返回 403 "account-level operations are not allowed"。所有客户端都必须使用路径式寻址。

tigris CLI

只有通过 TIGRIS_FORCE_PATH_STYLE 强制使用路径式寻址时才能正常工作。该环境变量是在 3.1.0 之后添加的(已确认存在于 3.6.1 中,在 3.1.0 中不存在)——旧版 tigrisdata/cli 发布版本和过时镜像中附带的 CLI 没有此变量,因此请确保 tigris --version 显示的是当前版本(install.sh 现在会从 tigrisdata/storage 下载)。

export TIGRIS_STORAGE_ENDPOINT=https://<integration>.int.exe.xyz
export TIGRIS_FORCE_PATH_STYLE=1               # REQUIRED — the proxy is path-style
export TIGRIS_STORAGE_ACCESS_KEY_ID=x          # placeholders; edge injects the real cred
export TIGRIS_STORAGE_SECRET_ACCESS_KEY=x
tigris ls <bucket>
tigris cp ./file t3://<bucket>/key             # up/download/rm all work

tigris CLI 自带的 S3 客户端不会发送 CRC64NVME 流式尾部校验,因此无需额外标志即可上传。

aws CLI / SDK(boto3、aws-sdk-js、rclone)

使用相同的端点、路径式寻址和占位符凭据:

AWS_ACCESS_KEY_ID=x AWS_SECRET_ACCESS_KEY=x \
aws s3 ls s3://<bucket> --endpoint-url https://<integration>.int.exe.xyz

近期版本的 aws-cli v2 会发送默认的 CRC64NVME 校验和尾部,代理会在上传时以 SignatureDoesNotMatch 拒绝该请求。请禁用此功能(也可在 ~/.aws/config 中设置):

export AWS_REQUEST_CHECKSUM_CALCULATION=when_required
export AWS_RESPONSE_CHECKSUM_VALIDATION=when_required

boto3:Config(s3={"addressing_style": "path"})。rclone:force_path_style = true。

预签名

代理提供了一个预签名辅助端点,可返回已签名的 t3.storage.dev URL:

curl -sX POST https://<integration>.int.exe.xyz/_/presign -d '{"key":"path/to/object"}'
说明
  • 按设计禁止账户级操作(ListBuckets、路径 /)——该集成的凭据被限定为只能访问一个存储桶。
  • 也可以使用普通的未签名 curl "https://<integration>.int.exe.xyz/<bucket>/?list-type=2"(边缘会注入凭据)——可方便地用于探测连通性。

评论

支持 Markdown