# Sandbox ports and SSH
URL: https://docs.munito.ai/sandboxes/ports-and-ssh

## Ports [#ports]

A server in a sandbox gets a URL for each port, for HTTPS and WebSockets. The server must listen on `0.0.0.0` or `127.0.0.1`.

1. Start a server in the sandbox, for example on port 8080:

```bash
curl -sS --fail-with-body "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/exec" \
  -H "Authorization: Bearer $MUNITO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"command": "nohup python3 -m http.server 8080 >/dev/null 2>&1 &"}'
```

2. Get the `url` of the port and the `token` of the sandbox:

```bash
curl -sS --fail-with-body "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/ports/8080" \
  -H "Authorization: Bearer $MUNITO_API_KEY"
```

3. Send the token in the header `munito-sandbox-token`:

```bash
curl -sS "$URL" -H "munito-sandbox-token: $TOKEN"
```

A port is private. These open it:

- **The token** opens all ports of the sandbox while the sandbox lives. Keep it secret.
- **A signed URL** opens one private port in a browser. Send `{"expires_in": 3600}` to `POST /sandboxes/{sandbox_id}/ports/8080/url`. The browser that opens the URL keeps access to that port for 24 hours.
- **A public port** opens for each person with its URL. Set `"public_ports": [8080]` in the create, or send `{"public": true}` to `PUT /sandboxes/{sandbox_id}/ports/8080`. To make it private again, send `{"public": false}`.

Connections:

- A connection can stay open for hours, so WebSockets and server-sent events work.
- A connection with no data for one hour closes.
- The server gets the address of the client in `X-Forwarded-For`.
- The `munito-sandbox-token` header and the cookie of a signed URL do not go to the server.
- A Munito API key in `Authorization` or `x-api-key` does not go to the server. Other values of these headers go to it.
- Each cookie that the server sets stays with the host of its port: the edge removes the `Domain` attribute from each `Set-Cookie`.

## SSH [#ssh]

1. Give the sandbox your public key. Set `ssh_keys` in the create, or use `PUT /sandboxes/{sandbox_id}/ssh`.
2. Get the SSH command with `GET /sandboxes/{sandbox_id}/ssh`.
3. Run the command. The user name is the id of the sandbox.

```bash
curl -sS --fail-with-body -X PUT "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/ssh" \
  -H "Authorization: Bearer $MUNITO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"keys\": [\"$(cat ~/.ssh/id_ed25519.pub)\"]}"

curl -sS --fail-with-body "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/ssh" \
  -H "Authorization: Bearer $MUNITO_API_KEY"
```

- Only the keys in `ssh_keys` open SSH. SSH accepts no password.
- The answer gives the `host_key`. Add the line `<host> <host_key>` to `~/.ssh/known_hosts`. Then `ssh` trusts the host at once.
- A shell is bash as root, in `/workspace`. `ssh <host> <command>` runs one command. `scp` and `sftp` work.
- `ssh -L 3000:localhost:3000` reaches port 3000 of the sandbox. A forward reaches only the ports of the sandbox.
- SSH refuses remote forwards (`-R`), agent forwarding and X11.
- A new list of keys replaces the old list. An open session stays open.
