# SSH & file transfer

> Open shells, run commands, copy files and forward ports — through any firewall, or directly over IPv6.

Every sandbox runs a standard OpenSSH server. There are three ways to reach it:

| Route | Command | Works when |
| - | - | - |
| **Tunnel** (default) | `sbx ssh <id>` | Always — SSH is carried over an authenticated WebSocket through the API, so only outbound HTTPS is needed |
| **Direct IPv6** | `ssh user@<ipv6>` | Your network has IPv6. Every sandbox has a public IPv6 address |
| **IPv4 port** | `ssh -p <port> user@<host>` | Always, with any SSH client — `sshEndpoint` (`sbx info` shows it) is a public IPv4 `host:port` forwarded to the sandbox's port 22 while it runs |

## sbx ssh

```bash
sbx ssh sb_k3v9x2mq                              # interactive shell
sbx ssh sb_k3v9x2mq "cd my-app && npm test"      # one command, exit code passed through
sbx ssh sb_k3v9x2mq -- bash -lc 'echo $HOME'     # argv form, quoting preserved
sbx ssh sb_k3v9x2mq -- bash -s < ./setup.sh      # pipe a local script
sbx ssh current                                   # the sandbox you created last in this shell
```

The CLI keeps a dedicated key at `~/.ssh/sandboxer_ed25519`, authorizes it on the sandbox the first time, and pins the sandbox's host key. You never have to manage `authorized_keys` yourself.

If the sandbox is stopped, `sbx ssh` tells you to resume it. In the first second of a resume you may get the retryable `sandbox_restoring` error — the CLI retries for you.

## Use your own SSH client

Authorize a public key, then connect to the IPv6 address or the IPv4 `sshEndpoint`:

```bash title="CLI"
sbx info sb_k3v9x2mq          # shows ip and SSH endpoint
ssh -i ~/.ssh/sandboxer_ed25519 user@2a01:4f9:3a:1e2f::6
ssh -i ~/.ssh/sandboxer_ed25519 -p 22006 user@red-fox-jump.box.sandboxer.com   # sshEndpoint red-fox-jump.box.sandboxer.com:22006
```

```bash title="curl"
curl -sS -X POST https://sandboxer.com/api/v1/sandboxes/sb_k3v9x2mq/sshkey \
  -H "Authorization: Bearer $SANDBOXER_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"key\":\"$(cat ~/.ssh/id_ed25519.pub)\"}"
```

The response includes `machineIp`, `sshUser` (`user`) and `hostKey`. Add the host key to `known_hosts` to pin it:

```bash
echo "2a01:4f9:3a:1e2f::6 ssh-ed25519 AAAAC3Nza…" >> ~/.ssh/known_hosts
```

Private keys are rejected by the API — only send `.pub` contents.

### Through the tunnel with plain ssh

Any tool that speaks SSH (VS Code Remote-SSH, JetBrains Gateway, `rsync`, Ansible) can use the tunnel. Add the CLI's stanza to your SSH config once:

```bash
sbx ssh-config --install   # or `sbx ssh-config` to print it and add it yourself
```

It adds a `Host *.sbx` block whose `ProxyCommand` is `sbx proxy %h`, with the CLI's key and the sandbox's pinned host key. Then `ssh sb_k3v9x2mq.sbx`, `rsync -av ./ sb_k3v9x2mq.sbx:app/` and "Remote-SSH: Connect to Host… sb_k3v9x2mq.sbx" all work.

## Copy files

```bash
sbx scp ./data.csv sb_k3v9x2mq:/home/user/          # upload
sbx scp sb_k3v9x2mq:/home/user/out.zip ./           # download
sbx scp -r ./my-project sb_k3v9x2mq:/home/user/     # directories
```

Recursive copies to a new directory are sent as one tar stream when both ends have `tar`, which is much faster for many small files.

Without SSH, the files API reads and writes single files (paths must resolve under `/home/user` or `/tmp`):

```bash
curl -sS "https://sandboxer.com/api/v1/sandboxes/sb_k3v9x2mq/files?path=my-app/package.json" \
  -H "Authorization: Bearer $SANDBOXER_API_KEY"

curl -sS -X PUT https://sandboxer.com/api/v1/sandboxes/sb_k3v9x2mq/files \
  -H "Authorization: Bearer $SANDBOXER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"path":"notes.txt","content":"hello"}'
```

The dashboard has a file browser with upload and download on every sandbox page.

## Forward ports

Reach a port inside the sandbox from your computer, privately:

```bash
sbx forward sb_k3v9x2mq --remote 5432                  # psql -h 127.0.0.1 -p 5432
sbx forward sb_k3v9x2mq --remote 3000 --local 8080
```

Or the other way round — expose a port on **your** machine inside the sandbox, so an agent there can reach a local model, an MCP server or a webhook receiver on your laptop:

```bash
sbx forward sb_k3v9x2mq --reverse --local 11434                 # 127.0.0.1:11434 inside
sbx forward sb_k3v9x2mq --reverse --local 7777 --remote 9000
```

Forwards run in the foreground until Ctrl-C and reconnect automatically if the sandbox moves (for example after a resume). Nothing becomes public; for a public URL use [Hosting](/docs/hosting).

## Exec without SSH

For automation, the commands API is usually simpler than SSH: no keys, a JSON result, and history you can read later.

```bash
sbx exec sb_k3v9x2mq "npm test"
sbx exec sb_k3v9x2mq --cwd my-app --timeout 300 -- npm run build
```

See [Long-running tasks](/docs/long-running) for detached commands and streaming.

## Web terminal

The dashboard's **Terminal** tab opens a full PTY in your browser over the same exec WebSocket the CLI uses — handy from a phone or a locked-down machine.
