Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration Reference

raptor reads a TOML file (default raptor.toml, override with serve --config <path>). Every key can be overridden by a RAPTOR_* environment variable; nested tables use a __ separator (e.g. RAPTOR_DDI__ANONYMOUS).

Top level

KeyTypeDefaultDescription
bindsocket addr0.0.0.0:8088address the HTTP server listens on
database_urlstring(required)sqlite://… or postgres://…; selects the backend
artifact_dirpath(required)root of the content-addressed artifact store
max_artifact_sizeinteger (bytes)1073741824 (1 GiB)maximum artifact upload size
urlstring(unset)external base URL for _links; derived from the Host header when unset
rollout_eval_interval_secsinteger5how often the background evaluator / auto-assign sweep runs
rollout_approval_enabledboolfalsegate new rollouts behind an operator approval (waiting_for_approval); reported as hawkBit’s rollout.approval.enabled
tenantstringDEFAULTtenant name this instance answers to on the DDI /{tenant}/... path segment (matched case-insensitively); any other segment gets 404

[quota] — per-entity growth caps

Mirrors hawkBit’s quotas (hawkbit.server.security.dos.*), with its default values. These bound unbounded growth — a chatty device appending action-status rows forever, a runaway upload loop — rather than rate-limiting requests. A breach is rejected with 429 Too Many Requests and hawkBit’s hawkbit.server.error.quota.tooManyEntries error code.

Set a key to 0 to disable that quota. This matches hawkBit, which treats any limit <= 0 as unlimited.

KeyDefaultCaps
max_status_entries_per_action1000status entries a device may report against one action
max_messages_per_action_status50messages a device may attach to one reported status
max_attribute_entries_per_target100attributes a device may report about itself
max_metadata_entries_per_target100metadata entries per target
max_metadata_entries_per_software_module100metadata entries per software module
max_metadata_entries_per_distribution_set100metadata entries per distribution set
max_artifacts_per_software_module50artifacts per software module
max_software_modules_per_distribution_set100modules per distribution set
max_rollout_groups_per_rollout500deployment groups per rollout
max_targets_per_rollout_group20000targets in any one rollout group

The two device-reported caps apply only to what a device sends over DDI. raptor’s own status entries — “rollout stopped”, “superseded by a new assignment” — are never capped, so a device that has exhausted its quota cannot stop the server recording why its action was cancelled.

max_status_entries_per_action also exempts feedback that closes an action (closed, canceled, a downloadonly action’s downloaded, and a cancel’s closed/rejected). Without that carve-out a device that spent its budget on progress reports could never file its terminal one, leaving the action active forever with no way to close it. hawkBit does the same, checking the count only for intermediate statuses.

Artifact size is capped separately by the top-level max_artifact_size.

[cleanup] — automatic action cleanup

Deletes closed actions past a retention window, along with their status history. action_status is the one table that otherwise grows without bound: quotas cap how much history any single action can accumulate, but nothing caps how many actions a fleet accumulates over years of updates.

Off by default — deleting deployment history is not something to start doing to an existing installation unasked.

KeyTypeDefaultDescription
enabledboolfalserun the sweep at all
action_expiry_daysinteger30how long a closed action is kept, from when it was last modified
action_statuseslist["finished", "error", "canceled"]which statuses may be deleted
interval_secsinteger3600how often the sweep runs
[cleanup]
enabled = true
action_expiry_days = 90

An active action is never eligible, whatever action_statuses says — a device can hold a listed status while its action is still live, and deleting it would strand that device holding an action id the server no longer knows. Deletion is batched — 1000 actions per statement, up to 10k per sweep — so a long-neglected instance drains over successive sweeps rather than in one enormous statement. (hawkBit bounds its own cleanup the same way, but at one batch per run.)

Rollout progress is unaffected. totalTargetsPerStatus is derived by counting actions, so deleting a finished one would walk a completed rollout’s targets back to scheduled — reporting as though the deployment had never run. raptor records each group’s purged outcomes before the rows go and folds them back in. (hawkBit has this drift and tolerates it; raptor does not.)

The two hawkBit tenant config keys are reported on /rest/v1/system/configs: action.cleanup.auto.expiry (milliseconds, -1 when disabled) and action.cleanup.auto.status.

[ddi] — device-facing API

KeyTypeDefaultDescription
anonymousboolfalsedisable all DDI auth (dev only)
gateway_tokenstring(unset)shared token; enables auto-registration
polling_intervalstring00:05:00poll sleep advertised to devices — see Polling time overrides below
confirmation_flowboolfalserequire confirmation before a deployment starts
auto_confirm_defaultboolfalsegive newly created targets autoConfirm, so confirmation_flow can’t strand confirmation-unaware clients
artifact_http_urlstring(unset)plain-HTTP base advertised in the DDI download-http links; unset means they reuse url
trusted_proxy_headerstring(unset)header to read the device address from behind a reverse proxy, e.g. x-forwarded-for; unset uses the socket peer

Polling time overrides

polling_interval accepts hawkBit’s pollingTime grammar (hawkBit 0.10, PR #2533): a default interval, optionally followed by ordered <RSQL> -> <interval> override rules, evaluated in written order — first match wins:

<default>[, <RSQL> -> <interval>]*

Each interval is HH:MM:SS, optionally with ~NN% jitter (NN 0–99): raptor draws fresh randomness on every poll response, matching hawkBit exactly, so a device’s advertised sleep can vary poll to poll rather than settling on one value.

[ddi]
polling_interval = "00:05:00, group==eu -> 00:00:30~10%, updateStatus!=in_sync -> 00:02:00"
  • The bare HH:MM:SS form (no rules) is unchanged from before this feature and behaves identically.
  • Override filters use raptor’s own FIQL dialect — the same one every q= parameter accepts — not hawkBit’s fuller Spring RSQL grammar. In particular, whitespace around the operator is not tolerated: write group==eu, not hawkBit’s own doc example group == 'eu'. A rule that fails to parse is rejected at startup (see below), not silently ignored.
  • raptor does not support hawkBit’s multi-day (d+:HH:mm:ss) or ISO-8601 (P2DT3H4M) interval forms — the incident-shaped use case this exists for (“poll this device faster while I’m watching it”) doesn’t need day-scale intervals.
  • A malformed polling_interval — bad grammar, or a rule referencing a filter field raptor doesn’t recognize — fails raptor serve at startup with an error, rather than surfacing on a device’s poll.
  • Known limitation, inherited from hawkBit: the Management API’s pollStatus.overdue is always computed from the default interval, even for a target currently matched by an override rule. hawkBit’s own release notes call this out as an accepted inaccuracy rather than a bug to fix.

[mgmt] — Management API / web console

KeyTypeDefaultDescription
usernamestring(required)admin username
password_hashstring(required)argon2id hash from raptor hash-password

Example

bind = "0.0.0.0:8088"
database_url = "postgres://raptor:raptor@localhost/raptor"
artifact_dir = "/var/lib/raptor/artifacts"
max_artifact_size = 2147483648            # 2 GiB
url = "https://raptor.example.com"
rollout_eval_interval_secs = 10
rollout_approval_enabled = false

[quota]
max_artifacts_per_software_module = 20
max_status_entries_per_action = 0          # unlimited

[ddi]
anonymous = false
gateway_token = "shared-registration-secret"
polling_interval = "00:05:00"
confirmation_flow = true

[mgmt]
username = "admin"
password_hash = "$argon2id$v=19$m=19456,t=2,p=1$..."

Environment overrides

RAPTOR_BIND=127.0.0.1:9090
RAPTOR_DATABASE_URL=sqlite://raptor.db?mode=rwc
RAPTOR_DDI__ANONYMOUS=true
RAPTOR_DDI__GATEWAY_TOKEN=super-secret
RAPTOR_MGMT__PASSWORD_HASH='$argon2id$...'

Environment values take precedence over the TOML file — the recommended way to inject secrets.