Quickstart
Add a machine, connect your Docker CLI to it, and run docker compose up there with localhost ports working.
The shortest path from a Linux machine you can reach over SSH to your Compose stack running on it. You need coma installed (Installation) and the docker CLI with Compose v2 on your laptop.
Add the machine
coma machine add dev ssh://you@203.0.113.10COMA connects over SSH and verifies the machine's host key. The first time, it shows the key's fingerprint and asks you to trust it; compare it with the server's own key first. COMA then records an inventory of the machine. It changes nothing on the machine.
A machine that already runs Docker:
Added machine dev (ssh://you@203.0.113.10)
Ubuntu 24.04.3 LTS · linux/amd64 · 8 CPUs · 31.3 GiB memory · 142.6 GiB free on /
engines: docker 28.2.2
health: healthy (observed 2026-10-04 14:02)
Next: coma connect dev (docker and Compose then run on dev)The last line is the command to run next. More on host keys and inventory: Add a machine.
Install an engine, if the machine has none
If the inventory says engines: none found, the Next: line points here:
coma machine bootstrap dev --engine dockerCOMA shows the plan, with every command it would run, and asks before it changes anything. It installs Docker from the distribution's own packages on Debian and Ubuntu. Skip this step if the machine already has Docker. Details: Bootstrap a bare VM.
Connect
coma connect devConnected to dev: docker 28.2.2 over ssh-streamlocal
Docker CLI context: default -> coma (coma disconnect switches back)
Tools that ignore Docker contexts: export DOCKER_HOST=unix:///Users/you/.coma/run/docker.sockCOMA starts its background process, comad, opens a local Docker API socket for the machine, and makes the Docker context coma current. From now on docker, Docker Compose and every new shell, including shells your coding agents start, use the machine. Nothing is exposed on the network: the socket is private to you, and traffic goes over SSH.
coma use does not switch Docker
coma use dev only makes dev the default target of COMA's own commands, such as coma docker and coma podman. Your docker CLI keeps pointing where it was. coma connect is the command that switches it.
Run your stack
In your project directory:
docker compose upThe containers run on dev, and Compose streams their logs to your terminal as usual.
If the Compose file bind-mounts project files, such as ./src:/app/src, COMA needs a copy of the directory on the machine. Bind mounts outside a synced directory are refused. In the project directory, start syncing before docker compose up:
coma sync watch --machine devOr set up a workspace, whose coma workspace up connects and syncs in one step. More in Source sync.
Open it on localhost
Every TCP port a container publishes on the machine is also open on your localhost at the same number. If the stack publishes port 3000:
curl localhost:3000On the machine, COMA publishes ports on 127.0.0.1 only, so ports: ["3000:3000"] does not open the port to the internet. coma port list shows the mirrored ports and their state. See Ports.
Disconnect
coma disconnectDocker CLI context restored to defaultYour docker CLI points back at the context it used before coma connect. Containers keep running on the machine. The endpoint keeps serving commands that are still running, such as docker logs -f, and stops once nothing has used it for two minutes.
Next
- Your first workspace: keep the machine, engine and ports in a
coma.yaml. - Coding agents: Codex, Claude Code and Cursor after
coma connect. - Tools that ignore Docker contexts: use
DOCKER_HOST. - Troubleshooting: when a command runs somewhere you did not expect.