Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ nav:
- dstack ps: docs/reference/cli/dstack/ps.md
- dstack stop: docs/reference/cli/dstack/stop.md
- dstack attach: docs/reference/cli/dstack/attach.md
- dstack connect: docs/reference/cli/dstack/connect.md
- dstack login: docs/reference/cli/dstack/login.md
- dstack logs: docs/reference/cli/dstack/logs.md
- dstack metrics: docs/reference/cli/dstack/metrics.md
Expand Down
28 changes: 27 additions & 1 deletion mkdocs/docs/guides/cli-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,33 @@ $ dstack attach <run name>
Use `--job JOB_NUMBER` with `dstack attach` to attach to another job. Ports
declared in the run configuration are forwarded while attached.

### Connect without attaching

When the server has the [SSH proxy](server-deployment.md#ssh-proxy) enabled,
the owner of a running dev environment can connect without keeping an attach
process running:

<div class="termy">

```shell
$ dstack connect &lt;run name&gt;
```

</div>

Interactive SSH is the default. Use `--ide` to open the IDE configured by the
dev environment, or `--vscode`, `--cursor`, `--windsurf`, or `--zed` to require
a specific configured IDE.

`dstack connect` refreshes the run, validates the complete proxy connection
record, and updates a local SSH alias using the current user's built-in key. It
does not fall back to direct host SSH. Use `--expect-sshproxy HOST[:PORT]` to
require a particular proxy endpoint.

Unlike `dstack attach`, this command does not forward ports or stream logs. See
the [`dstack connect` reference](../reference/cli/dstack/connect.md) for the
connection and validation details.

??? info "User SSH keys"
The server stores a built-in SSH key pair for each user.

Expand Down Expand Up @@ -269,7 +296,6 @@ available in the CLI or for integrations that need to call the server directly.
Out of scope for this guide:
- Git repo workflows
- File upload workflows
- Direct SSH/sshproxy workflows
- Backward compatibility between older clients and servers
-->

Expand Down
14 changes: 13 additions & 1 deletion mkdocs/docs/guides/server-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,19 @@ This lets you:
- Reach runs on SSH fleets with a head node without giving users the head node's SSH key.
- Let users connect to runs without `dstack attach`. This requires uploading their public SSH key(s) to the `dstack` server.

<!-- TODO: once connecting through the proxy without `dstack attach` is exposed in the UI/CLI, document the steps in this section. -->
After the proxy is deployed and configured, the owner of a running dev
environment can open a direct SSH or IDE session without keeping `dstack
attach` running:

```shell
dstack connect &lt;run name&gt;
dstack connect --ide &lt;run name&gt;
```

The command uses the current user's built-in SSH key and fails if the server
does not return a valid proxy connection. It does not forward ports or stream
logs. See the [`dstack connect` reference](../reference/cli/dstack/connect.md)
for the supported IDEs and security checks.

### Deployment

Expand Down
8 changes: 8 additions & 0 deletions mkdocs/docs/reference/api/python/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ finally:
show_root_toc_entry: false
heading_level: 4

### `dstack.api.RunDirectConnection` { #dstack.api.RunDirectConnection data-toc-label="RunDirectConnection" }

::: dstack.api.RunDirectConnection
options:
show_root_heading: false
show_root_toc_entry: false
heading_level: 4

### `dstack.api.Resources` { #dstack.api.Resources data-toc-label="Resources" }

#SCHEMA# dstack.api.Resources
Expand Down
96 changes: 96 additions & 0 deletions mkdocs/docs/reference/cli/dstack/connect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
title: connect
description: Connect directly to a running dev environment through the SSH proxy
---

# dstack connect

This command connects directly to a running dev environment through the
server's configured SSH proxy. It can open an interactive SSH session or the
IDE configured by the dev environment without keeping `dstack attach` running.

## Usage

<div class="termy">

```shell
$ dstack connect --help
#GENERATE#
```

</div>

Interactive SSH is the default mode:

```shell
dstack connect &lt;run name&gt;
```

Use `--ide` to open the IDE selected by the dev environment configuration:

```shell
dstack connect --ide &lt;run name&gt;
```

The supported IDEs are VS Code, Cursor, Windsurf, and Zed. You can request one
explicitly with `--vscode`, `--cursor`, `--windsurf`, or `--zed`. An explicit
option fails if it does not match the run configuration. On Linux, the Zed
launcher can be named either `zed` or `zeditor`.

Use `--replica` and `--job` to select a job. Without `--replica`, the command
uses any running replica with the selected job number.

## Pin the SSH proxy

Automation can require an exact proxy endpoint:

```shell
dstack connect --expect-sshproxy proxy.example.com:2222 &lt;run name&gt;
```

The port defaults to `22`. Bracket IPv6 addresses, for example
`[2001:db8::1]:2222`. If the run reports a different endpoint, the command
fails before downloading a key, updating local SSH configuration, or launching
a client.

## Requirements and behavior

`dstack connect` is intentionally limited to a running dev environment owned by
the current user. The server must have the SSH proxy enabled and provide a
complete, internally consistent SSH and IDE connection record for the selected
job. The command never falls back to direct host SSH.

The CLI validates the proxy host, port, upstream identifier, SSH command, IDE
URL, and remote working directory before changing local state. It then stores a
local `dstack-direct-*` alias in `~/.dstack/ssh/config` using the current user's
built-in SSH key. The selected job's dynamic proxy identifier stays in the
`user@alias` target, so resolving the connection again after a retry does not
reuse a stale proxy session.

Client processes are launched with argument vectors, without a shell. Remote
paths in IDE URLs are percent-encoded before they are passed to the local IDE.

This command does not forward ports or stream logs. Use
[`dstack attach`](attach.md) when those attached-session features are required.

## Python API

Use `Run.get_direct_connection()` to perform the same refresh, validation, key
setup, and SSH alias update without launching a client:

```python
import subprocess

from dstack.api import Client

client = Client.from_config()
run = client.runs.get("my-dev-environment")
if run is None:
raise RuntimeError("Run not found")

connection = run.get_direct_connection()
subprocess.run(connection.ssh_command, check=True)
```

`RunDirectConnection.ssh_command` and `ide_command` are argument tuples. Pass
them directly to a subprocess API; do not join them into a shell command.
Loading