devlanes is in beta and not ready for production use.Report an issue

The lanes run on a box. Your laptop gets their hostnames and ports.

A box is any machine that runs devlanes and that you can reach with ssh, or with a command such as docker exec. Your laptop's daemon mirrors the box's lanes over one session, with the same names and the same port numbers, and the box opens no ports.

Nobody sets up DNS and a wildcard cert for an hour-long sandbox.

A dev server on a box was always reachable somehow: a private IP, a forward per port, a public tunnel. None of it is worth doing for a lane an agent will throw away before lunch, so it did not get done. With devlanes the box's lanes show up on your laptop by default.

The usual way

  • http://10.0.3.14:20011A private IP in the address bar. Cookies, CORS and OAuth callbacks wanted a hostname.
  • ssh -L 20011:localhost:20011 my-vpsOne forward per port, typed again after every sleep.
  • *.dev.example.com, a wildcard cert, a subdomain per branchDNS, certbot and a proxy config, for a sandbox that lives an hour.
  • https://random-words.example.devA public URL for something that was never meant to leave the machine.

With devlanes

  • devlanes remote connect my-vps --backgroundOne command. The connection belongs to your local daemon and stays until you disconnect.
  • https://myapp1.localhostThe box's hostnames join your local proxy, with your local certificate.
  • psql -h 127.0.0.1 -p 20013 myapp_lane1Databases, debuggers, gRPC and websockets, on the box's own port numbers.
  • devlanes daemon pairA one-time code pairs your machine. The box keeps a hash of the token.

Pair once. The box opens no ports.

The box prints a code that works once and expires in 10 minutes. Your laptop trades it for a token the box keeps only a hash of. From then on the connection belongs to your local daemon: it survives sleep, network loss and restarts, until you disconnect.

Anything you can reach over ssh can be a box. The tunnel runs inside the session itself, so the box needs no TCP forwarding enabled and no firewall rule.

on my-vps
$ devlanes daemon pair
pairing code: K7QM-3XWD
it works once and expires in 10 minutes
on your other machine, run:
  devlanes remote connect <box> --code K7QM-3XWD
on your laptop
$ devlanes remote connect my-vps --code K7QM-3XWD --background
$ devlanes url ls
HOST                      TARGET       PORT   STATE
api.myapp1.localhost  ->  myapp@1:api  20010  ready
myapp1.localhost      ->  myapp@1:web  20011  ready

Same ports, same hostnames, on your laptop.

Your laptop binds the box's port numbers on its own 127.0.0.1 and adds the box's hostnames to your proxy, with the certificate you already trust. The URL a service prints on the box is the one you open here, and psql, a debugger, gRPC or websockets connect as if the service were local.

your laptop
browser
https://myapp1.localhost
devlanes daemon
proxy :443, TLS from your CA
api.myapp1.localhost :20010
myapp1.localhost :20011
mirror on 127.0.0.1
:20010 :20011 :20012
my-vpsor a container, pod, WSL distro or codespace
no inbound ports
only sshd (or the exec command)
devlanes daemon
myapp@1 (feat/checkout)
api 127.0.0.1:20010
web 127.0.0.1:20011
worker 127.0.0.1:20012
devlanes tunnel --stdio
started by sshd, once per client
the URL printed there opens here.

The box's lane shows up in your TUI.

A connected box's lanes join the project tab after your own, with their domain, their ports and the URL that opens each one on this machine. Starting and stopping stays on the box; the pane says what to run there.

devlanes, lane @1 on my-vps
devlanes  1 myapp         Monitor  Daemon  Boxes
lanes  1 @0 main   2 @1 my-vps  [ ] switch lanes
┌ myapp@1  running · 3 up ────────── on my-vps ┐
│ box       my-vps · ssh · devlanes 0.10.0     │
│ domain    myapp1.localhost                   │
│ services  3 of 3 up                          │
│ infra     postgres :20013                    │
│ ports     4 of 4 mirrored here               │
│ urls      https://api.myapp1.localhost       │
│           https://myapp1.localhost           │
│                                              │
│ Read-only here. On my-vps: ssh my-vps,       │
│ then devlanes status myapp@1                 │
└──────────────────────────────────────────────┘
 o open in browser   [ ] switch lane   ? all keys

No ssh on the box? A command works too.

A container, a pod, a WSL distribution or a codespace has no sshd, but each has a command that runs a program inside it: docker exec, kubectl exec, wsl.exe, gh codespace ssh. Name the box in your user config with that command and it connects and pairs like any ssh host.

~/.devlanes/config.yaml
remote:
  boxes:
    myapp:
      command:
        - docker
        - exec
        - -i
        - myapp
        - devlanes
        - tunnel
        - --stdio

In the docs

Install devlanes

Homebrew

brew install devlanes-run/tap/devlanes

Shell script

curl -fsSL https://devlanes.run/install.sh | sh

PowerShell

irm https://devlanes.run/install.ps1 | iex

npm

npm install -g devlanes

uv

uv tool install devlanes

cargo binstall

cargo binstall --git https://github.com/devlanes-run/devlanes devlanes