EdgeVPN web UI
August 3, 2026 · View on GitHub
React + TypeScript + Vite. Built from source and embedded into the Go
binary — the dist/ directory is never committed.
Requirements
Node 20.19 or newer (see .nvmrc). Vite 8 does not run on Node 18.
Development
Run the API in one terminal:
edgevpn -g > /tmp/ev.yaml
edgevpn api --config /tmp/ev.yaml --listen ':8080'
And the dev server in another:
cd api/react-ui
npm install
npm run dev
Vite prints http://localhost:3000/, but the router uses a hardcoded
/app basename, so open http://localhost:3000/app — the bare root
matches no route. /api and /debug are proxied to the backend.
Point at a different backend with EDGEVPN_URL=http://host:port npm run dev.
Checks
npm run typecheck # tsc --noEmit
npm test # vitest run
npm run build # typecheck + production build into dist/
Design system
All colour, type and spacing live in src/styles/tokens.css as --ev-*
custom properties. No component may contain a literal colour value.
The UI is dark-only by design; there is no light theme.
--ev-signal is the sole accent. The semantic colours (--ev-ok,
--ev-warn, --ev-crit) encode state and are never decorative.
Notes
The Go API has no json struct tags, so responses are PascalCase
(PeerID, RateIn, BlockChain). src/types/api.ts mirrors that
deliberately — do not "fix" the casing without changing the Go side,
which would break api/client and downstream consumers.