Fleet management control plane for Telemt MTProto proxy nodes
Quick Install Β β’Β Features Β β’Β Architecture Β β’Β Development Β β’Β Docker
| Feature | Description | |
|---|---|---|
| π | Fleet Dashboard | Real-time monitoring with metrics, health indicators, and alerts |
| π₯ | Managed Clients | Centralized client management with secret rotation and quotas |
| π€ | Agent System | Lightweight per-node agents with mTLS enrollment and gRPC streaming |
| ποΈ | Dual Storage | SQLite for dev/lightweight, PostgreSQL for production |
| π | Self-Update | Panel and agents update themselves from GitHub Releases |
| π¦ | Embedded UI | Single binary ships the React dashboard β no separate web server |
| π | TOTP 2FA | Optional two-factor authentication for operator accounts |
| π‘οΈ | RBAC | Viewer, Operator, and Admin roles with middleware enforcement |
sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/lost-coder/panvex/main/deploy/install.sh)"Interactive wizard: ports, storage, TLS, firewall, admin account β all configured step by step.
sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/lost-coder/panvex/main/deploy/install-agent.sh)"Requires a panel URL and enrollment token (create one in Settings β Enrollment Tokens).
π Non-interactive mode (CI / automation)
# Control Plane
PANVEX_ADMIN_PASS='<password>' \
PANVEX_HTTP_PORT=8080 \
PANVEX_GRPC_PORT=8443 \
sudo -E bash install.sh
# Agent
PANVEX_PANEL_URL='https://panel.example.com' \
PANVEX_ENROLLMENT_TOKEN='<token>' \
sudo -E bash install-agent.shRun bash install.sh --help for all environment variables.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π Browser β
β React Β· TanStack Router/Query β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β π‘ Control Plane (:8080) β
β HTTP API Β· WebSocket Β· Embedded UI β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β π gRPC Gateway (:8443) β
β mTLS Β· Bidirectional Stream Β· Jobs β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β π€ Agent (per Telemt node) β
β Heartbeats Β· Snapshots Β· Job Execution β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π Repository Layout
| Directory | Description |
|---|---|
cmd/control-plane |
Control plane server (HTTP + gRPC + embedded UI) |
cmd/agent |
Agent binary with bootstrap and enrollment |
internal/controlplane |
Auth, jobs, presence, storage, server logic |
internal/agent |
Telemt client, runtime, self-updater |
internal/gatewayrpc |
Generated gRPC stubs (protobuf) |
internal/security |
Enrollment, crypto, mTLS CA |
web |
React dashboard (Vite + TailwindCSS 4 + TanStack) |
db/migrations |
PostgreSQL and SQLite schema migrations |
proto |
Protobuf gateway contract |
deploy |
Install scripts, Docker Compose, nginx config |
π§ Tech Stack
| Layer | Technology |
|---|---|
| Backend | Go 1.26, chi/v5, pgx/v5, modernc.org/sqlite, gRPC |
| Frontend | React 19, Vite 8, TailwindCSS 4, TanStack Router + Query |
| UI Kit | Inlined under web/src/ui/ β Radix UI primitives + CVA |
| Database | PostgreSQL (primary) Β· SQLite (lightweight) |
| Deploy | Multi-stage Docker Β· systemd Β· nginx |
go build ./... # Build all
go test ./... # Run tests
go test -race ./... # Race detector
golangci-lint run ./... # Lint
sqlc generate # Regenerate DB codecd web
npm install # Install deps
npm run dev # Dev server (proxies API to :8080)
npm run build # Production build
npm run lint # ESLint1. Bootstrap admin:
go run ./cmd/control-plane bootstrap-admin \
-username admin \
-password '<strong-password>'2. Start control plane:
go run ./cmd/control-plane -http-addr :8080 -grpc-addr :84433. Start frontend dev server:
cd web && npm run devDashboard at
http://localhost:5173, API proxied to:8080
π¦ Single binary build
cd web && npm run build:embed
cd .. && go build -tags embeddedui -o panvex-control-plane ./cmd/control-planeEach compose file ships a bootstrap service under --profile bootstrap
that creates the first admin one-shot. It refuses to plant an account
on a non-empty store, so it's safe to re-run.
SQLite (lightweight)
# 1. First-run admin (run before bringing up the backend so the SQLite
# file isn't contended).
PANVEX_BOOTSTRAP_PASSWORD='<strong-password>' \
docker compose -f deploy/docker-compose.sqlite.yml \
--profile bootstrap run --rm bootstrap
# 2. Start the stack.
docker compose -f deploy/docker-compose.sqlite.yml up --build -dPostgreSQL (dev β default password, plaintext DB traffic)
# 1. Start Postgres + backend (creates schema on first boot).
docker compose -f deploy/docker-compose.postgres.yml up --build -d
# 2. First-run admin.
PANVEX_BOOTSTRAP_PASSWORD='<strong-password>' \
POSTGRES_PASSWORD='<db-password>' \
docker compose -f deploy/docker-compose.postgres.yml \
--profile bootstrap run --rm bootstrapPostgreSQL (production β TLS, no default credentials)
# 1. Bring up the stack. Required env vars are enforced via ${VAR:?...}.
POSTGRES_PASSWORD='<strong-db-password>' \
PANVEX_ENCRYPTION_KEY='<strong-encryption-key>' \
docker compose -f deploy/docker-compose.prod.yml up --build -d
# 2. First-run admin. Reuse the same PANVEX_ENCRYPTION_KEY so freshly
# minted secrets are readable to the running backend.
POSTGRES_PASSWORD='<strong-db-password>' \
PANVEX_ENCRYPTION_KEY='<strong-encryption-key>' \
PANVEX_BOOTSTRAP_PASSWORD='<strong-admin-password>' \
docker compose -f deploy/docker-compose.prod.yml \
--profile bootstrap run --rm bootstrapThe prod profile refuses to start without POSTGRES_PASSWORD and
PANVEX_ENCRYPTION_KEY, forces sslmode=require, sets resource
limits, JSON-log rotation (15 MiB Γ 10), PANVEX_ENV=production, and
binds publishers to loopback (terminate TLS at a reverse proxy β see
deploy/nginx/default.conf).
Override the admin username via
PANVEX_BOOTSTRAP_USERNAME(default:admin).Dashboard:
http://localhost:8080Β Β·Β gRPC:localhost:8443
- Create an enrollment token: Settings β Enrollment Tokens
- On each Telemt server:
sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/lost-coder/panvex/main/deploy/install-agent.sh)"Manual bootstrap (without installer)
./panvex-agent bootstrap \
-panel-url https://panel.example.com \
-enrollment-token '<token>' \
-state-file /var/lib/panvex-agent/agent-state.jsonCreate and manage Telemt clients centrally from the dashboard:
- π Generate secrets and
user_ad_tag - π Set limits: connections, unique IPs, quota, expiration
- π Assign by fleet group or individual nodes
- π Rotate secrets without recreating the client
- π Live deployment status, connection links, and usage per node
Two-Factor Authentication β TOTP 2FA is optional. Enable in Profile page.
Emergency TOTP reset via CLI:
./panvex-control-plane reset-user-totp \
-storage-driver sqlite \
-storage-dsn /var/lib/panvex/panvex.db \
-username adminThe control plane checks GitHub Releases for new versions automatically.
| Method | Command |
|---|---|
| Dashboard | Settings β Updates β Update Panel / Update Agent |
| CLI | ./panvex-control-plane self-update |
| Auto-update | Enable in Settings β Updates (disabled by default) |
Agents can be updated individually or in bulk. The panel sends an update job via gRPC β the agent downloads and installs the new binary automatically.
Built with β€οΈ for Telemt fleet operators