A project can feel like its own development machine without staying running all day. Give its devcontainer an SSH alias, and let connections control its lifecycle:
Connect to projects-example
→ start the devcontainer if needed
→ open an SSH session inside it
Close the last connection
→ wait a short grace period
→ stop the project's containers
An SSH-capable editor such as T3 Code gets a remote environment. A terminal gets a shell where you can run a coding agent such as Codex CLI. The project keeps its existing development-container setup.
Start with the devcontainer CLI
With Docker running and the CLI installed, start an existing checkout:
npm install -g @devcontainers/cli
devcontainer up --workspace-folder "$HOME/Projects/example"
The CLI uses the project's definition and applicable lifecycle hooks. Its output identifies the container's user and workspace. It does not automatically clone the repository: the workspace follows the definition, often mounting your existing checkout. CLI documentation
The container also needs an SSH server and your public key in the login user's ~/.ssh/authorized_keys. For Debian/Ubuntu containers, the official SSH server feature supplies the server:
"features": {
"ghcr.io/devcontainers/features/sshd:1": {}
}
Merge this into your definition and rebuild if needed. Add the public key separately; installing an SSH server does not configure authentication for you.
Let the SSH alias start the environment
An ordinary SSH alias can run a connection helper using ProxyCommand:
Host projects-example
HostName localhost
User vscode
ProxyCommand ~/bin/project-ssh example
Use the actual container user. project-ssh is a small lifecycle script you supply, rather than a built-in command. Its job is to:
- Resolve the project's checkout.
- Run
devcontainer upwhen the environment is stopped. - Connect SSH to the container's server.
The transport can use Docker directly:
docker exec --user root -i CONTAINER_ID /usr/sbin/sshd -i
The container ID comes from startup. Docker carries the SSH stream; the server handles login as the configured user. This avoids assigning a listening port to each project. Keep setup messages on stderr so stdout remains the SSH protocol stream. OpenSSH server documentation
Stop after the last connection—not the first
The helper also tracks live connections. Simultaneous connections share one startup operation and reuse the same container.
When the last connection closes, start a timer—for example, 60 seconds. A new connection cancels that timer. If the project stays idle, stop its containers and retain their files and volumes. For a Compose project, include its dependency containers too.
This requires a little lifecycle bookkeeping outside SSH. ProxyCommand supplies the connection hook; SSH configuration has no built-in “stop my devcontainer when idle” setting. A small script and an idle watcher are sufficient; no Python-specific design is required. SSH configuration reference
An editor may keep its SSH connection open between chats. Closing a chat therefore might not stop the environment. Disconnecting the environment releases that connection. Background jobs stop too when the container shuts down.
macOS, Linux and WSL
The flow is the same. The Docker host and the location of the SSH client differ:
| Platform | Where to run it | What changes |
|---|---|---|
| macOS | Your Mac terminal, with Docker Desktop or Colima running | Docker runs Linux containers in a VM. The alias and helper live on the Mac. |
| Linux | Your Linux terminal, with Docker Engine available | No Docker VM is needed. The alias and helper live on the Linux host. |
| Windows with WSL 2 | Your WSL terminal, with Docker Desktop integration enabled | Install the CLI and helper inside WSL; keep the checkout in its Linux filesystem. |
For WSL, enable Docker Desktop integration for the distribution you use. A Windows application using Windows SSH does not automatically read WSL's ~/.ssh/config: it needs a supported way to connect through WSL, or a separate Windows-side setup. Docker's WSL guide
Use it from your coding tool
First check the alias in a terminal:
ssh projects-example
Then select that SSH environment in your editor and point it at the container workspace reported by the CLI. Install any coding CLI you want to run inside the container as part of its setup.
The daily interaction becomes simple: select the project, work in its environment, then disconnect. The devcontainer definition controls the project; the connection helper controls when it runs.
Top comments (0)