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/:443 directly and terminates TLS — no host nginx, no host MySQL (MySQL runs in the project stack).
  • One shared dev user instead of a per-project deploy user — every developer's key lands in ~dev/.ssh/authorized_keys and 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 reload over 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

  1. Check SSH connectivity
  2. Install Docker (via get.docker.com; pulls curl + ca-certificates first on minimal images)
  3. Install git, curl, unzip
  4. Raise inotify limits (fs.inotify.max_user_watches) so Vite's file watcher doesn't exhaust them on a multi-project box
  5. Create the shared dev user (docker group, your SSH key seeded) + /home/dev/projects
  6. Create the traefik-public Docker network
  7. Set up Traefik on :80/:443 (ACME or custom cert — see below)
  8. GHCR login (optional)
  9. Install gon-cli on the box (/usr/local/bin/gon symlink so non-login SSH finds it)
  10. Seed ~dev/.gon/config.json with 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 --cert and --key together (no --email). gon uploads the PEM to /opt/traefik/certs and 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

OptionDescription
--aliasShort name for the server (used as --host downstream)
--userSSH user for the first connection (default root, or the cloud image's sudo user)
--emailEmail for Let's Encrypt (public VPS). Prompted if neither --email nor --cert is given.
--cert / --keyPaths to a PEM cert + key for a LAN box (mutually exclusive with --email; both required together)
--ghcr-tokenClassic PAT with read:packages for pulling private images
--shared-patTeam GitHub PAT seeded into ~dev/.gon/config.json (so devs skip gon auth:login)
--dev-keysPath 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

OptionDescription
--hostDev server alias or IP (must be set up via server:dev:setup)
--repoGitHub repo slug owner/name
--branchBranch to check out (default: auto-detect, prefers main over master)
--domainPublic dev domain for the app
--vite-hostVite HMR subdomain (default vite.<domain>)
--mailpit-hostMailpit subdomain (default mail.<domain>)
--tlsacme or custom (default: inherit the server's cert_mode)
A DNS pre-flight checks that <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-vps1
gon server:dev:keys add dev-vps1 --key=~/devs/jan.pub --label=jan
gon server:dev:keys add dev-vps1 --key="ssh-ed25519 AAAA..." --label=petr
gon 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 volume
gon server:dev:remove demo --keep-repo # Preserve the cloned repo
gon server:dev:remove demo --yes # Skip confirmation

Troubleshooting

SymptomCause + fix
gon: command not found over SSHRe-run server:dev:setup — it creates the /usr/local/bin/gon symlink non-login SSH needs.
Browser shows the Traefik default certDNS 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:5173Vite 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