Appearance
Deploy with Docker Compose
The docker-compose.yml at the root of pantahub-base brings up the whole cluster on one machine: the API built from your checkout (with hot reload), the web UI, and every backing service — mongo replica set, the kafka pipeline, elasticsearch/fluentd, localstack S3, gc and cron jobs.
Development environment
This setup is for developing and testing the platform itself — real Pantavisor devices cannot connect to it. Devices require a TLS endpoint with a certificate they trust, and the compose stack serves plain HTTP on localhost (its nginx front uses a self-signed localhost certificate). To serve real hardware, use the Helm chart with a public domain; to populate a dev Hub with devices, simulate them with pantavisor-mocker.
Prerequisites
Docker with the compose plugin, and roughly 8 GB of RAM to spare.
Elasticsearch needs the kernel setting
vm.max_map_count=262144:shsudo sysctl -w vm.max_map_count=262144Two files/dirs the compose file expects to exist in the repo root:
shcd pantahub-base touch .env.local mkdir -p .data/elasticsearch.env.localis your local override ofenv.default(it can start empty);.data/is where all persistent state lands (mongo, elasticsearch, kafka, localstack).
Configure
env.default documents every knob and ships working development defaults — including dev-only JWT/JWE keys that must be replaced for anything public. Put your overrides in .env.local; it is layered on top. A useful minimum:
sh
# .env.local
# basic-auth secret for the cron/admin endpoints (user: saadmin)
PANTAHUB_SA_ADMIN_SECRET=changemeA note on the built-in demo accounts (admin, user1–user3, …): unless PANTAHUB_PRODUCTION is set, base runs in dev mode and enables all of them with their code defaults — including admin/admin. The PANTAHUB_DEMOACCOUNTS_PASSWORD_* variables only take effect in production mode (PANTAHUB_PRODUCTION=yes), where accounts without an explicit password are disabled. For anything reachable by others, set both.
Bring it up
sh
docker compose up -d
docker compose psFirst bring-up takes a few minutes and is deliberately self-ordering: mongo initializes replica set rs0, kafka creates its topics, kafka-connect uploads the Debezium connector configs once healthy, and phs waits for those before starting. A few restarts on the kafka side in the first minutes are normal — the entrypoints' wait-loops sort themselves out.
The base service builds from Dockerfile.development and bind-mounts your checkout, so the API hot-reloads when you edit the Go source — this compose file doubles as the development environment.
What's listening where
| Service | URL / port |
|---|---|
API (base) | http://localhost:12365 |
Web UI (www) | http://localhost:3000 |
| pvr repo service | http://localhost:12367 |
| nginx TLS front | https://localhost:12376 (http on 12375) |
| mongo primary | mongodb://localhost:27017 |
| kibana (optional) | http://localhost:5601 |
Open the UI at http://localhost:3000 and log in with a demo account — in dev mode the built-ins are enabled with their defaults (e.g. admin/admin). To point the pvr CLI at your cluster:
sh
pvr -b http://localhost:12365 loginTwo optional extras:
- Log UI — kibana sits behind a compose profile:
docker compose --profile logs up -d. - Mutual TLS — the nginx service on
:12376terminates TLS and forwards the client certificate to the API (Pantahub-TLS-Client-Certheader). This lets you exercise the TLS onboarding protocol with local clients (e.g.curl --cert) — not with real devices, which would reject the self-signed certificate.
Simulating devices
Since real hardware can't join a development Hub, pantavisor-mocker fills the gap: it simulates a Pantavisor device — registration with an auto-join token, device/user metadata sync, the full OTA update lifecycle (download, install, test, rollback), log upload, and a pvcontrol- compatible socket — without any hardware.
sh
# create a device token in your local Hub first (Device tokens → new)
pantavisor-mocker init --storage dev-device-1 \
--host localhost --port 12365 \
--token <auto-join token>
pantavisor-mocker start --storage dev-device-1 --auto--host/--port point the simulated device at your local API instead of the api.pantahub.com default; they land in the storage's pantahub.config (PH_CREDS_HOST / PH_CREDS_PORT), where you can also change them later.
--auto makes it accept updates on its own, so the simulated device walks trails like a healthy real one — useful for exercising deployments end to end. Each --storage directory is one device; run several to fake a small fleet. (Also available as a container: ghcr.io/pantavisor/pantavisor-mocker.)
The other compose files
| File | Purpose |
|---|---|
docker-compose.yml | The full stack described here — the default. |
docker-compose.development.yml | Slimmer dev variant without the kafka pipeline. |
docker-compose.vs.yml | Like development, tuned for IDE/devcontainer use. |
docker-compose.production.yml | Minimal single-node build (release Dockerfile, single mongo) — a starting point, not a hardened production setup. |
For a real deployment — multi-node, and reachable by real devices — use the Helm chart with a public domain instead of stretching compose.
Reset
All state lives in .data/ and the elastic-data volume:
sh
docker compose down -v
rm -rf .dataRecreate .data/elasticsearch before the next up. Wiping kafka state but not zookeeper's (or vice versa) can cause cluster-id mismatches — when in doubt, wipe both.