gon server:dev
Provision and run a shared remote development environment on a VPS or a LAN box. Developers edit the code live over VS Code Remote-SSH; the stack (containers, builds, Vite HMR) runs on the server, not on their laptops.
When to use this
- Local Docker Desktop / WSL2 is the bottleneck — cold starts take minutes, dev machines hit RAM/CPU ceilings.
- The team wants one shared environment with reachable preview URLs instead of local tunnels.
Production stays on gon server + gon release. A dev box is a separate machine.
How it differs from server:setup
- Traefik binds
:80/:443directly and terminates TLS — no host nginx, no host MySQL (MySQL runs in the project stack). - One shared
devuser instead of a per-projectdeployuser — every developer's key lands in~dev/.ssh/authorized_keysand they all work under/home/dev/projects. - gon-cli is installed on the box, so inside a project you run the usual
gon up,gon shell,gon artisan,gon reloadover Remote-SSH. - Vite runs as a live dev server (HMR) behind Traefik on a
vite.subdomain.
server:dev:setup
One-time bootstrap of the box. Idempotent — safe to re-run after a gon-cli upgrade to pick up fixes.
gon server:dev:setup 37.235.105.189 \--alias=dev-vps1 \--email=ssl@example.com \--ghcr-token=ghp_xxxxx
What it does
- Check SSH connectivity
- Install Docker (via
get.docker.com; pullscurl+ca-certificatesfirst on minimal images) - Install
git,curl,unzip - Raise inotify limits (
fs.inotify.max_user_watches) so Vite's file watcher doesn't exhaust them on a multi-project box - Create the shared
devuser (docker group, your SSH key seeded) +/home/dev/projects - Create the
traefik-publicDocker network - Set up Traefik on
:80/:443(ACME or custom cert — see below) - GHCR login (optional)
- Install gon-cli on the box (
/usr/local/bin/gonsymlink so non-login SSH finds it) - Seed
~dev/.gon/config.jsonwith the shared PAT (only with--shared-pat)
TLS modes
Pick exactly one:
- Let's Encrypt (public VPS) — pass
--email. Traefik mints certs via the ACME resolver; the domain must resolve publicly to the box. - Custom certificate (LAN / internal CA) — pass
--certand--keytogether (no--email). gon uploads the PEM to/opt/traefik/certsand Traefik serves it via its file provider. See the LAN dev box recipe.
The chosen mode is saved as cert_mode in ~/.gon/servers.json and inherited by server:dev:add-project.
Options
| Option | Description |
|---|---|
--alias | Short name for the server (used as --host downstream) |
--user | SSH user for the first connection (default root, or the cloud image's sudo user) |
--email | Email for Let's Encrypt (public VPS). Prompted if neither --email nor --cert is given. |
--cert / --key | Paths to a PEM cert + key for a LAN box (mutually exclusive with --email; both required together) |
--ghcr-token | Classic PAT with read:packages for pulling private images |
--shared-pat | Team GitHub PAT seeded into ~dev/.gon/config.json (so devs skip gon auth:login) |
--dev-keys | Path to a file of dev public keys (one per line) to seed at setup time |
server:dev:add-project
Clone a project onto the box, configure its dev deployment, and start the stack. The repo is cloned from GitHub, so it must be pushed first.
gon server:dev:add-project demo \--host=dev-vps1 \--repo=rozklad/demo \--domain=demo.example.com
It clones the repo, writes the deployment block into gon.json (kind: vps-dev, domain, vite/mailpit hosts), generates .env (incl. theme + VITE_DEV_HMR_* / VITE_DEV_APP_ORIGIN), then runs gon install + gon up on the box. First run takes 5–15 min.
Options
| Option | Description |
|---|---|
--host | Dev server alias or IP (must be set up via server:dev:setup) |
--repo | GitHub repo slug owner/name |
--branch | Branch to check out (default: auto-detect, prefers main over master) |
--domain | Public dev domain for the app |
--vite-host | Vite HMR subdomain (default vite.<domain>) |
--mailpit-host | Mailpit subdomain (default mail.<domain>) |
--tls | acme or custom (default: inherit the server's cert_mode) |
<domain>, vite.<domain> and mail.<domain> all resolve to the box. On a public VPS this is required for the ACME challenge; on a LAN box they must resolve on your internal DNS.
server:dev:keys
Manage the shared dev user's SSH keys (onboarding / offboarding without touching unrelated entries).
gon server:dev:keys list dev-vps1gon server:dev:keys add dev-vps1 --key=~/devs/jan.pub --label=jangon server:dev:keys add dev-vps1 --key="ssh-ed25519 AAAA..." --label=petrgon server:dev:keys remove dev-vps1 --label=petr
--key accepts a file path or a full ssh-… AAAA… string. See the add a developer recipe.
server:dev:reload
Recreate a project's stack from your laptop so a changed .env is picked up. SSHes in and runs gon reload in the project dir (force-recreate + config:clear).
gon server:dev:reload demo
Working over Remote-SSH directly? Run gon reload inside /home/dev/projects/demo instead — it does the same thing. (Plain gon up does not recreate running containers, so a changed .env would stay invisible.)
server:dev:ssh-config
Print a ready-to-paste ~/.ssh/config block (alias <alias>-dev, user dev, keepalive) for VS Code Remote-SSH and plain ssh.
gon server:dev:ssh-config dev-vps1
server:dev:info
Print a "dev card" for a project: app / Vite / Mailpit URLs, SSH + VS Code targets, the DB tunnel command and credentials, and live container status.
gon server:dev:info demo
server:dev:remove
Tear down a project from the box. The box itself stays.
gon server:dev:remove demo # Drop containers, volumes + repo (with confirmation)gon server:dev:remove demo --keep-volumes # Preserve the DB volumegon server:dev:remove demo --keep-repo # Preserve the cloned repogon server:dev:remove demo --yes # Skip confirmation
Troubleshooting
| Symptom | Cause + fix |
|---|---|
gon: command not found over SSH | Re-run server:dev:setup — it creates the /usr/local/bin/gon symlink non-login SSH needs. |
| Browser shows the Traefik default cert | DNS not propagated yet (ACME), or stale Traefik state — cd /opt/traefik && sudo docker compose up -d. |
| 400 "Untrusted Host" | .env unreadable by PHP-FPM → Laravel fell back to production. add-project writes 0644 to fix it. |
Vite manifest not found / assets on 0.0.0.0:5173 | Vite dev server crashed or its asset origin is wrong. server:dev:setup raises inotify limits and the gon-core vite.config.mts points the origin/HMR at the vite. subdomain — make sure both are current. |
Related
- Remote dev environment — end-to-end public VPS recipe
- Add a developer
- LAN dev box (custom cert)
gon server— production counterpart