# SSH Access

Daytona provides SSH access to sandboxes through an SSH gateway, so you can connect from local terminals, IDEs, and development tools without installing software in the sandbox.

SSH has no equivalent of a bearer header, so the credential travels in the SSH username. Connect as `<sandboxId>#<apiKey>` to the gateway of the sandbox's region:

```bash
ssh -p 2222 '<sandboxId>#<apiKey>'@proxy.app.daytona.io
```

The gateway splits the username on the first hash character, validates the API key for that sandbox, and proxies the session to the SSH server inside the sandbox. The sandbox ID part accepts either the region-tagged ID returned by the API (`<base58>-<region>`) or the bare UUID.

The gateway accepts the SSH handshake without client authentication and authorizes afterwards, so a rejected connection is closed right after the handshake instead of failing with a password prompt. Connections are rejected when:

- The API key is invalid or does not belong to the sandbox's project
- The sandbox ID is unknown, or the sandbox lives in a different region than the gateway
- The sandbox is not **`running`**
- The username has no **`#`** separator, or either part is empty

The sandbox reports running once its toolbox port answers. The in-sandbox SSH server can lag behind by a few seconds after a create, so a connection opened immediately after the sandbox becomes running may be closed. Retry the connection.

:::note[Info]
The SSH gateway host is region-specific. Use the host shown in the dashboard's **SSH** tab, or read the SSH gateway host and port fields from the sandbox details in the API.
:::

## Use cases

SSH access is used when a local tool needs a shell or a TCP connection inside a sandbox.

- **Remote development in an IDE**: VS Code and JetBrains IDEs connect over SSH, then edit and run code in the sandbox. JetBrains Gateway installs the selected IDE in the sandbox.
- **Local terminals**: a developer opens a shell in the sandbox from their own terminal, with no software installed in the sandbox. Resizing the local window resizes the remote shell.
- **File transfer**: **`scp`** and **`sftp`** copy files between your machine and the sandbox with the standard OpenSSH clients.
- **Scripts and pipelines**: a one-shot command returns the exit code of the remote command, with stdout and stderr on separate streams. Input piped into **`ssh`** reaches the remote command.
- **Sandbox services on your machine**: local port forwarding connects a local port to a database or web server in the sandbox, without exposing it to the internet.
- **Inspection of agent sandboxes**: a person connects to the sandbox an agent works in and inspects its files and processes.

## Access from Dashboard

The [Daytona Dashboard ↗](https://app.daytona.com/dashboard/sandboxes) builds the SSH command for you.

1. Go to [Sandboxes ↗](https://app.daytona.com/dashboard/sandboxes)
2. Locate the sandbox you want to connect to
3. Select **SSH access** in the options menu (**⋮**), or the sandbox's **SSH** tab
4. Copy the **SSH command** and run it in your terminal

The command uses your selected project's API key, masked in the panel; use **Reveal** to show it. Copying always yields the full command. If the gateway rejects a stale key, use **Regenerate key**.

Only members whose project API key has sandbox write permission see the SSH tab.

## Access via CLI

The Daytona CLI resolves the SSH gateway of the sandbox's region and runs the system SSH client with your credential in the username.


```bash
# Interactive shell
daytona sandbox ssh {sandboxId}

# One-shot command
daytona sandbox ssh {sandboxId} uname -a

# Forward a sandbox port to your machine
daytona sandbox ssh {sandboxId} -L 8080:localhost:8080
```

- SSH flags after the sandbox ID go to **`ssh`** before the destination.
- Any remaining arguments become the remote command.
- The CLI requires OpenSSH **`ssh`** on your **`PATH`**.
- SSH flags end at the first argument that does not start with **`-`**.
- Use **`--`** to end the SSH flags explicitly when the remote command itself starts with **`-`**.
- The CLI writes the credential to a temporary SSH config file with mode **`0600`**.
- The CLI removes the temporary SSH config file when **`ssh`** exits.
- The temporary SSH config file keeps the API key out of the process arguments.
- The CLI exits with the exit code of **`ssh`**.
- The exit code of **`ssh`** is the exit code of the remote command, or 255 if **`ssh`** fails to connect or hits an error.


## Access via API

The sandbox details include the SSH gateway endpoint for the sandbox's region:

```bash
curl 'https://api.daytona.com/sandboxes/{sandboxId}' \
  --header 'Authorization: Bearer YOUR_API_KEY'
```

Build the SSH command from the SSH gateway host and port fields in the response, the sandbox ID, and your API key. Both fields are absent when the region's gateway cannot be resolved. The gateway shares its host with the region's toolbox proxy URL and listens on port 2222.

## Usage examples

The gateway forwards every SSH channel and channel request, so interactive shells, one-shot commands, scp, sftp, and local port forwarding work with the standard OpenSSH clients.

```bash
# Interactive shell
ssh -p 2222 '<sandboxId>#<apiKey>'@proxy.app.daytona.io

# One-shot command
ssh -p 2222 '<sandboxId>#<apiKey>'@proxy.app.daytona.io uname -a

# Pipe stdin into a remote command
cat ./input.txt | ssh -p 2222 '<sandboxId>#<apiKey>'@proxy.app.daytona.io wc -l

# Copy a file into the sandbox
scp -P 2222 ./file.txt '<sandboxId>#<apiKey>'@proxy.app.daytona.io:/work/

# Interactive file transfer
sftp -P 2222 '<sandboxId>#<apiKey>'@proxy.app.daytona.io

# Forward a sandbox port to your machine
ssh -p 2222 -L 8080:localhost:8080 '<sandboxId>#<apiKey>'@proxy.app.daytona.io
```

Exit codes are preserved, so `ssh ... <command>` can be used in scripts and pipelines. Standard output and standard error arrive as separate streams, so `2>` redirection on the client side works as with any SSH host. Closing stdin on the client half-closes the remote command's stdin, so piped commands terminate once the input is consumed.

## Session environment

An SSH session on a Linux sandbox lands in the SSH server run by the Daytona daemon:

| **Property**          | **Behavior**                                                                                                                                                        |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Shell**             | The first of **`zsh`**, then **`bash`**, listed in the sandbox's **`/etc/shells`**; **`sh`** when neither is listed. Interactive sessions and one-shot commands use the same shell. |
| **Working directory** | The daemon's, which is the image's **`WORKDIR`** or, if none, the home directory. One-shot commands run there, and relative **`scp`** and **`sftp`** paths resolve against it.  |
| **Terminal**          | Honors **`pty-req`** and **`window-change`**, so resizes reach the shell.                                                                                                   |
| **Idle timeout**      | None; the sandbox lifecycle, not the SSH server, ends idle sessions.                                                                                                |

## Port forwarding

Local forwarding (`-L`) opens a TCP connection inside the sandbox for every connection to the local port. The address is resolved inside the sandbox, so `-L 8080:localhost:8080` reaches a service bound to `localhost:8080` in the sandbox. A target port with nothing listening is refused with `open failed: connect failed`; an unresponsive target times out after 10 seconds.

```bash
# Reach a sandbox web server on http://localhost:8080
ssh -p 2222 -N -L 8080:localhost:8080 '<sandboxId>#<apiKey>'@proxy.app.daytona.io
```

The following are not supported through the gateway:

- **Remote forwarding (`-R`)**: rejected, with **`remote port forwarding failed`**.
- **Unix socket forwarding** (**`-L`**/**`-R`** with socket paths)
- **Agent forwarding (`-A`)**

To expose a sandbox port to the internet rather than to your machine, use [sandbox previews](https://www.daytona.io/docs/en/v2/preview.md).

## Connection lifetime

An SSH session stays open for as long as the sandbox is running. The gateway closes the client connection promptly when the sandbox stops running or is deleted.

Reconnecting with the same command attaches to the sandbox again. For long interactive sessions, wrap ssh in a reconnect loop or use autossh; set the ServerAliveInterval option so the client notices a dead connection quickly:

```bash
ssh -p 2222 -o ServerAliveInterval=3 -o ServerAliveCountMax=2 '<sandboxId>#<apiKey>'@proxy.app.daytona.io
```

SSH traffic counts toward the sandbox's [idle timeout](https://www.daytona.io/docs/en/v2/linux-sandboxes.md#idle-timeout). The gateway records activity once the in-sandbox SSH server has answered, and then whenever bytes flow from the client into the sandbox. An open session with no input does not keep the sandbox alive: a shell left idle at the prompt, or a long-running command that produces output without further input, does not reset the idle clock. Type into the session or reconnect to reset it.

## Connect with VS Code

You can connect VS Code directly to your sandbox using the Remote SSH extension.

1. Install the [Remote Explorer extension ↗](https://marketplace.visualstudio.com/items?itemName=ms-vscode.remote-explorer)
2. Add a new SSH connection
3. When prompted for the SSH connection URL, paste the SSH command from above

For more information, see the [VS Code Remote SSH documentation ↗](https://code.visualstudio.com/docs/remote/ssh).

## Connect with JetBrains IDEs

JetBrains Gateway provides remote development support for connecting to your sandbox.

1. Download [JetBrains Gateway ↗](https://www.jetbrains.com/remote-development/gateway/)
2. Add a new connection
3. When prompted for the SSH connection URL, paste the SSH command from above
4. Select the IDE to install in your sandbox

## Security

SSH access is stateless, with no per-sandbox access list or SSH token. The credential is your project API key, granting access to every sandbox in the project and to the API.

:::caution[Warning]
Anyone with the SSH command can access the sandbox. Treat it like a secret. To cut off access, revoke or rotate the API key on the [API keys](https://www.daytona.io/docs/en/v2/api-keys.md) page.
:::

### Host keys

The host key your client sees is the gateway's, not the sandbox's. Each region's gateway presents one stable ed25519 host key, so the known hosts file holds one entry per gateway host and stays valid across sandboxes and gateway restarts. A host key change warning for a gateway host you have connected to before should be treated as suspicious.

The gateway-to-sandbox hop runs inside the private overlay network. The in-sandbox SSH server is reachable only from the gateway, not from other sandboxes or the internet.