---
title: SSH
description: Go SDK - SSH API reference
---

Reach a running sandbox over SSH: open a native in-process SSH client, run exec requests, attach an interactive shell, transfer files over SFTP, or stand up a reusable SSH server endpoint. See [SSH](/sandboxes/ssh) for usage flows.


## Sandbox

#### <span className="msb-recv">sb.</span><span className="msb-hn">SSH()</span>

```go
func (s *Sandbox) SSH() *SandboxSSHOps
```

<Accordion title="Example">

```go
ssh := sb.SSH()
client, err := ssh.OpenClient(ctx)
```

</Accordion>

Return the SSH operations namespace for this sandbox. The namespace groups the client and server helpers; it holds no resources of its own.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#sandboxsshops">*SandboxSSHOps</a></div>
    <div className="msb-param-desc">SSH client and server helpers for this sandbox.</div>
  </div>
</div>

## SandboxSSHOps

<p className="msb-backref">Returned by <a href="#sb-ssh">SSH()</a></p>

SSH operations namespace for a sandbox. Obtained via [`sb.SSH()`](#sb-ssh). Holds no resources; it groups the client and server entry points.


#### <span className="msb-recv">ssh.</span><span className="msb-hn">OpenClient()</span>

```go
func (ssh *SandboxSSHOps) OpenClient(ctx context.Context, opts ...SSHClientOption) (*SSHClient, error)
```

<Accordion title="Example">

```go
client, err := sb.SSH().OpenClient(ctx,
    m.WithSSHUser("app"),
    m.WithSSHTerm("xterm-256color"),
)
if err != nil {
    return err
}
defer client.Close(ctx)
```

</Accordion>

Open a native in-process SSH client to this sandbox. Generates an ephemeral Ed25519 client and host key pair, stands up an internal server bound to a duplex stream, and authenticates over public key. With no options it uses login user `root`, terminal from `$TERM` (falling back to `xterm`), and SFTP enabled.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels the connection attempt.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>opts</code><a className="msb-type" href="#sshclientoption">...SSHClientOption</a></div>
    <div className="msb-param-desc">Login user, terminal name, and SFTP toggle.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#sshclient">*SSHClient</a></div>
    <div className="msb-param-desc">Native SSH client session.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">ssh.</span><span className="msb-hn">PrepareServer()</span>

<Tooltip tip="On microsandbox cloud, the reusable server works when you supply explicit host-key and authorized-key material; the convenience defaults are local-only."><span className="msb-badge-limited">Limited on cloud <Icon icon="circle-info" size={11} /></span></Tooltip>

```go
func (ssh *SandboxSSHOps) PrepareServer(ctx context.Context, opts ...SSHServerOption) (*SSHServer, error)
```

<Accordion title="Example">

```go
srv, err := sb.SSH().PrepareServer(ctx,
    m.WithSSHAuthorizedKeysPath("/etc/msb/authorized_keys"),
)
if err != nil {
    return err
}
defer srv.Close(ctx)
```

</Accordion>

Prepare a reusable SSH server endpoint for this sandbox. Loads or creates the host key and resolves authorized keys from the default authorized-keys file unless overridden. The returned [`SSHServer`](#sshserver) can serve connections one at a time over the process's standard streams.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels server preparation.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>opts</code><a className="msb-type" href="#sshserveroption">...SSHServerOption</a></div>
    <div className="msb-param-desc">Host key, authorized keys, guest user, and SFTP toggle.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#sshserver">*SSHServer</a></div>
    <div className="msb-param-desc">Prepared server endpoint.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

## SSHClient

<p className="msb-backref">Returned by <a href="#ssh-openclient">OpenClient()</a></p>

A native in-process SSH client session. Obtained via [`OpenClient()`](#ssh-openclient).


#### <span className="msb-recv">c.</span><span className="msb-hn">Exec()</span>

```go
func (c *SSHClient) Exec(ctx context.Context, command string, opts ...SSHExecOption) (*SSHOutput, error)
```

<Accordion title="Example">

```go
out, err := client.Exec(ctx, "python -V")
if err != nil {
    return err
}
if !out.Success() {
    return fmt.Errorf("exit %d: %s", out.Status, out.Stderr)
}
fmt.Printf("%s", out.Stdout)
```

</Accordion>

Run an SSH exec request and collect stdout, stderr, and the exit status. The command is run through the sandbox's configured shell. No PTY is requested unless [`WithSSHTTY`](#sshexecoption) is passed.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels the exec request.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>command</code><span className="msb-type">string</span></div>
    <div className="msb-param-desc">Command string sent through SSH.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>opts</code><a className="msb-type" href="#sshexecoption">...SSHExecOption</a></div>
    <div className="msb-param-desc">PTY toggle for the exec channel.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#sshoutput">*SSHOutput</a></div>
    <div className="msb-param-desc">Captured stdout, stderr, and exit status.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">c.</span><span className="msb-hn">Attach()</span>

```go
func (c *SSHClient) Attach(ctx context.Context, opts ...SSHAttachOption) (int, error)
```

<Accordion title="Example">

```go
code, err := client.Attach(ctx,
    m.WithSSHAttachTerm("xterm-256color"),
    m.WithSSHDetachKeys("ctrl-p,ctrl-q"),
)
if err != nil {
    return err
}
fmt.Printf("shell exited with %d\n", code)
```

</Accordion>

Bridge the local terminal to an interactive SSH shell. Requests a PTY sized to the current terminal, puts the terminal into raw mode, forwards keystrokes, relays window-resize events, and returns when the shell exits or the detach key sequence is typed.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels the attach session.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>opts</code><a className="msb-type" href="#sshattachoption">...SSHAttachOption</a></div>
    <div className="msb-param-desc">Terminal name and detach key sequence.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">int</span></div>
    <div className="msb-param-desc">Shell exit code (128 if terminated by signal).</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">c.</span><span className="msb-hn">SFTP()</span>

```go
func (c *SSHClient) SFTP(ctx context.Context) (*SFTPClient, error)
```

<Accordion title="Example">

```go
sftp, err := client.SFTP(ctx)
if err != nil {
    return err
}
defer sftp.Close(ctx)

if err := sftp.Write(ctx, "/tmp/hello.txt", []byte("hi")); err != nil {
    return err
}
```

</Accordion>

Open an SFTP session over this SSH connection. Returns a high-level SFTP client for reading, writing, and managing files inside the guest. Requires SFTP enabled on the client (the default).

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels opening the SFTP session.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#sftpclient">*SFTPClient</a></div>
    <div className="msb-param-desc">SFTP client session.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">c.</span><span className="msb-hn">Close()</span>

```go
func (c *SSHClient) Close(ctx context.Context) error
```

<Accordion title="Example">

```go
defer client.Close(ctx)
```

</Accordion>

Close this SSH client session. The handle is consumed; do not use it after closing.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels the close.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

## SSHServer

<p className="msb-backref">Returned by <a href="#ssh-prepareserver">PrepareServer()</a></p>

A prepared SSH server endpoint for a sandbox. Obtained via [`PrepareServer()`](#ssh-prepareserver).


#### <span className="msb-recv">srv.</span><span className="msb-hn">ServeConnection()</span>

```go
func (srv *SSHServer) ServeConnection(ctx context.Context) error
```

<Accordion title="Example">

```go
srv, err := sb.SSH().PrepareServer(ctx)
if err != nil {
    return err
}
defer srv.Close(ctx)

if err := srv.ServeConnection(ctx); err != nil {
    return err
}
```

</Accordion>

Serve one SSH transport over this process's stdin and stdout. Returns when the connection ends. Call again on the same [`SSHServer`](#sshserver) to serve another connection.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels serving the connection.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">srv.</span><span className="msb-hn">Close()</span>

```go
func (srv *SSHServer) Close(ctx context.Context) error
```

<Accordion title="Example">

```go
defer srv.Close(ctx)
```

</Accordion>

Release this prepared server endpoint. The handle is consumed; do not use it after closing.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels the close.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

## SSHOutput

<p className="msb-backref">Returned by <a href="#c-exec">Exec()</a></p>

The output from an SSH exec request.

#### <span className="msb-recv">o.</span><span className="msb-hn">Status</span>

`int`

Exit status code

#### <span className="msb-recv">o.</span><span className="msb-hn">Stdout</span>

`[]byte`

Captured stdout bytes

#### <span className="msb-recv">o.</span><span className="msb-hn">Stderr</span>

`[]byte`

Captured stderr bytes

#### <span className="msb-recv">o.</span><span className="msb-hn">Success()</span>

```go
func (o SSHOutput) Success() bool
```

<Accordion title="Example">

```go
out, err := client.Exec(ctx, "test -f /etc/passwd")
if err != nil {
    return err
}
fmt.Println("present:", out.Success())
```

</Accordion>

Report whether the command exited with status `0`.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">bool</span></div>
    <div className="msb-param-desc"><code>true</code> when <code>Status</code> is <code>0</code>.</div>
  </div>
</div>

## SFTPClient


<p className="msb-backref">Returned by <a href="#c-sftp">SFTP()</a></p>

A high-level SFTP client session over an SSH connection. Obtained via [`SFTP()`](#c-sftp).


#### <span className="msb-recv">sftp.</span><span className="msb-hn">Read()</span>

```go
Read(ctx, path)
```

Read a file into memory

<p className="msb-label">Returns</p>

`([]byte, error)`

#### <span className="msb-recv">sftp.</span><span className="msb-hn">Write()</span>

```go
Write(ctx, path, data)
```

Write a file, creating or truncating it

<p className="msb-label">Returns</p>

`error`

#### <span className="msb-recv">sftp.</span><span className="msb-hn">Mkdir()</span>

```go
Mkdir(ctx, path)
```

Create a directory

<p className="msb-label">Returns</p>

`error`

#### <span className="msb-recv">sftp.</span><span className="msb-hn">RemoveFile()</span>

```go
RemoveFile(ctx, path)
```

Remove a file

<p className="msb-label">Returns</p>

`error`

#### <span className="msb-recv">sftp.</span><span className="msb-hn">RemoveDir()</span>

```go
RemoveDir(ctx, path)
```

Remove an empty directory

<p className="msb-label">Returns</p>

`error`

#### <span className="msb-recv">sftp.</span><span className="msb-hn">Rename()</span>

```go
Rename(ctx, oldPath, newPath)
```

Rename a file or directory

<p className="msb-label">Returns</p>

`error`

#### <span className="msb-recv">sftp.</span><span className="msb-hn">RealPath()</span>

```go
RealPath(ctx, path)
```

Resolve a path to its canonical absolute form

<p className="msb-label">Returns</p>

`(string, error)`

#### <span className="msb-recv">sftp.</span><span className="msb-hn">ReadLink()</span>

```go
ReadLink(ctx, path)
```

Read a symlink target

<p className="msb-label">Returns</p>

`(string, error)`

#### <span className="msb-recv">sftp.</span><span className="msb-hn">Symlink()</span>

```go
Symlink(ctx, target, linkPath)
```

Create a symlink

<p className="msb-label">Returns</p>

`error`

#### <span className="msb-recv">sftp.</span><span className="msb-hn">Close()</span>

```go
Close(ctx)
```

Close the session (consumes the handle)

<p className="msb-label">Returns</p>

`error`

## Types

### SSHClientOption

<p className="msb-backref">Used by <a href="#ssh-openclient">OpenClient()</a></p>

Functional option for [`OpenClient()`](#ssh-openclient). Defaults: user `root`, terminal from `$TERM` (falling back to `xterm`), SFTP enabled.

| Option | Description |
|--------|-------------|
| WithSSHUser(user) | SSH login user. Default `root` |
| WithSSHTerm(term) | Terminal name for interactive sessions |
| WithSSHClientSFTP(enabled) | Enable or disable SFTP on the internal server. Default `true` |

### SSHExecOption

<p className="msb-backref">Used by <a href="#c-exec">Exec()</a></p>

Functional option for [`Exec()`](#c-exec).

| Option | Description |
|--------|-------------|
| WithSSHTTY(enabled) | Request a PTY for the exec channel |

### SSHAttachOption

<p className="msb-backref">Used by <a href="#c-attach">Attach()</a></p>

Functional option for [`Attach()`](#c-attach). The default terminal comes from `$TERM` (falling back to `xterm`); detach keys default to the standard sequence.

| Option | Description |
|--------|-------------|
| WithSSHAttachTerm(term) | Terminal name for the interactive shell |
| WithSSHDetachKeys(keys) | Detach key sequence |

### SSHServerOption

<p className="msb-backref">Used by <a href="#ssh-prepareserver">PrepareServer()</a></p>

Functional option for [`PrepareServer()`](#ssh-prepareserver). SFTP is enabled by default; when no authorized-keys path is provided, the default authorized-keys file is loaded.

| Option | Description |
|--------|-------------|
| WithSSHHostKeyPath(path) | Override the host private key path |
| WithSSHAuthorizedKeysPath(path) | Override the authorized-keys path |
| WithSSHServerUser(user) | Override the guest user used for SSH exec requests |
| WithSSHServerSFTP(enabled) | Enable or disable SFTP on the server endpoint. Default `true` |
