Bitrok is a self-hosted HTTP tunnel relay. The Go server owns tunnel registrations and SQLite persistence; the Go CLI keeps an authenticated WebSocket control channel open to forward HTTP traffic to a local service; the Next.js dashboard handles account sessions and CLI credentials.
Run the relay and dashboard in separate terminals:
# Terminal 1: relay
cp server/.env.example .env
set -a
. ./.env
set +a
go run ./server/cmd/bitrok-server
# Terminal 2: dashboard
cp web/.env.example web/.env.local
cd web
npm ci
npm run devThe scoped examples document the complete server environment and web environment. The local relay listens on http://localhost:8080, and the dashboard uses BITROK_SERVER_URL=http://localhost:8080.
Build and test everything with:
go test ./...
go test -race ./...
go vet ./...
cd web && npm run lint && npx tsc --noEmit && npm run build- Open the dashboard and sign in with GitHub.
- Claim the permanent username namespace in Settings.
- Run
bitrok login(or itsbitrok authalias) to open the browser authentication flow. - Start a tunnel with
bitrok myapp 3000.
The public host is deterministic: myapp-<username>.<BITROK_DOMAIN>. Usernames are immutable after claim because CLI credentials carry the namespace claim.
The relay is intentionally a single replica: SQLite and the in-memory WebSocket hub are not shared across processes. Put a reverse proxy in front of it with a wildcard certificate and wildcard DNS for *.bitrok.tech (or your configured domain), and route both HTTP traffic and the CLI control WebSocket upgrades to the same replica. Deploy the dashboard separately to Vercel with PostgreSQL.
See docs/server-architecture.md for protocol details, docs/production-deployment.md for the release checklist and recovery procedure, and docs/production-readiness-audit.md for the current CTO-level release assessment.
- Relay JWTs accept only HS256 and require
sub,exp, issuer, and audience. - Tunnel CRUD is scoped by authenticated user ID; platform hosts must end in the caller's immutable username.
- Proxy requests and responses are bounded at 10 MiB and hop-by-hop/header-injection vectors are stripped.
- SQLite is opened with WAL, foreign keys, busy timeout, and a
0600database file. - The CLI stores credentials and run-state files with
0600permissions and validates process ownership before stopping a tunnel. - Installers verify GoReleaser SHA-256 checksums before extraction.
See the repository license file before distributing the software.