Cubicle

Remote development environments

Develop inside Cubicle Boxes from a macOS or Linux laptop, with one virtual machine per developer reached over SSH and the private network, VS Code or Cursor Remote-SSH through the alias cubicle ssh-config writes, dev servers at private names such as job-1.acme.cubicle.internal, a template Box snapshot as the team baseline, automatic hibernation 60 minutes after each start, and what Cubicle cannot do for remote development.

Develop inside a Box from a macOS or Linux laptop. Each developer gets a Box, a Linux virtual machine with its own disk, and works in it over SSH: in a terminal with cubicle ssh, or in VS Code or Cursor through Remote-SSH. A dev server in the Box opens in the laptop's browser at the Box's private DNS name, such as http://job-1.acme.cubicle.internal:8000/. A team prepares one template Box with its tools and creates each developer's Box from its snapshot. Every Box hibernates 60 minutes after each start, whatever you are doing, so a session longer than an hour needs another start; see Day to day.

Why a Box

  • A full virtual machine. A Box boots its own Linux kernel and runs a whole Linux system, with systemd, an SSH server and user accounts. See Boxes.
  • A persistent disk. Your repositories, packages and settings stay on the Box's disk across stop, start and hibernation.
  • sudo for people. Once you have added an SSH key, your guest account in the Box has passwordless sudo. See The guest account and sudo.
  • A private DNS name. Services in the Box are reachable from your laptop on their own ports at <box>.<org>.cubicle.internal, and nothing is exposed to the internet.
  • A desktop console. The Dashboard shows the Box's graphical desktop for programs that need a screen. See Use the desktop console.
  • A team baseline. Snapshot one prepared Box and create every developer's Box from the snapshot. See Build a template Box.

How it works

The cubicle CLI and its tunnel, a root network helper, hold a WireGuard connection from your laptop to Cubicle's Gateway, which forwards traffic only to the Boxes you hold a grant on. cubicle ssh and cubicle ssh-config write an OpenSSH alias for a Box, with its host key pinned, so ssh, scp, rsync and Remote-SSH extensions connect to port 22 on the Box's private address as your own guest account. Other ports in the Box are reachable the same way, by the Box's private DNS name. Connections only go from your laptop to the Box, and the Box reaches the public IPv4 internet for packages and Git. Networking describes the full path.

Before you begin

  • A Cubicle account. Cubicle is invite-only.
  • Membership in an organization that can create Boxes, acme in the examples. A personal organization starts with Box creation turned off; see Box creation approval. In a team where an owner or admin creates the Boxes, a developer needs only membership and a grant.
  • A laptop running macOS or Linux, on x64 or arm64, where you can use sudo. Linux also needs systemd-resolved; see platform requirements. Windows is not supported.
  • A network that allows outbound UDP to Gateway. WireGuard uses only UDP.
  • For an editor: VS Code or Cursor with its Remote-SSH extension.

Set up a development Box

  1. Install the CLI and the tunnel. The installer asks before it installs the CLI, and --tunnel then installs the tunnel, which runs sudo and asks for your password.

    curl -fsSL https://api.cubicle.sh/downloads/install | sh -s -- --tunnel
    cubicle tunnel status
    # installed, disconnected

    If cubicle is not found, add ~/.local/bin to your PATH; see Install the CLI.

  2. Log in. The CLI prints a link and a code; press Enter to open the browser and confirm the code there.

    cubicle login
    # Logged in as dev@example.com.
  3. Add your SSH public key. Cubicle accepts only ssh-ed25519 keys, and without an argument the CLI reads ~/.ssh/id_ed25519.pub.

    ssh-keygen -t ed25519   # only if ~/.ssh/id_ed25519 does not exist yet
    cubicle keys add
    # added SHA256:…
  4. Create a Box sized for development. The default base image is Debian-based, and its default size of 2 vCPUs, 2048 MiB of memory and a 12 GiB disk is small for builds. A Box can have up to 64 vCPUs, 262,144 MiB of memory and a 2048 GiB disk; see Limits.

    cubicle boxes create --org acme job-1 --vcpus 4 --memory 8192 --disk 40 --wait
    # 0b3f6c2e-8d4a-4f6e-9c1d-7a2b5e8f9d10  acme/job-1  running  desired=running@1  node=worker-1  ssh=ready
    • A Box cannot be resized, so choose its size now.
    • Its vCPUs, memory and disk stay reserved while it is stopped or hibernated. When no Node has room, create fails with 503 capacity.
    • You created the Box, so you hold a grant on it.
  5. Open a shell in the Box. cubicle ssh connects the tunnel, writes the alias cubicle-acme-job-1 and runs ssh as your guest account.

    cubicle ssh acme/job-1

    Install your tools with sudo, for example sudo apt-get update && sudo apt-get install -y git, and clone your repository.

  6. Connect VS Code or Cursor. The tunnel stays connected after ssh exits; if it is not, run cubicle connect. In the editor, run Remote-SSH: Connect to Host… and enter the alias cubicle-acme-job-1. The editor reads the same ~/.ssh/config, so the pinned host key and your key apply. For a Box you have not opened with cubicle ssh yet, write its alias first:

    cubicle ssh-config acme/job-1
    # configured: ssh cubicle-acme-job-1
  7. Run a dev server in the Box, listening on all interfaces, and open it from your laptop:

    # In the Box
    python3 -m http.server 8000 --bind 0.0.0.0

    Open http://job-1.acme.cubicle.internal:8000/ in your laptop's browser, or run curl http://job-1.acme.cubicle.internal:8000/.

    • Any port works, except TCP 5900, which leads to the desktop console.

    • A server that listens only on 127.0.0.1 is not reachable by name. Start it with its host option set to 0.0.0.0, or forward its port over SSH and open http://localhost:8000/:

      ssh -N -L 8000:localhost:8000 cubicle-acme-job-1
    • Private names have no HTTPS certificates. Use plain HTTP, or the forwarded localhost port when your app needs localhost as its address.

    • If your dev server accepts only host names it knows, allow job-1.acme.cubicle.internal in its settings.

SSH into a Box and Reach a Box over the private network cover each step's options and errors.

Set up a team

An owner or admin of the organization prepares a template once and gives each developer a Box made from it.

  1. Add each developer to the organization. They need a Cubicle account first, so ask a Cubicle operator to invite anyone who has none.

    cubicle members add --org acme dev@example.com --role member
    # dev@example.com is member
  2. Build the template Box as a person, over SSH: commands that a service account sends cannot rely on sudo. Its disk is the smallest disk a Box made from it can have, so keep it small.

    cubicle boxes create --org acme template --disk 20 --wait
    cubicle ssh acme/template

    In the Box, install the team's tools system-wide, with packages or into /usr/local/bin, not into your home directory. Each developer gets their own account and home directory. Then remove your credentials, tokens and shell history, and exit. Prepare the template Box has the details.

  3. Stop the template Box and snapshot it. Note the snapshot's ID.

    cubicle boxes stop acme/template --wait
    cubicle snapshot acme/template template-v1
    # snapshot template-v1: done
    cubicle snapshots acme/template
    # SNAPSHOT_ID  template-v1  complete  2026-11-05T10:04:12.000Z
  4. Create each developer's Box from the snapshot, then grant it to them by user ID, the first column of cubicle members list --org acme:

    cubicle boxes create --org acme job-1 --snapshot SNAPSHOT_ID --vcpus 4 --memory 8192 --disk 40 --wait
    cubicle grants add acme/job-1 6b9e0d2c-41af-4c3b-8e2d-5f7a9c1b3d4e

    You created the Box, so you hold a grant on it too. Remove yours with cubicle grants rm acme/job-1 YOUR_USER_ID if you do not need it.

  5. Each developer follows steps 1 to 3 and 5 to 7 of Set up a development Box with their own Box.

  • One Box per developer. Anyone with a grant and an SSH key has root in the Box and can read every home directory in it, including tokens and keys. See The virtual machine is the isolation boundary.
  • Who gets grants. Grant each developer their own Box. Only owners and admins add grants, and they need a grant themselves to SSH into a Box. A member who holds a grant on the template Box can create Boxes from its snapshot themselves, but that grant also lets them SSH into the template. See Box grants.
  • Give a teammate access. To pair on a Box, an owner or admin runs cubicle grants add acme/job-1 USER_ID with the teammate's ID. The teammate then uses cubicle ssh acme/job-1 with their own guest account and sudo, or opens the dev server by name, which needs no SSH key. cubicle grants rm acme/job-1 USER_ID ends their access; their files stay on the disk. See Grant access to a Box.
  • Know the template's limits. Every Box made from the snapshot runs on the template Box's Node and shares its capacity, and the snapshot holds the template builder's home directory. See Know the limits first.
  • Update the baseline. Change the template, take a snapshot with a new name such as template-v2, and create new Boxes from it. Existing Boxes do not change. See Update the template.

Day to day

A Box hibernates 60 minutes after its start first reports running, whatever you are doing:

  • SSH sessions, editor connections, builds, console use and network traffic do not extend the hour. You cannot turn automatic hibernation off or change the hour.

  • Only a start resets it. Starting a running Box again gives it a fresh 60 minutes without a reboot, but SSH and private-network traffic pause until its Node has applied the start, and open connections may drop.

  • To see when it happens, read hibernateAt, or look at Hibernation on the State tab of the Box's details in the Dashboard, which counts down the minutes.

    cubicle boxes get acme/job-1 | jq -r .hibernateAt
    # 2026-11-05T11:02:17.000Z

What happens to your work:

Hibernate, automatically or on requestStopDelete
Files on the diskKeptKeptDeleted, with every snapshot of it
Memory and running processes, such as a dev serverKept: they carry on when the Box starts againLost: the next start is a cold bootLost
Open SSH sessions and editor connectionsEndEndEnd
Private DNS name, address, host key and grantsKeptKeptGone

What stop, hibernate and delete keep has the full list. The CLI has no hibernate command: to hibernate a Box now, use Hibernate in its row on the Dashboard's Boxes page.

To pick up after hibernation:

  1. Start the Box. A hibernated Box resumes from its saved memory.

    cubicle boxes start acme/job-1 --wait

    In the Dashboard, use Resume in the Box's row on the Boxes page. cubicle ssh does not start a Box: on a hibernated one it fails with box has no trusted host key or guest account yet (not_requested); retry when it is running.

  2. Reconnect with cubicle ssh acme/job-1, or reconnect the editor to cubicle-acme-job-1. The alias and the pinned host key still apply. The Box is routed to your laptop again within about 10 seconds of being ready. After your laptop restarts, run cubicle connect first, or use cubicle ssh, which connects.

  • A program you start in an SSH session can end when that session ends. Run a dev server you want to keep across reconnects outside the session, for example with nohup, in a terminal multiplexer such as tmux that you install, or as a systemd service.
  • At the end of the day you need not do anything: the Box hibernates within the hour. Stop it with cubicle boxes stop acme/job-1 --wait when you want a clean boot next time or before a snapshot. Either way it keeps its vCPUs, memory and disk reserved.
  • Do not shut down or reboot from inside the Box. The Box goes to failed; start it again.
  • When the host under a Box restarts, a Box that was running stays stopped, with restartRequired: true, until you start it, and its memory is lost. See A host restart needs an explicit start.
  • Push your work to a Git remote. A Box's disk and its snapshots live on one Node, and deleting the Box deletes them for good.
  • Your CLI login lasts 30 days. When it expires, run cubicle login, then cubicle connect.

Stop, hibernate and wake a Box has the steps in the SDK, the API and the Dashboard.

Limits

These come from Cubicle, not from your editor. Not available yet lists what is planned.

  • No public URLs. Cubicle has no public URLs, port forwarding or proxies to the internet. A dev server is reachable only from laptops connected to the private network with a grant on the Box, so you cannot share a preview link or receive webhooks from the internet.
  • No connections from the Box to you. A Box cannot open connections to your laptop or to other Boxes, and SSH remote forwarding (-R) is disabled. A dev server in the Box cannot use a database on your laptop or in a teammate's Box.
  • No agent or X11 forwarding. Your laptop's SSH agent is not available in the Box. For Git over SSH, create a key in the Box and add it to your Git host, or use HTTPS. Use the desktop console for graphical programs.
  • IPv4 only. The tunnel carries IPv4, and IPv6 is disabled in the Box.
  • macOS and Linux laptops only. The CLI and the tunnel do not run on Windows.
  • One operating-system user per laptop. The tunnel serves the user who installed it, with one Cubicle login at a time. Its routes are system-wide, so every user and program on the laptop can reach your Boxes, including the console on port 5900, which has no password. See Limitations.
  • API keys cannot use SSH or the private network. CI jobs and SDK code can run commands in a Box with exec, but cannot reach its ports.
  • No always-on Box. Every Box hibernates 60 minutes after each start.
  • No resize or rename. To change a Box's size, snapshot it and create a new Box from the snapshot; its disk can grow but not shrink. The new Box has its own name, address, DNS name and host key, so run cubicle ssh-config for it.
  • x86-64 Linux without a GPU. Boxes run x86-64 Linux on a kernel that Cubicle manages, and their desktops render in software.
  • One Node per template. Every Box made from one snapshot runs on the same Node. When that Node is full, create fails with 503 capacity.

On this page