docs/sandboxes/ssh.mdx
SSH gives a sandbox a familiar interface without putting an SSH daemon inside the guest. microsandbox speaks SSH on the host side, then forwards shells, remote commands, and SFTP file operations into the sandbox.
Use it when you want existing SSH tools to work with a sandbox, or when you want SDK code to use SSH semantics while still going through microsandbox.
There are two ways to connect:
ssh binary, TCP listener, or authorized key is required, which makes it the quickest path for a shell from msb or SSH semantics from the SDK.ssh, sftp, and ProxyCommand can connect.Native sessions keep the SSH protocol boundary but do not expose a listener.
msb ssh devbox
msb ssh connect devbox
With no remote command, the CLI opens an interactive shell. With --, the remaining tokens become the SSH command string and run through the sandbox shell.
msb ssh devbox -- uname -a
msb ssh devbox -- sh -lc "cd /app && npm test"
If a sandbox name collides with an SSH subcommand such as serve or authorize, use --name:
msb ssh --name serve
msb ssh --name authorize -- uptime
let output = ssh.exec("uname -a").await?; println!("{}", String::from_utf8_lossy(&output.stdout));
ssh.close().await?;
```typescript TypeScript
const sb = await Sandbox.start("devbox");
const ssh = await sb.ssh().connect();
const output = await ssh.exec("uname -a");
console.log(output.stdout.toString());
await ssh.close();
sb = await Sandbox.start("devbox")
ssh = await sb.ssh().connect()
output = await ssh.exec("uname -a")
print(output.stdout_text)
await ssh.close()
sb, err := m.StartSandbox(ctx, "devbox")
if err != nil {
return err
}
defer sb.Close()
ssh, err := sb.SSH().Connect(ctx)
if err != nil {
return err
}
defer ssh.Close(ctx)
output, err := ssh.Exec(ctx, "uname -a")
if err != nil {
return err
}
fmt.Print(string(output.Stdout))
SDK clients can attach the local terminal to an SSH shell. This requires a real terminal.
<CodeGroup> ```rust Rust let code = sb .ssh() .connect_with(|ssh| ssh.term("xterm-256color")) .await? .attach() .await?; ```const ssh = await sb.ssh().connect({ term: "xterm-256color" });
const code = await ssh.attach({ detachKeys: "ctrl-]" });
ssh = await sb.ssh().connect(term="xterm-256color")
code = await ssh.attach(detach_keys="ctrl-]")
ssh, err := sb.SSH().Connect(ctx, m.WithSSHTerm("xterm-256color"))
if err != nil {
return err
}
code, err := ssh.Attach(ctx, m.WithSSHDetachKeys("ctrl-]"))
The native SSH client can open SFTP over the same SSH connection.
<CodeGroup> ```rust Rust let sftp = ssh.sftp().await?; sftp.write("/tmp/hello.txt", b"hello").await?; let data = sftp.read("/tmp/hello.txt").await?; sftp.close().await?; ```const sftp = await ssh.sftp();
await sftp.write("/tmp/hello.txt", Buffer.from("hello"));
const data = await sftp.read("/tmp/hello.txt");
await sftp.close();
sftp = await ssh.sftp()
await sftp.write("/tmp/hello.txt", b"hello")
data = await sftp.read("/tmp/hello.txt")
await sftp.close()
sftp, err := ssh.SFTP(ctx)
if err != nil {
return err
}
defer sftp.Close(ctx)
if err := sftp.Write(ctx, "/tmp/hello.txt", []byte("hello")); err != nil {
return err
}
data, err := sftp.Read(ctx, "/tmp/hello.txt")
External client mode exposes a sandbox as an SSH server for tools that already speak SSH. This is the closest match for normal SSH usage: authorize a public key, serve the sandbox, then connect with ssh or sftp.
msb ssh authorize --file ~/.ssh/id_ed25519.pub
msb ssh authorize --key "ssh-ed25519 AAAA... user@host"
cat ~/.ssh/id_ed25519.pub | msb ssh authorize --stdin
Keys are appended to <MSB_HOME>/ssh/authorized_keys.
msb ssh serve devbox
The default listener is 127.0.0.1:2222.
ssh -p 2222 [email protected]
sftp -P 2222 [email protected]
Choose a different bind address or port when needed:
msb ssh serve devbox --host 127.0.0.1 --port 2223
msb ssh serve --stdio carries a single SSH connection over stdin/stdout instead of a TCP listener. Point OpenSSH at it with ProxyCommand so standard SSH tools can reach the sandbox by host alias.
Add an entry to your ~/.ssh/config:
Host devbox.msb
User root
ProxyCommand msb ssh serve devbox --stdio
The Host value is the alias you connect to, and devbox is the sandbox name passed to msb ssh serve.
Once it is in place, the alias works with any OpenSSH-based tool:
ssh devbox.msb
sftp devbox.msb
scp ./build.tar devbox.msb:/tmp/
rsync -av ./src/ devbox.msb:/app/
Editors that build on OpenSSH, such as VS Code Remote-SSH, connect to the devbox.msb host the same way.
For exact SDK signatures, see the SSH reference for Rust, TypeScript, Python, or Go.