Docker deployment
Run Prelude Collector under Docker and Docker Compose, including volumes, environment variables, networking, and update flow.
This page is the reference for running Prelude Collector under Docker and Docker Compose. It covers the image, the run command, volume mounts, environment variables, networking, and how to update.
For a guided first install, see Installation. For Podman specifics see Podman deployment. For every config field the collector accepts, see the Configuration reference.
Prerequisites
| Requirement | Version | Notes |
|---|---|---|
| Docker Engine | 24 or later | Compose v2 is included. |
| RAM | 2 GB minimum | 4 GB+ recommended once you add monitoring. |
| Network | Reachable to target devices | And to your registry on first pull. |
The collector image is published to the public registry
registry.arolo-solutions.com/prelude/prelude-collector. The
examples below use the :1.0 tag, the current stable release.
Pull the image
The registry is publicly pullable — no authentication required:
docker pull registry.arolo-solutions.com/prelude/prelude-collector:1.0.0
The image is self-contained: it embeds default OpenConfig YANG models, vendor MIBs for common platforms, and all static assets. Nothing extra needs to be downloaded after pull.
Quick start with Docker Compose
The fastest path is a single Compose file that runs the collector
together with PostgreSQL and NATS on the same host. Save this as
docker-compose.yml:
services:
collector:
image: registry.arolo-solutions.com/prelude/prelude-collector:1.0.0
container_name: prelude-collector
restart: unless-stopped
ports:
- "4030:4030"
environment:
COLLECTOR_DB_HOST: postgres
COLLECTOR_DB_PORT: "5432"
COLLECTOR_DB_USER: prelude
COLLECTOR_DB_NAME: collector
COLLECTOR_DB_PASSWORD: ${POSTGRES_PASSWORD:-change-me-sE43kapqD8df5fds}
COLLECTOR_APP_URL: http://localhost:4030
volumes:
- collector-data:/app/storage
depends_on:
postgres:
condition: service_healthy
nats:
condition: service_started
networks:
- prelude
postgres:
image: postgres:16-alpine
container_name: prelude-postgres
restart: unless-stopped
environment:
POSTGRES_USER: prelude
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change-me-sE43kapqD8df5fds}
POSTGRES_DB: collector
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U prelude -d collector"]
interval: 2s
timeout: 3s
retries: 15
networks:
- prelude
nats:
image: nats:2
container_name: prelude-nats
restart: unless-stopped
networks:
- prelude
volumes:
collector-data:
postgres-data:
networks:
prelude:
driver: bridge
Start the stack:
docker compose up -d
Port 4030 serves the REST API and web UI. To scrape device data
into Prometheus, attach the
Prometheus output backend and publish the
configured port (default 9090) on your collector container.
Configuration
The collector is configured entirely through COLLECTOR_* environment
variables. The compose file above sets the
database connection (COLLECTOR_DB_*) and the public URL
(COLLECTOR_APP_URL); everything else falls back to sensible defaults.
For the full list of variables and their defaults, see the
Configuration reference.
Standalone (without Compose)
If your PostgreSQL and NATS already exist elsewhere, run only the collector container:
docker run -d \
--name prelude-collector \
--restart unless-stopped \
-p 4030:4030 \
-e COLLECTOR_DB_HOST=your-postgres-host \
-e COLLECTOR_DB_PORT=5432 \
-e COLLECTOR_DB_USER=prelude \
-e COLLECTOR_DB_PASSWORD=change-me-sE43kapqD8df5fds \
-e COLLECTOR_DB_NAME=collector \
-v collector-data:/app/storage \
registry.arolo-solutions.com/prelude/prelude-collector:1.0.0
Point COLLECTOR_DB_HOST at your existing PostgreSQL - see the
Configuration reference for the full set of
COLLECTOR_DB_* variables. NATS is not set through environment
variables; configure it after first boot in the web UI under
Output Settings → NATS.
Volumes
The collector is configured through environment variables and writes
runtime state under /app/storage. The only volume it needs is the
storage volume; back it up.
| Mount | Purpose |
|---|---|
collector-data:/app/storage |
Runtime storage: YANG cache, MIBs, file output, the auto-generated TLS cert under certs/, and the at-rest encryption key under keys/. Named volume, back this up. |
postgres-data:/var/lib/postgresql/data |
PostgreSQL database files. Named volume, back this up. |
To bring your own TLS certificate, place it under the mounted storage
volume and point COLLECTOR_TLS_CERT / COLLECTOR_TLS_KEY at it — see
Advanced: bring your own TLS cert below.
Environment variables
The collector is configured entirely through COLLECTOR_* environment
variables. The compose file above sets the
database connection and the public URL; everything else falls back to
sensible defaults. For the full list of variables and their defaults,
see the Configuration reference.
When you want to template ports, image tags, or database credentials
through Compose, use an .env file next to docker-compose.yml and
reference variables with ${VAR} syntax. That keeps secrets out of
the Compose file itself.
Networking and ports
| Port | Service | Description |
|---|---|---|
4030 |
Collector | REST API and web UI (HTTPS if TLS is enabled) |
5432 |
PostgreSQL | Database |
4222 |
NATS | Client connections |
If you attach the Prometheus output backend,
it runs its own HTTP server on a configurable port (default 9090)
inside the collector container — publish that port separately when
you enable the backend.
Inside the Compose network, services reach each other by service
name: PostgreSQL is postgres, NATS is nats://nats:4222. Use those
names (in COLLECTOR_DB_HOST and the NATS Output Settings), not
localhost.
If you front the collector with a reverse proxy or load balancer,
terminate TLS there and forward to port 4030 over the internal
network. Keep any Prometheus output port on a private network — do
not expose it publicly.
TLS / HTTPS
HTTPS is always on. On first start, if you have not supplied a
certificate, gweb auto-generates a self-signed certificate under
storage/certs/ and serves with it. For production, terminate TLS
either at a reverse proxy or in the collector itself.
Advanced: bring your own TLS cert
To serve your own certificate in the collector:
-
Place the certificate and private key under the mounted storage volume so they persist, for example under
certs/:storage/certs/ ├── your-domain.pem └── your-domain.key -
Set both
COLLECTOR_TLS_CERTandCOLLECTOR_TLS_KEYon thecollectorservice, pointing at the in-container paths:services: collector: environment: COLLECTOR_TLS_CERT: /app/storage/certs/your-domain.pem COLLECTOR_TLS_KEY: /app/storage/certs/your-domain.key
The collector then serves HTTPS on port 4030 with your certificate.
You must set both variables — if either is unset, gweb falls back
to the auto-generated self-signed certificate under storage/certs/.
See the Configuration reference for the full set of
variables.
First-run setup
The schema is migrated automatically on startup (COLLECTOR_AUTO_MIGRATE
defaults to true), and on first boot the collector seeds a default
admin — admin / @rolo!Pass246 — which you sign in with on the web
UI and are forced to change. See
Installation / First-run setup.
To drive the REST API you then need a Bearer token. Issue one from the web UI — Settings → API Tokens → New Token — or from the command line inside the container:
# Generate an API token (printed once - copy it now)
docker compose exec collector ./prelude-collector user token \
-u admin -d api-token
Export the token for use with the API:
export TOKEN="<your-api-token>"
If you set COLLECTOR_AUTO_MIGRATE to false, apply pending
migrations explicitly instead — startup blocks until the schema is
current:
docker compose exec collector ./prelude-collector migrate up
Updating
Pull the new tag and recreate the changed containers. PostgreSQL and NATS keep running:
docker compose pull
docker compose up -d
Migrations run automatically on startup; with
COLLECTOR_AUTO_MIGRATE=false, run
docker compose exec collector ./prelude-collector migrate up
after recreating the container.
To pin a specific version, set the image tag in your Compose file or
through an .env variable, then pull and recreate:
docker compose pull collector
docker compose up -d collector
Migrations are idempotent.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Collector exits immediately | Database not reachable or not migrated | Check docker compose logs postgres, then run migrate up |
Connection refused on port 4030 |
Container port not published | Confirm -p 4030:4030 (or the ports mapping) and that COLLECTOR_PORT matches |
| NATS connection errors | Wrong NATS URL in Output Settings | In the web UI under Output Settings → NATS, use the service name: nats://nats:4222 |
| Metrics endpoint empty | Metrics disabled | Set COLLECTOR_METRICS_ENABLED to true |
| TLS errors | Wrong cert path | Verify COLLECTOR_TLS_CERT and COLLECTOR_TLS_KEY point at readable in-container paths under /app/storage |
Air-gapped environments
If the host has no outbound connectivity, transfer the image and license to it offline. See the Air-gapped install tutorial for the step-by-step, and Air-gap deployment for the operational reference.
See also
- Podman deployment - the same compose file, run under Podman with rootless and Quadlet notes.
- Configuration reference - every
COLLECTOR_*environment variable. - Air-gap deployment - operational shape of an air-gapped install.
- Air-gapped install tutorial - step-by-step walkthrough.