# Box: a dev environment in the browser
URL: https://synquic.tech/docs/guides/dev-box.md

Install a Box to get VS Code in the browser on your own server, with the runtimes you pick, git and build tools, your code on persistent volumes, and a domain for any dev server in one step.

import { Step, Steps } from 'fumadocs-ui/components/steps';

A **Box** is a development environment you install from the Apps catalog: VS Code in the browser
([code-server](https://github.com/coder/code-server), the official image from Coder), the runtimes you pick
(Node.js, Bun, Python, Go), git, curl and build tools, and your code on persistent volumes. It runs on your
server as an ordinary [one-click app](/docs/guides/one-click-apps), so logs, backups, domains and
redeploys work as for any project.

<Callout title="What you need first">
- A server with at least 2 GB of memory. The install wizard checks it. To cap what the Box and your builds
  can use, set limits under [Resources](/docs/guides/sleep-mode-resources) like for any app.
- A domain for the editor, so VS Code opens over HTTPS. A free subdomain works if your panel offers one.
</Callout>

## Create a Box

<Steps>

<Step>

### Open the app

Click **New Project** in the sidebar, stay on the **Apps** tab, and choose **Box** (search for `box` or
`vscode`).

</Step>

<Step>

### Pick the runtimes

**Runtimes** lists Node.js (LTS), Bun, Python 3 and Go. Node.js and Python are selected by default. git,
curl and build tools (gcc, make, pkg-config) are always there, whatever you pick.

</Step>

<Step>

### Optionally, a repository

**Git repository to clone** takes a public `https://` URL, and **Branch** a branch name (empty means the
repository's default branch). The Box clones it once, on its first start. See
[Clone a repository](#clone-a-repository) for private repositories.

</Step>

<Step>

### Choose the editor's address and install

Give the **VS Code** endpoint a domain, then install. The first deploy builds the Box image (the code-server
image plus build tools and the start script) and starts the editor.

</Step>

</Steps>

## Sign in

Open the project. The **Overview** shows the connection details:

- **VS Code**: the editor's address. **Open** opens it in a new tab.
- **Password**: generated at install, 24 letters and digits. Reveal or copy it and sign in.

The editor opens `~/workspace`. Where things live:

| Path | Volume | What is there |
| --- | --- | --- |
| `/home/coder/workspace` | `box_workspace` | Your code, and the cloned repository. |
| `/home/coder` | `box_home` | Everything else in your home directory: runtimes, VS Code extensions and settings, shell history. |

Both volumes survive restarts and redeploys, and you can back them up like any other volume
([Volumes and volume backups](/docs/guides/volumes-backups)).

## Runtimes

The Box installs the runtimes with [mise](https://mise.jdx.dev) into the home volume, in the background on
the first start. The editor is usable right away; a runtime appears in new terminals when its install
finishes.

| Runtime | Setting | Default version |
| --- | --- | --- |
| Node.js | `BOX_NODE_VERSION` | 24.21.0 (LTS) |
| Bun | `BOX_BUN_VERSION` | 1.4.2 |
| Python | `BOX_PYTHON_VERSION` | 3.14.7 |
| Go | `BOX_GO_VERSION` | 1.27.1 |

- **Progress:** the service logs show lines starting with `[box]`, and `cat ~/.local/share/box/status` in
  the terminal prints `installing`, `ready` or `failed`. A runtime that failed is retried on the next restart.
- **Idempotent:** every start runs the same install, and a runtime that is already installed is left alone.
- **Add one later:** open **Configuration**, then **App settings**, change **Runtimes**, press
  **Save changes** and **Apply now**. The Box restarts and installs the new one.
- **Pin other versions:** the version fields are under the advanced settings. An exact version keeps a Box
  reproducible; a major version (`24`) or `lts` makes mise install the newest match.
- **Remove one:** unticking a runtime does not delete it. Run `mise unuse -g node` (for example) in the
  terminal to drop it.
- **Other tools:** mise is always installed, so `mise use -g java@21` or `mise use -g rust` adds more.

Every download is HTTPS only. The mise archive is checked against its published SHA-256 before it runs,
and mise checks the checksums of the runtimes it downloads. Debian packages for the build tools are
installed over HTTPS when the image is built.

## Clone a repository

A public repository set in **Git repository to clone** is cloned into `~/workspace/<name>` on the first
start, once. Changing the URL later clones the new repository on the next restart, next to the first one; a
folder that already exists is never overwritten.

The URL must be a plain `https://` address, with no user name or token in it. Synq does not hand its own
Git credentials (GitHub App, tokens, deploy keys) to a Box: anyone with the Box password has a shell in the
container and could read them. For a **private repository**, clone it from the Box's terminal after signing
in to your Git host there, for example:

- over HTTPS, with a fine-grained, read-only token that git asks for when you run `git clone`;
- over SSH, with a key you create in the Box (`ssh-keygen -t ed25519`) and add to the repository as a
  deploy key.

## The Box panel

The Box panel is on the project's **Overview**, under the connection details, and on the service's own
**Overview** (**Apps & Services**, then the **box** service), where it also has **Open VS Code** and
**Show password**. It shows:

- a reminder that the password opens a shell (see [Security](#security));
- the runtimes the Box installs and the repository it clones;
- **Regenerate password**;
- **Exposed ports**, with a form to expose another one.

## Regenerate the password

Press **Regenerate password** in the Box panel and confirm. Synq generates a new password, saves it as the
service's encrypted `PASSWORD` variable and restarts the editor with it. Everyone signed in is signed out
and the old password stops working; files and runtimes are kept. The new password is shown once in the
panel, and the connection details show it from then on.

If the Box cannot restart (a deployment is running, for example), the old password is put back and still
works. A Box that has not been deployed yet just saves the new password for its first start.

## Expose a port

Run a dev server in the Box's terminal, then give it a domain:

<Steps>

<Step>

### Listen on all interfaces

The dev server must listen on `0.0.0.0`, not only on `localhost`. For example `npm run dev -- --host 0.0.0.0`
for Vite, or `python -m http.server 8000 --bind 0.0.0.0`.

</Step>

<Step>

### Enter the port

In the Box panel, type the port in **Container port** and press **Expose a port**. Port 8080 is the editor
itself and is refused.

</Step>

<Step>

### Choose the address

The service's **Domains** tab opens with the **Add route** form filled in for that port. Pick a free
subdomain or your own domain and press **Add**, as in [Custom domains](/docs/guides/custom-domains). The
Box keeps running: the route is applied like any other domain, and the port is then listed under
**Exposed ports**.

</Step>

</Steps>

To stop exposing a port, remove its route on the service's **Domains** tab.

<Callout title="An exposed port is public" type="warn">
Anyone with the address reaches the dev server, without the Box password. For a private preview, open
`/proxy/3000/` on the editor's address instead (replace 3000 with your port): code-server forwards it to
the port and it stays behind the password. `/proxy/` strips the prefix, so the dev server sees `/`; a dev
server configured with that path as its base (for example Vite's `--base`) uses `/absproxy/3000/`, which
keeps it.
</Callout>

## Security

- **The password is a shell.** Anyone who has it can run commands in the container and read every file in
  it, including the workspace. Share it only with people you trust, and regenerate it when someone should
  lose access. code-server limits sign-in attempts (2 a minute, 12 an hour).
- **No root.** The editor runs as the `coder` user (uid 1000). The Box image removes code-server's
  password-less sudo, so the editor user can't become root. That is also why system packages can't be
  added from inside; use mise, npm, pip or go for tools.
- **No Docker access.** The Docker socket is not mounted and the container is not privileged, so the Box
  cannot start containers or reach the host.
- **Exposed ports are public.** See [Expose a port](#expose-a-port).

## From the API

`services.getBox` returns the editor's address, the exposed ports, the runtimes and the repository (never
the password), and `services.regenerateBoxPassword` sets a new password, restarts the editor and returns the
password once. Exposing a port is an ordinary route: add an entry to the service's `publicEndpoints` with
`services.update`. See [Services](/docs/api/services).

## Limits

- Private repositories are not cloned automatically; see [Clone a repository](#clone-a-repository).
- There is no root in the Box, so system packages beyond the build tools can't be installed.
- A runtime removed from the settings stays installed until you run `mise unuse -g <name>`.
- On Synq Cloud, a regenerated password is saved and takes effect on the next redeploy, because the running
  container can't be restarted with a new environment in place. The old password works until then.

## Related

<Cards>
  <Card title="One-click apps" href="/docs/guides/one-click-apps" description="The install wizard, domains, connection details and app settings." />
  <Card title="Custom domains" href="/docs/guides/custom-domains" description="Free subdomains, your own domains and HTTPS." />
  <Card title="Volumes and volume backups" href="/docs/guides/volumes-backups" description="Back up and restore the Box's workspace and home volumes." />
</Cards>
