Skip to content

Configuration Reference

The controller and daemon both read a single YAML file at startup. Every key is mapped to a Java record with a compact constructor that applies defaults — if you omit a key, you get the default below. This page is the canonical reference. When in doubt, the records under java/cloud-controller/.../config/ and java/cloud-daemon/.../config/ are the ground truth.

What you’ll learn

  • Every controller and daemon configuration key, its type, default, and effect
  • Which keys are required for production and which are safe defaults
  • How environment variables override config for containerised deployments
  • The full Valkey key namespace the controller writes under

controller.yml

Lives at config/controller.yml under the install root (default /etc/prexorcloud/). Reload requires a controller restart — there is no signal-based hot reload.

uuid

FieldTypeDefaultRequired
uuidstringauto-generatedno

Stable controller identifier persisted across restarts. The first boot generates one and writes it back into controller.yml. In HA, every controller must have its own.

http

FieldTypeDefaultNotes
hoststring0.0.0.0Bind address. Use 127.0.0.1 if a reverse proxy on the same host is the only listener you want.
portint8080REST + SSE + dashboard.
cors.allowedOriginslist<string>["http://localhost:3000"]Origins allowed for browser clients. The dashboard origin must be listed when served from a different domain.

grpc

FieldTypeDefaultNotes
hoststring0.0.0.0Bind address for daemon connections.
portint9090gRPC port; mTLS terminated by the controller.

network

FieldTypeDefaultNotes
allowedSubnetslist<string>["0.0.0.0/0", "::/0"]CIDR allowlist for HTTP clients. Lock down for production. Empty list rejects all clients. Behind a reverse proxy, set http.trustedProxyCidrs so the real client IP is evaluated.

database (MongoDB)

FieldTypeDefaultRequired
uristringmongodb://localhost:27017yes
databasestringprexorcloudyes

PrexorCloud does not embed Mongo. The reference Compose stack runs Mongo as its own service. Replica-set URIs are supported and recommended for HA: mongodb://h1,h2,h3/prexorcloud?replicaSet=rs0&w=majority.

redis

FieldTypeDefaultRequired
uristringredis://localhost:6379yes (production)

Redis or Valkey, both speak the same protocol. The block is nullable in development; production refuses to start without it. rediss://... enables TLS to the coordination store.

All keys live under prexor:v1:. The version suffix is reserved for forward-compatibility — every read and write today uses this namespace. Full key map:

FamilyPrefixTTL / retention
Lease ownershipprexor:v1:lease:scheduler-configured lease TTL
Lease fencing tokensprexor:v1:lease-token:no TTL
Runtime snapshotsprexor:v1:node: / instance: / player:no TTL; removed on cleanup
Plugin tokensprexor:v1:plugintoken:15 minutes
JWT revocationprexor:v1:jwt:revoked:remaining JWT lifetime
Rate limitsprexor:v1:ratelimit:60 seconds
Console flood windowsprexor:v1:console:window:2× active flood window
Workload replay protectionprexor:v1:workloadseq:workload-token lifetime, 15 minutes
SSE ticketsprexor:v1:sse:ticket:30 seconds
SSE replay bufferprexor:v1:sse:sequence / replaybounded by replay trim
Module Redis storageprexor:v1:platform:<moduleId>:module-managed
Login attempts / locksprexor:v1:login:fail: / prexor:v1:login:lock:failure-window / lockout-duration
Password reset tokensprexor:v1:pwreset:30 minutes; deleted on consume

The same map is exposed live at GET /api/v1/system/redis/schema for operators with system.settings permission.

runtime

FieldTypeDefaultNotes
profilestringdevelopmentOne of development, production. Production requires Redis at startup; the wiring graph swaps in real coordination accessors for leases, JWT revocation, login lockouts, SSE replay, rate limits.

logging

FieldTypeDefaultNotes
levelstringINFOStandard SLF4J levels: ERROR, WARN, INFO, DEBUG, TRACE.
formatstringHUMANHUMAN for single-line text. JSON for line-delimited structured JSON via JsonLogEncoder.

scheduler

FieldTypeDefaultNotes
evaluationIntervalSecondsint15Tick frequency. New placement decisions and scaling evaluations happen each tick.
scalingCooldownSecondsint60Default per-group cooldown after a scale event. Per-group config can override.
nodeTimeoutSecondsint90Time without heartbeat before a node is marked offline.
auditRetentionDaysint90TTL on the audit_log collection. Mongo’s TTL index is keyed off createdAt.

heartbeat

FieldTypeDefaultNotes
intervalMslong30000Daemon → controller heartbeat cadence.
missedThresholdint3Consecutive misses before the node session is considered stale.

security

FieldTypeDefaultNotes
jwtSecretstringempty (auto-generated)Base64 ≥ 32 bytes. Auto-generated on first boot is fine for dev; production should set a managed value.
jwtExpirationMinutesint144024 hours.
initialAdminPasswordstringempty (auto-generated)First-boot bootstrap. Written to config/.initial-admin-password mode 0600 if generated.
jwtPreviousSecretslist<string>[]Old secrets accepted during rotation until tokens expire naturally.
rateLimiting.perIpPerMinuteint100Per-IP REST rate limit.
rateLimiting.perUserPerMinuteint300Per-user REST rate limit.
rateLimiting.failOpenOnRedisErrorboolfalseWhether to allow traffic when Valkey is unreachable. Default closed.
lockout.enabledbooltrueAccount lockout on failed logins.
lockout.maxAttemptsint5Failed logins before a lock.
lockout.windowSecondsint900Sliding failure window.
lockout.lockoutSecondsint900Lock duration after threshold.
passwordReset.enabledboolfalseOff by default. When false, /api/v1/auth/password-reset/* returns 404.
passwordReset.tokenTtlMinutesint30Single-use token lifetime.
passwordReset.resetUrlBasestringemptyDashboard base URL. Mailer appends /auth/reset-password?token=....
passwordReset.smtp.hoststringemptyWhen blank, LogMailer writes the reset link to the controller log instead of sending email.
passwordReset.smtp.portint587
passwordReset.smtp.startTlsbooltrue
passwordReset.smtp.implicitTlsboolfalse
passwordReset.smtp.usernamestringempty
passwordReset.smtp.passwordstringempty
passwordReset.smtp.fromstringemptyDefaults to no-reply@<host> when blank.

In production profile, lockout + password-reset state lives in Valkey and is shared across controllers.

crashes

FieldTypeDefaultNotes
ringBufferSizeint500Per-process in-memory ring of recent crashes for the dashboard.
crashLoopThresholdint3Crashes within window before a group is paused.
crashLoopWindowSecondsint300Sliding window.

metrics

FieldTypeDefaultNotes
enabledbooltrueExposes /metrics (Prometheus exposition). Gate access via reverse-proxy ACL.
retentionHoursint168In-process metric retention for the dashboard’s mini-graphs. Independent of your Prometheus retention.
collectionIntervalSecondsint30Internal sampling cadence for derived gauges.

modules

FieldTypeDefaultNotes
directorystringmodulesDirectory of installed module bundles.
dataDirectorystringmodules/dataPer-module on-disk storage root.
hotReloadbooltrueFile-watcher reload on bundle change.
signing.requiredboolprofile-defaultTrue in production, false in development. Production fails-closed when a signature cannot be verified.
signing.modeenumKEYEDKEYED for sidecar .sig; COSIGN_BUNDLE for cosign sign-blob --bundle.
signing.trustRootstringemptyPEM bundle. PUBLIC KEY blocks for raw-keyed; CERTIFICATE blocks for cosign-with-internal-CA.
signing.allowUnsignedDevelopmentbooltrueLets dev profile install unsigned bundles even if required=true is set elsewhere.
signing.rekor.policyenumDISABLEDREQUIRE_SET enforces offline Rekor SET verification — bundle must include a SignedEntryTimestamp.
signing.rekor.publicKeystringemptyPEM bundle for the Rekor public key. Required when policy = REQUIRE_SET.

See Cosign Pipeline for the verification flow.

maintenance

FieldTypeDefaultNotes
enabledboolfalseGlobal maintenance mode. Overrides per-group settings.
messagestringnetwork-defaultSurfaced to dashboards and proxy plugins.
bypasslist<string>[]Group names exempt from maintenance.

dashboard

FieldTypeDefaultNotes
enabledbooltrueServes the bundled dashboard.
pathstringdashboardOn-disk directory.

backup

FieldTypeDefaultNotes
directorystringbackupsBackup root, relative to install root.
retentionCountint10Manifests kept by the catalog. Older manifests are pruned by prexorctl backup prune.

networks

A list of seed NetworkComposition records applied on first boot. Subsequent edits via REST (/api/v1/networks) win — seeds with names that already exist are not re-applied. See Network Composition.

events

A list of seed EventChoreography cron-shaped scaling overlays. Same “first-boot only” semantics as networks.

daemon.yml

Lives at config/daemon.yml under the daemon install root.

nodeId

FieldTypeDefaultRequired
nodeIdstringnode-1yes

Cluster-unique. Setting two daemons to the same nodeId is undefined behaviour and likely to produce certificate-renewal contention.

controller

FieldTypeDefaultNotes
hoststring127.0.0.1Controller hostname / IP reachable from this daemon.
grpcPortint9090Controller gRPC port.

health

FieldTypeDefaultNotes
enabledbooltrueLocal readiness/liveness HTTP endpoint.
bindAddressstring127.0.0.1Bind locally; expose to systemd / k8s only.
portint9091

security

FieldTypeDefaultNotes
certificateDirstringconfig/securitymTLS material lives here. The bootstrap flow writes daemon.crt, daemon.key, ca.crt.
joinTokenstringemptyOne-time bootstrap credential. The first successful registration deletes this from config.

instances

FieldTypeDefaultNotes
directorystringinstancesPer-instance working directories.
shutdownTimeoutSecondsint30Time given to a graceful stop before forced kill.
killTimeoutSecondsint10Time after SIGTERM before SIGKILL.
logRingBufferLinesint500Console buffer per instance.

resources

FieldTypeDefaultNotes
maxMemoryMbint00 = auto-detect from cgroup / system. Set explicitly to cap how much the daemon will admit.

logging

Same shape as the controller: level, format.

labels

Free-form key-value pairs. Groups can target nodes via placement.nodeSelector. Common patterns:

labels:
region: "eu-west"
tier: "dedicated"
hardware: "ryzen-9950x"

reconnect

FieldTypeDefaultNotes
initialDelayMslong1000First retry delay after gRPC stream loss.
maxDelayMslong60000Cap for exponential backoff.
multiplierdouble2.0Backoff multiplier.

Environment variables

All values can be overridden by environment variables, mostly used inside the Compose stack.

Controller

VariablePurpose
PREXORCLOUD_HTTP_HOSTOverride http.host.
PREXORCLOUD_GRPC_HOSTOverride grpc.host.
PREXORCLOUD_DATABASE_URIMongo URI.
PREXORCLOUD_REDIS_URIValkey/Redis URI.
PREXORCLOUD_RUNTIME_PROFILEdevelopment or production.
PREXORCLOUD_SECURITY_JWT_SECRETJWT signing secret.

Daemon

VariablePurpose
PREXORCLOUD_CONTROLLER_HOSTController host.
PREXORCLOUD_CONTROLLER_GRPC_PORTController gRPC port.
PREXORCLOUD_NODE_IDOverride nodeId.
PREXORCLOUD_SECURITY_JOIN_TOKENOne-shot join token; cleared after first registration.

Per-instance (injected by the daemon)

These are read by the bundled prexor-plugin inside each MC server JVM:

VariablePurpose
CLOUD_INSTANCE_IDInstance identifier
CLOUD_GROUPGroup name
CLOUD_PORTAssigned port
CLOUD_NODE_IDHost node identifier
CLOUD_CONTROLLER_URLController REST API URL

CLI

VariablePurpose
PREXOR_CONTROLLERDefault --controller URL.
PREXOR_TOKENDefault auth token.
PREXOR_OUTPUT=jsonJSON output across all commands.

Roles (roles.yml)

The controller seeds three roles on first boot from defaults/roles.yml:

  • ADMIN["*"]. All permissions.
  • OPERATOR — node / group / instance / template / module / catalog / audit / metrics view + mutate.
  • VIEWER — read-only across the same surfaces.

Custom roles edit-able via prexorctl role or directly in the roles Mongo collection.

Validation

ConfigValidator runs at startup and refuses to boot in production when:

  • redis is unset.
  • modules.signing.required=true but trustRoot is empty.
  • modules.signing.rekor.policy=REQUIRE_SET but rekor.publicKey is empty or mode != COSIGN_BUNDLE.

A misconfigured production controller logs the full validation report and exits non-zero before binding ports.

Next up