dev-serve — One-Command Dev Server Hosting
name: dev-serve
by brennerspear · published 2026-03-22
$ claw add gh:brennerspear/brennerspear-dev-serve---
name: dev-serve
description: Start and manage tmux-backed dev servers exposed through Caddy at wildcard subdomains.
---
# dev-serve — One-Command Dev Server Hosting
Start a dev server in a tmux session and expose it via Caddy at `<project>.YOUR_DOMAIN`. One command up, one command down.
Setup
1. **Install the script:**
```bash
cp scripts/dev-serve.sh ~/.local/bin/dev-serve
chmod +x ~/.local/bin/dev-serve
```
2. **Set your domain** (one of):
- Export `DEV_SERVE_DOMAIN` in your shell profile
- Or edit the `DOMAIN` variable in the script
3. **Requirements:**
- Caddy running with wildcard DNS + TLS (see [caddy](https://clawhub.com/skills/caddy) skill)
- `tmux`, `jq`, `curl`
- Caddy admin API on `localhost:2019`
CLI
dev-serve up <repo-path> [port] # Start dev server + add Caddy route
dev-serve down <name> # Stop dev server + remove Caddy route
dev-serve ls # List active dev servers
dev-serve restart <name> # Restart dev server (keep Caddy route)How It Works
1. Derives subdomain from the repo folder name (`~/projects/myapp` → `myapp.YOUR_DOMAIN`)
2. Detects the dev command from `package.json` `scripts.dev` (supports vite, next, nuxt, sveltekit)
3. Auto-patches Vite `allowedHosts` if a vite config file exists
4. Starts the dev server in a tmux session named `dev-<name>` with `--host 0.0.0.0 --port <port>`
5. Adds a Caddy route + dashboard link to the Caddyfile
6. Reloads Caddy via admin API (no sudo, no restart)
7. Verifies end-to-end: waits for the dev server to listen, then polls HTTPS until 2xx/3xx (up to 90s)
Examples
# Start with auto-assigned port (starts at 5200, skips used ports)
dev-serve up ~/projects/myapp
# → https://myapp.YOUR_DOMAIN
# Explicit port
dev-serve up ~/projects/myapp 5200
# Override dev command
DEV_CMD="bun dev" dev-serve up ~/projects/myapp 5300
# Stop and clean up
dev-serve down myapp
# List what's running
dev-serve lsConfiguration
| Variable | Default | Description |
|----------|---------|-------------|
| `DEV_SERVE_DOMAIN` | *(must be set)* | Your wildcard domain (e.g. `mini.example.com`) |
| `DEV_SERVE_STATE_DIR` | `~/.config/dev-serve` | Where state JSON is stored |
| `CADDYFILE` | `~/.config/caddy/Caddyfile` | Path to your Caddyfile |
| `CADDY_ADMIN` | `http://localhost:2019` | Caddy admin API address |
| `DEV_CMD` | *(auto-detected)* | Override the dev server command |
Port Convention
Vite `allowedHosts`
Vite blocks requests from unrecognized hostnames. `dev-serve up` automatically patches `vite.config.ts` (or `.js`/`.mts`/`.mjs`) to add the subdomain. If auto-patching fails, it prints the manual fix.
Architecture
Browser (Tailscale / LAN / etc.)
→ DNS: *.YOUR_DOMAIN → your server IP
→ Caddy (HTTPS with auto certs)
→ reverse_proxy localhost:<port>
→ Dev server (in tmux session)Companion Skills
Troubleshooting
**Dev server not starting:**
tmux attach -t dev-<name> # see what happened**Cert not provisioning (curl exit 35):**
Wait 30-60s for DNS-01 challenge. Check `tail -20 /var/log/caddy-error.log`.
**Caddy reload failed:**
caddy reload --config ~/.config/caddy/Caddyfile --address localhost:2019**403 from Vite:**
The subdomain wasn't added to `allowedHosts`. Add it manually to your `vite.config.ts`:
server: { allowedHosts: ['myapp.YOUR_DOMAIN'] }More tools from the same signal band
Order food/drinks (点餐) on an Android device paired as an OpenClaw node. Uses in-app menu and cart; add goods, view cart, submit order (demo, no real payment).
Sign plugins, rotate agent credentials without losing identity, and publicly attest to plugin behavior with verifiable claims and authenticated transfers.
The philosophical layer for AI agents. Maps behavior to Spinoza's 48 affects, calculates persistence scores, and generates geometric self-reports. Give your...