Run a local process as if it were inside your cluster: prefix any command with plug and it resolves the cluster DNS and reaches the cluster services like any workload of the stack - no code change, no proxy configuration in your app. One tiny agent container on the cluster side, one static CLI on yours. Docker, Swarm, Kubernetes and OpenShift.

Getting started

Two pieces: a small agent on the cluster, and the plug CLI on each dev machine. Set up once per cluster - after that, day-to-day runs need no sudo or admin. New here? See what plug does first.

1. Deploy the agent, once, on the cluster

Add the service to the stack you want to reach - it joins the stack's network automatically:

Loading plug-service.yml…

The socket line is required on Docker, Compose and Swarm: it is how the agent creates your -s name, and an agent without it refuses to start rather than fail on your first -s. It is root on the host, so mount it only on a cluster you trust. Kubernetes needs no socket - a Services-only RBAC role instead, and the same rule applies. See Install for every platform: Compose, Swarm, Kubernetes, OpenShift, or one agent for several stacks.

Left as is, the agent lets in whoever reaches its port: the right default on a network you trust. To let in only the developers a member accepts, uncomment PLUG_ADMISSION: invite (on Compose, with the members volume). The three ways a cluster decides who gets in, and how to move between them, are in the Security model.

2. Install the CLI, on each dev machine

One line, straight from the cluster - the agent hands over the right binary. The install grants plug its privilege once, so that no later run ever needs it.

Commands below are for

A single sudo, inside the installer:

# the agent regenerates its host key each start (not a secret here) - skip the check
ssh -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null get@<cluster-host> install | sh

The installer reads the cluster address straight from your ssh command and saves a profile named after that host, so plug is ready right away. Install from a second cluster and you get a second profile to run alongside. (No live ssh? The first run asks once, via a short wizard.)

To give the profile a name of your own, the one you will type after -p, add it to the command: useful when the host says nothing (localhost behind a port-forward) or when a gateway names the application.

ssh -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null get@<cluster-host> install my-cluster | sh

3. Run your process as a service of the cluster

Something the cluster can call back: it answers to a name, like any deployed workload.

plug -s my-app:8080:3000 npm run start:dev

Your command runs as a named member of the cluster: it answers to my-app:8080, forwarded to its local :3000, and in your code you address cluster services by name - http://pdfbox:8080, mongodb:27017. Ctrl-C stops your process; when the last one exits, your machine is back exactly as it was.

To keep that command with the project, in package.json, a Maven or Gradle build, or a Makefile, see From your build tool.

4. Run your process as a pure client

Something the cluster will never call back - a GUI database tool, a one-off script. It reaches services by name, but nothing is named and no port is reserved on the agent. One stance or the other, never both:

Commands below are for
plug -c mongodb-compass

Give plug the program, not a launcher for it. xdg-open is the reflex here, and it does not work: it hands the program to the desktop session and returns at once, with the program parented to something else. plug then sees your command finish, ends the session and takes the tunnel down, while the program it was supposed to serve is only just starting - and being nobody's child of plug, it cannot be attributed to a cluster either. Same reason as --dockerrun further down: what you launched handed the real work to another process manager. Point plug at the executable itself, as above, and it stays for as long as the program runs.

5. Run a container as a member of the cluster

Testing an image before you deploy it needs one more word, because prefixing docker with plug cannot work: plug carries the traffic of the process it launches, and that process is the docker CLI, which posts a request to a socket and exits. The container is created by the docker daemon, which is nobody's child, so none of its traffic would go through the tunnel. --dockerrun puts plug in the network the container will use instead:

# your image reaches cluster services by name, unmodified
plug -c --dockerrun docker run --rm my-image

# and can answer to one, exactly like a process would
plug -s my-api:8080:8080 --dockerrun docker run --rm my-image

Same on all three systems, because a container is a Linux environment on every one of them. docker run only, and in the foreground: see the CLI reference for the limits and the two environment variables that go with it.

6. Let plug pick the local port

The cluster port is agreed in advance - it is what other workloads dial. The local one is nobody's business but yours, and pinning it is what makes two projects fight over 3000. Name it instead, and plug picks a free one per session:

plug -s web:8080:PORT npm run dev -- --port={PORT}

PORT declares it - bare, because the third field of a -s can only ever be a port, so there is nothing to disambiguate. {PORT} references it in the command - braced, because argv is free text and a bare PORT would also rewrite --transport=PORTAL. Any name works, and the same name twice means one port:

# one process, two cluster names, one listener
plug -s web:80:PORT -s web-tls:443:PORT node server.js --listen={PORT}

The command line is the only channel - plug puts nothing in your process's environment. The two halves have to match, and plug says so at startup rather than let either mistake through: a {TOKEN} nothing declared reaches your command as a literal string, and a name nothing references allocates a port your process is never told about. Pinning still works, and still makes sense when something outside the session needs a stable address - a bookmarked URL, a debugger attach config.

Where to next

Something feels off? plug doctor checks everything plug touches - binaries, resolver state, the privileged service, each profile's cluster - and names the remedy next to each finding.

Read the CLI reference for every command, How it works for the mechanics, Profiles & versions for day-to-day usage and updates, Swarm for the cluster side, Security model before deploying anywhere sensitive, the Coverage matrix for what works on which OS, and the Roadmap for what's coming.