| 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
-
Install the script:
cp scripts/dev-serve.sh ~/.local/bin/dev-serve
chmod +x ~/.local/bin/dev-serve
-
Set your domain (one of):
- Export
DEV_SERVE_DOMAIN in your shell profile
- Or edit the
DOMAIN variable in the script
-
Requirements:
- Caddy running with wildcard DNS + TLS (see caddy skill)
tmux, jq, curl
- Caddy admin API on
localhost:2019
CLI
dev-serve up <repo-path> [port]
dev-serve down <name>
dev-serve ls
dev-serve restart <name>
How It Works
- Derives subdomain from the repo folder name (
~/projects/myapp → myapp.YOUR_DOMAIN)
- Detects the dev command from
package.json scripts.dev (supports vite, next, nuxt, sveltekit)
- Auto-patches Vite
allowedHosts if a vite config file exists
- Starts the dev server in a tmux session named
dev-<name> with --host 0.0.0.0 --port <port>
- Adds a Caddy route + dashboard link to the Caddyfile
- Reloads Caddy via admin API (no sudo, no restart)
- Verifies end-to-end: waits for the dev server to listen, then polls HTTPS until 2xx/3xx (up to 90s)
Examples
dev-serve up ~/projects/myapp
dev-serve up ~/projects/myapp 5200
DEV_CMD="bun dev" dev-serve up ~/projects/myapp 5300
dev-serve down myapp
dev-serve ls
Configuration
| 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
- Permanent services: 3100 range (managed in Caddyfile directly)
- Dev servers: 5200+ (managed by dev-serve, auto-assigned)
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
- caddy — Required. Sets up the Caddy reverse proxy with wildcard TLS.
Troubleshooting
Dev server not starting:
tmux attach -t dev-<name>
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'] }