hyperhive — deploy options

services.hyperhive.deploy.allSwarmServices

Host the swarm’s shared services on this hive. The services that exist once per swarm rather than once per hive — the forge, the matrix homeserver, the SSO provider, the queue, the metrics and log stores — have their toggle asserted from this, so a swarm’s service host is declared in one place.

Every toggle it asserts is a services.hyperhive.deploy.* one, because “does THIS host run it” is a per-host decision — which is the same reason this option is a deploy.* one itself. See ./deploy.nix.

services.hyperhive.deploy.singleHostSwarm turns this on as part of the all-on-one-box mode. Set it directly to run the swarm’s services on a host that is not otherwise all-local — a dedicated services box with hives elsewhere is exactly that shape.

With it off, this hive is a client of those services: it still configures how to reach them, it just doesn’t run them.

Type: boolean

Default:

false

Example:

true

Declared by:

services.hyperhive.deploy.authelia.enable

Run the swarm’s authelia in a swarm-authelia container on this host. A swarm has one SSO provider, and this says it lives here.

With it off, this hive is a client: services.hyperhive.swarm.authelia.url still points at whoever runs it, and no container is created. That asymmetry is why the two live in different namespaces — every hive needs the client half, only one runs the server half.

Type: boolean

Default:

false

Example:

true

Declared by:

services.hyperhive.deploy.authelia.package

authelia package to run in the container. Defaults to nixpkgs’s; override to pin a specific upstream.

Type: package

Default:

pkgs.authelia

Declared by:

services.hyperhive.deploy.authelia.bridgePackage

swarm-authelia-bridge package — the only process allowed to write usersFile. Wired by default from this flake’s own package set (see flake.nix); override to run a different build.

Type: package

Default:

hyperhive.packages.${system}.swarm-authelia-bridge

Declared by:

services.hyperhive.deploy.authelia.hostClientSecretDir

Where the minted client secrets sit as seen from the host — <id>.secret holds a plaintext, <id>.digest the hash authelia itself reads.

Published for the same reason as hostUsersFile: the plaintext’s other reader lives in a different container, and containers that share this host’s network namespace still have separate filesystem roots. The host is the only place both trees are addressable, so the host is where a delivery step has to run.

⚠️ Nothing here exists until authelia’s first boot has run. A consumer must wait for it — it cannot be a bindMounts source, because nixos-container refuses to start when a bind source is missing, and that turns a fresh hive into a boot-order deadlock.

Type: string (read only)

Default:

"/var/lib/nixos-containers/swarm-authelia/var/lib/authelia-swarm/oidc-clients"

Declared by:

services.hyperhive.deploy.authelia.hostUsersFile

usersFile as seen from the host — the container’s root prefixed onto the path authelia sees.

Published for callers that only ever need to read the file (e.g. an operator diagnosing a bad entry). swarm-authelia-bridge itself never uses this path — it runs inside the container, as the file’s own owner, and writes the in-container path directly.

Type: string (read only)

Default:

"/var/lib/nixos-containers/swarm-authelia/var/lib/authelia-swarm/users.yml"

Declared by:

services.hyperhive.deploy.authelia.usersFile

Path (inside the container) of authelia’s file users database.

Written by swarm-authelia-bridge, not by hand: agents come and go continuously, so the subject set is dynamic and belongs to a program. swarm-controller cannot write this file itself — a different uid owns it — so the bridge is the only writer, running inside this same container as this file’s actual owner. When the user set is empty this module writes a single disabled placeholder subject, swarm.placeholder, so authelia starts and serves its login page; nobody can log in until swarmctl user add creates the first account.

Type: string

Default:

"/var/lib/authelia-swarm/users.yml"

Declared by:

services.hyperhive.deploy.bao.enable

Run the swarm’s secret store in a swarm-bao container on this host. A swarm has one store and it has to exist somewhere.

Where it runs is a separate question from that it runs: set this directly to put the store on a host of its own, and clients still reach it by name at services.hyperhive.swarm.bao.domain rather than at a local address.

With it off, this hive is a client: it still reads its own secrets from whoever runs the store, authenticating with its own client certificate. Every hive needs the client half; only one runs the server half, which is why the two live in different namespaces.

Type: boolean

Default:

false

Example:

true

Declared by:

services.hyperhive.deploy.bao.package

OpenBao package to run.

⚠️ An assertion below refuses 2.7.0 or newer, which drops the built-in PKCS11 seal.

Type: package

Default:

pkgs.openbao

Declared by:

services.hyperhive.deploy.bao.agentPkiMountPath

Mount path of the PKI engine agent client certificates are issued from. Its root is generated inside the store and its key never leaves it.

An option rather than a literal because the store host sets the mount up while swarm-controller, possibly on another host, issues through it: both have to spell it identically.

Type: string

Default:

"pki-agents"

Declared by:

services.hyperhive.deploy.bao.agentPkiRoleName

Role on services.hyperhive.deploy.bao.agentPkiMountPath agent client certificates are issued through. It issues client certificates named hive-agent-* and nothing else, and swarm-controller may call its issue endpoint and no other path on the mount.

Type: string

Default:

"swarm-agent"

Declared by:

services.hyperhive.deploy.bao.bootstrapTokenFile

Token used once per swarm to create the store’s cert-auth mount and the bao-granter policy and role, after which every granting unit logs in as the granter with a certificate instead.

Cert auth answers a role, so no client can authenticate until some role exists — and creating the granter’s is what this token is for. It has to come from outside that cycle, which is why an operator places it rather than the deployment minting it.

Produce it from the root token bao operator init printed, under the bao-bootstrap policy shipped at /etc/hyperhive/bao-bootstrap-policy.hcl, then delete it once swarm-bao-granter-role has run — docs/getting-started/setup.md has the commands. Setting this is what renders swarm-bao-granter-role; while it is null, a store whose granter is not set up has no way to set it up.

A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-bootstrap/grant.token"

Declared by:

services.hyperhive.deploy.bao.builderClientCertFile

Certificate the swarm builder presents to the store. Its subject must be services.hyperhive.deploy.bao.builderCommonName.

./glue-bao-tls.nix points it at the leaf it mints on the store’s host. On a builder host without the store, it is a file the operator copies from the store’s host. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/builder.pem"

Declared by:

services.hyperhive.deploy.bao.builderClientKeyFile

Private key for services.hyperhive.deploy.bao.builderClientCertFile. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/builder-key.pem"

Declared by:

services.hyperhive.deploy.bao.builderCommonName

Subject the store’s swarm-builder cert-auth role accepts: the identity the swarm builder presents from inside its container. Its grant is two paths, read only: swarm/services/builder/forge/token and its own queue client secret.

⚠️ Reserved as a hive name by ./swarm.nix, like its siblings.

Type: string

Default:

"swarm-builder"

Declared by:

services.hyperhive.deploy.bao.ciRunnerClientCertFile

Certificate the unit that fetches the CI runner’s registration token presents to the store. Its subject must be services.hyperhive.deploy.bao.ciRunnerCommonName.

./glue-bao-tls.nix points it at the leaf it mints on the store’s host. On a runner host without the store, it is a file the operator copies from the store’s host. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/ci-runner.pem"

Declared by:

services.hyperhive.deploy.bao.ciRunnerClientKeyFile

Private key for services.hyperhive.deploy.bao.ciRunnerClientCertFile. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/ci-runner-key.pem"

Declared by:

services.hyperhive.deploy.bao.ciRunnerCommonName

Subject the store’s swarm-ci-runner cert-auth role accepts: the identity swarm-bao-ci-runner, the unit that fetches the forge’s runner registration token for the CI runner, presents. Its grant is one path, swarm/services/ci-runner/registration-token, and read only.

⚠️ Reserved as a hive name by ./swarm.nix, like its siblings.

Type: string

Default:

"swarm-ci-runner"

Declared by:

services.hyperhive.deploy.bao.clientCaFile

Authority the store validates hive client certificates against.

This module declares no default, and the store’s own pki root can’t be this authority: a store that authenticated against a root it issues could not come up before the thing it issues.

On a hive that runs the store, a glue module supplies the CA it minted for exactly this, as a mkDefault. Point this at something else — an operator’s own CA — and yours wins.

null leaves client-certificate verification off, which is only appropriate where something else authenticates the connection.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/ca.pem"

Declared by:

services.hyperhive.deploy.bao.clientCertFile

Certificate a reader on this machine presents to the store.

The counterpart to services.hyperhive.deploy.bao.clientCaFile, which is the store’s side of the same handshake.

On a hive that runs the store, a glue module supplies the leaf it minted, as a mkDefault. Everywhere else this is the credential an operator places by hand — the one secret that cannot come out of the store, because it is what opens it.

A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao/client.pem"

Declared by:

services.hyperhive.deploy.bao.clientKeyFile

Private key for services.hyperhive.deploy.bao.clientCertFile. Both or neither — a certificate with no key authenticates nothing.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao/client-key.pem"

Declared by:

services.hyperhive.deploy.bao.controllerCommonName

Subject the store’s swarm-controller cert-auth role accepts. An interface, not a label: cert auth matches on the CN, so whatever mints the controller’s leaf has to spell it the same way.

Lives here because it is a property of the role, which this module writes — not a credential belonging to the controller. Nothing outside the store needs it except whatever issues that leaf.

⚠️ Reserved as a hive name. A hive’s own leaf carries its name as the CN, so a hive named after this subject would satisfy the role — ./swarm.nix feeds this value into the guard on services.hyperhive.swarm.hives to make that unrepresentable.

Type: string

Default:

"swarm-controller"

Example:

"swarm-controller.svc"

Declared by:

services.hyperhive.deploy.bao.extraListenAddresses

Addresses the store listens on in addition to loopback, each on services.hyperhive.swarm.bao.port.

Loopback is unconditional and not listed here: the host running the store is always one of its readers. Every other address depends on which network the reading hives share with this one, and that is a deployment fact no other module’s config can be read to infer — a swarm meshed over wireguard names its mesh address, one on a trusted LAN names that interface, and an all-local swarm names nothing at all.

Addresses only, no port: a store reachable on two ports is a misconfiguration rather than a topology.

Type: list of string

Default:

[ ]

Example:

[
  "10.100.0.1"
]

Declared by:

services.hyperhive.deploy.bao.forgePublisherClientCertFile

Certificate the forge’s host presents to the store, both to publish the swarm-controller’s forge token and to fetch the forge’s OIDC client secret. Its subject must be services.hyperhive.deploy.bao.forgePublisherCommonName.

./glue-bao-tls.nix points it at the leaf it mints on the store’s host. On a forge host without the store, it is a file the operator copies from the store’s host. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/forge-publisher.pem"

Declared by:

services.hyperhive.deploy.bao.forgePublisherClientKeyFile

Private key for services.hyperhive.deploy.bao.forgePublisherClientCertFile. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/forge-publisher-key.pem"

Declared by:

services.hyperhive.deploy.bao.forgePublisherCommonName

Subject the store’s swarm-forge-publisher cert-auth role accepts: the forge host’s one store identity, presented by swarm-bao-forge-publisher, which publishes the swarm-controller’s forge token, and by swarm-bao-forge-oidc, which fetches the forge’s OIDC client secret. Its grant is two paths: swarm/controller/swarm-controller/forge/token, write only, and swarm/services/<forge client id>/oidc/client, read only.

⚠️ Reserved as a hive name by ./swarm.nix, like its siblings.

Type: string

Default:

"swarm-forge-publisher"

Declared by:

services.hyperhive.deploy.bao.forwarderOidcClientCertFile

Certificate the unit that fetches the store’s own forwarder’s OIDC client secret presents to the store. Its subject must be services.hyperhive.deploy.bao.forwarderOidcCommonName.

⚠️ Not the hive’s own leaf, for the reason services.hyperhive.deploy.bao.queueAgentClientCertFile gives.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/forwarder-oidc.pem"

Declared by:

services.hyperhive.deploy.bao.forwarderOidcClientKeyFile

Private key for services.hyperhive.deploy.bao.forwarderOidcClientCertFile.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/forwarder-oidc-key.pem"

Declared by:

services.hyperhive.deploy.bao.forwarderOidcCommonName

Subject the store’s swarm-forwarder-oidc cert-auth role accepts — the identity swarm-bao-forwarder-oidc, the unit that fetches the store’s own forwarder’s OIDC client secret, presents. Its grant is one path, swarm/services/<forwarder client id>/oidc/client, and read only.

Its own identity rather than reuse of services.hyperhive.deploy.bao.otelOidcCommonName: the two read different clients’ secrets, and the store’s forwarder is not entitled to the swarm collector’s.

Type: string

Default:

"swarm-bao-forwarder-oidc"

Example:

"swarm-bao-forwarder-oidc.svc"

Declared by:

services.hyperhive.deploy.bao.grafanaOidcClientCertFile

Certificate the unit that fetches Grafana’s OIDC client secret presents to the store. Its subject must be services.hyperhive.deploy.bao.grafanaOidcCommonName.

⚠️ Not the hive’s own leaf, for the reason services.hyperhive.deploy.bao.queueAgentClientCertFile gives.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/grafana-oidc.pem"

Declared by:

services.hyperhive.deploy.bao.grafanaOidcClientKeyFile

Private key for services.hyperhive.deploy.bao.grafanaOidcClientCertFile.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/grafana-oidc-key.pem"

Declared by:

services.hyperhive.deploy.bao.grafanaOidcCommonName

Subject the store’s swarm-grafana-oidc cert-auth role accepts — the identity the unit that fetches Grafana’s OIDC client secret presents.

Its grant is one path, swarm/services/<grafana client id>/oidc/client, and read only. Not per hive, unlike the two prefixes above: an OIDC client is registered once per swarm, so the path names the service and never a hive.

⚠️ Same collision as its siblings, and the same answer: ./swarm.nix feeds this value into the guard on services.hyperhive.swarm.hives.

Type: string

Default:

"swarm-bao-grafana-oidc"

Example:

"swarm-bao-grafana-oidc.svc"

Declared by:

services.hyperhive.deploy.bao.granterClientCertFile

Certificate the store’s granting units present to the store. Its subject must be services.hyperhive.deploy.bao.granterCommonName.

Null, or a null services.hyperhive.deploy.bao.clientCaFile, means this deployment writes those grants some other way: no granting unit renders.

⚠️ Unlike every other leaf the store’s host mints, this one is never copied to another host; its only reader is that host.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/granter.pem"

Declared by:

services.hyperhive.deploy.bao.granterClientKeyFile

Private key for services.hyperhive.deploy.bao.granterClientCertFile.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/granter-key.pem"

Declared by:

services.hyperhive.deploy.bao.granterCommonName

Subject the store’s bao-granter cert-auth role accepts: the identity every swarm-bao-*-policy unit on the store’s host logs in as to write the swarm-* policies, cert-auth roles and pki roles.

⚠️ Root-equivalent: it may write a swarm-* policy with any content. Reserved as a hive name by ./swarm.nix, like its siblings.

Type: string

Default:

"bao-granter"

Declared by:

services.hyperhive.deploy.bao.hiveLeafCommonNamePrefix

Prefix of the subject the store’s per-hive gateway-leaf roles accept. The role for hive h accepts <prefix>-h and may only issue from <servicesPkiMountPath>/issue/<hiveLeafPkiRolePrefix>-h, which issues for h’s domain and *. that domain and nothing else.

Per hive for the reason services.hyperhive.deploy.bao.queueAgentCommonNamePrefix is: one subject for every hive could ask for any hive’s certificate.

⚠️ Reserved as a hive name by ./swarm.nix, per hive, like its siblings.

Type: string

Default:

"swarm-bao-hive-leaf"

Example:

"swarm-bao-hive-leaf.svc"

Declared by:

services.hyperhive.deploy.bao.hiveLeafPkiRolePrefix

Prefix of the per-hive roles on services.hyperhive.deploy.bao.servicesPkiMountPath that each hive’s gateway leaf is issued through: <prefix>-<hive>. The same name is that hive’s policy and cert-auth role. Must start with swarm-.

Type: string

Default:

"swarm-hive-leaf"

Declared by:

services.hyperhive.deploy.bao.logsAuthCommonName

Subject the store’s swarm-logs-auth cert-auth role accepts: the identity the log store’s agent auth responder presents to read agent queue credentials, swarm/agents/<agent>/queue and nothing else under an agent.

⚠️ Reserved as a hive name by ./swarm.nix, like its siblings.

Type: string

Default:

"swarm-logs-auth"

Declared by:

services.hyperhive.deploy.bao.matrixCtlCommonName

Subject the store’s matrix-ctl cert-auth role accepts — the identity the matrix container’s swarm-matrix-appservice-publish unit presents when it publishes the swarm appservice’s token.

A third identity rather than reuse of either sibling above, and the narrowest of the three: its grant is one path, that credential itself. The point of the whole arrangement is that the process holding the appservice token is not the hive, so handing it the hive’s own leaf — which reads every agent credential in the swarm and this hive’s own secrets — would give the separation away in one line.

⚠️ Same collision as its siblings, and the same answer: ./swarm.nix feeds this value into the guard on services.hyperhive.swarm.hives, so a hive named after it fails evaluation rather than silently receiving matrix-ctl’s grant.

Type: string

Default:

"swarm-matrix-ctl"

Example:

"swarm-matrix-ctl.svc"

Declared by:

services.hyperhive.deploy.bao.metricsPort

Loopback port the store serves its Prometheus metrics on, scraped by a collector on this same host.

Here and not beside services.hyperhive.swarm.bao.port because no client of the store ever needs it: reaching this port means being the local collector, which is a property of the host running the store.

⚠️ Cannot be services.hyperhive.swarm.bao.port + 1 — openbao derives every listener’s cluster address as its own port plus one, so the API listener already holds that number. The default sits one above it, and its own derived cluster address one above that.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default:

8202

Declared by:

services.hyperhive.deploy.bao.natsAuthCommonName

Subject the store’s swarm-nats-auth cert-auth role accepts: the identity the queue’s auth-callout responder presents to read agent queue credentials, swarm/agents/<agent>/queue and nothing else under an agent.

Its own principal rather than services.hyperhive.deploy.bao.natsCommonName: that one issues the queue’s TLS leaf from a host unit, this one reads secrets from inside the queue’s container.

⚠️ Reserved as a hive name by ./swarm.nix, like its siblings.

Type: string

Default:

"swarm-nats-auth"

Declared by:

services.hyperhive.deploy.bao.natsCommonName

Subject the store’s swarm-nats cert-auth role accepts: the identity the queue’s host presents to ask for the queue’s TLS leaf.

Its own principal rather than services.hyperhive.deploy.bao.servicesIssuerCommonName, whose role issues for every name in services.hyperhive.swarm.serviceDomains. This one may issue from services.hyperhive.deploy.bao.natsPkiRoleName alone, and that role only for services.hyperhive.swarm.nats.domain.

⚠️ Reserved as a hive name by ./swarm.nix, like its siblings.

Type: string

Default:

"swarm-nats"

Declared by:

services.hyperhive.deploy.bao.natsPkiRoleName

Role on services.hyperhive.deploy.bao.servicesPkiMountPath the queue’s TLS leaf is issued through. It allows exactly services.hyperhive.swarm.nats.domain: no subdomains, IPs or localhost.

Type: string

Default:

"swarm-nats"

Declared by:

services.hyperhive.deploy.bao.otelOidcClientCertFile

Certificate the unit that fetches the collector’s OIDC client secret presents to the store. Its subject must be services.hyperhive.deploy.bao.otelOidcCommonName.

⚠️ Not the hive’s own leaf, for the reason services.hyperhive.deploy.bao.queueAgentClientCertFile gives.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/otel-oidc.pem"

Declared by:

services.hyperhive.deploy.bao.otelOidcClientKeyFile

Private key for services.hyperhive.deploy.bao.otelOidcClientCertFile.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/otel-oidc-key.pem"

Declared by:

services.hyperhive.deploy.bao.otelOidcCommonName

Subject the store’s swarm-otel-oidc cert-auth role accepts — the identity the unit that fetches the collector’s OIDC client secret presents. Its grant is one path, swarm/services/<collector client id>/oidc/client, and read only.

Its own identity rather than reuse of services.hyperhive.deploy.bao.grafanaOidcCommonName: the two read different services’ client secrets, and a collector is not entitled to Grafana’s.

Type: string

Default:

"swarm-bao-otel-oidc"

Example:

"swarm-bao-otel-oidc.svc"

Declared by:

services.hyperhive.deploy.bao.queueAgentClientCertFile

Certificate the unit that fetches this hive’s queue client credential presents to the store. Its subject must be <queueAgentCommonNamePrefix>-<this hive's name>; cert auth matches on the CN and the role accepts nothing else.

⚠️ Not services.hyperhive.deploy.bao.clientCertFile. Pointing this at the hive’s own leaf would evaluate, deploy and log in — and hand a unit that reads one credential a certificate that reads every agent credential in the swarm and this hive’s own secrets.

No default here: ./glue-bao-tls.nix points it at the leaf it mints, wherever this host mints its own PKI. A deployment that reads a store on another host names it by hand, alongside the leaf itself.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/queue-agent.pem"

Declared by:

services.hyperhive.deploy.bao.queueAgentClientKeyFile

Private key for services.hyperhive.deploy.bao.queueAgentClientCertFile.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/queue-agent-key.pem"

Declared by:

services.hyperhive.deploy.bao.queueAgentCommonNamePrefix

Prefix of the subject the store’s per-hive queue-credential roles accept. The role for hive h accepts <prefix>-h and grants read on exactly swarm/hives/h/queue/agent — the client credential that hive’s agent containers authenticate to the swarm queue with.

A prefix rather than one subject because every hive runs its own reader and the path it reads carries that hive’s name. One subject for all of them would need a hives/* grant, which would let one hive read another hive’s queue credential.

⚠️ Reserved as a hive name by ./swarm.nix, per hive, for the reason its fixed-subject siblings are: cert auth trusts the CA and allowed_common_names is the whole narrowing, so a hive whose own leaf carried one of these spellings would receive that grant.

Type: string

Default:

"swarm-bao-queue-agent"

Example:

"swarm-bao-queue-agent.svc"

Declared by:

services.hyperhive.deploy.bao.reviewClassifierClientCertFile

Certificate the review classifier presents to the store. Its subject must be services.hyperhive.deploy.bao.reviewClassifierCommonName.

./glue-bao-tls.nix points it at the leaf it mints on the store’s host. On a classifier host without the store, it is a file the operator copies from the store’s host. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/review-classifier.pem"

Declared by:

services.hyperhive.deploy.bao.reviewClassifierClientKeyFile

Private key for services.hyperhive.deploy.bao.reviewClassifierClientCertFile. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/review-classifier-key.pem"

Declared by:

services.hyperhive.deploy.bao.reviewClassifierCommonName

Subject the store’s swarm-review-classifier cert-auth role accepts: the identity the review classifier presents from inside its container. Its grant is three paths, read only: swarm/services/review-classifier/anthropic-api-key, swarm/services/review-classifier/acp-provider and its own queue client secret.

⚠️ Reserved as a hive name by ./swarm.nix, like its siblings.

Type: string

Default:

"swarm-review-classifier"

Declared by:

services.hyperhive.deploy.bao.seal

How the store’s root key is sealed.

pkcs11 is the default and binds the key to the host’s TPM: the store unseals itself at boot, and an attacker with the disk does not get the secrets. shamir is openbao’s own default — unseal keys held by whoever ran bao operator init, entered by hand after every restart — and is the honest choice for a host with no TPM.

⚠️ This is a declaration, and nothing at evaluation time can check it: nix runs on the build machine and cannot see the target’s TPM. Saying pkcs11 on a host without one fails when the store’s container starts and its provisioning unit cannot create the token — later than activation, and on the container’s journal. That is deliberate — a store that comes up sealed by software while the config says hardware is weaker than it reads, and silently so.

Type: one of “pkcs11”, “shamir”

Default:

"pkcs11"

Example:

"shamir"

Declared by:

services.hyperhive.deploy.bao.secretPublisherCommonName

Subject the store’s secret-publisher cert-auth role accepts — the identity that copies authelia’s minted OIDC client secrets into the store so a hive that does not host authelia can read its own.

A second identity rather than reuse of services.hyperhive.deploy.bao.controllerCommonName: the controller’s grant includes rewriting every hive’s policy and login role, which is not something a unit whose whole job is copying one file should be able to do. This one’s grant is create/update under the hive prefix and nothing else.

⚠️ Same collision as its sibling above, and the same answer: ./swarm.nix feeds this value into the guard on services.hyperhive.swarm.hives, so a hive named after it fails evaluation rather than silently receiving the publisher’s grants.

Type: string

Default:

"swarm-secret-publisher"

Example:

"swarm-secret-publisher.svc"

Declared by:

services.hyperhive.deploy.bao.serverCaFile

Authority a reader on this machine validates the store’s certificate against.

Not services.hyperhive.deploy.bao.clientCaFile with the words rearranged: that one is the store choosing which readers to trust, this one is a reader choosing which store to trust. A deployment that self-signs both ends points them at the same file and reads that as confirmation they are interchangeable — they are not, and they diverge the moment either end gets a real CA.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao/ca.pem"

Declared by:

services.hyperhive.deploy.bao.serverCertFile

Certificate the store serves, covering services.hyperhive.swarm.bao.domain.

This module declares no default and deliberately does not know what could provide one — for the same reason services.hyperhive.deploy.bao.clientCaFile doesn’t: the store never reaches for an authority.

On a hive that runs the store, a glue module supplies a path as a mkDefault, so naming your own here wins over it.

A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao/server.pem"

Declared by:

services.hyperhive.deploy.bao.serverKeyFile

Private key for services.hyperhive.deploy.bao.serverCertFile. Both or neither — a certificate with no key is a listener that cannot start.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao/server-key.pem"

Declared by:

services.hyperhive.deploy.bao.servicesIssuerClientCertFile

Certificate swarm-services-cert logs in to the store with to ask for the swarm-services leaf the gateway serves. Its subject must be services.hyperhive.deploy.bao.servicesIssuerCommonName.

⚠️ Neither the reader’s services.hyperhive.deploy.bao.clientCertFile nor a hive’s own identity: this one’s policy permits update on pki/issue/swarm-services and nothing else, and it is the same on every gateway host, whether or not a hive runs there.

Required on every self-signed gateway host that fronts a swarm-service name (services.hyperhive.swarm.localServiceDomains not empty). Unset there, the host evaluates and swarm-services-cert fails, naming both options. A host fronting none only fetches the store’s root, presenting services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityCertFile, and needs no services-issuer pair.

./glue-bao-tls.nix points it at the leaf it mints on the store’s host. On any other gateway host that needs it, it is a file the operator copies from the store’s host. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/services-issuer.pem"

Declared by:

services.hyperhive.deploy.bao.servicesIssuerClientKeyFile

Private key for services.hyperhive.deploy.bao.servicesIssuerClientCertFile. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/services-issuer-key.pem"

Declared by:

services.hyperhive.deploy.bao.servicesIssuerCommonName

Subject the store’s services-issuer cert-auth role accepts — the identity a hive presents when it asks the pki mount for the swarm-services certificate its gateway serves.

A fourth identity rather than reuse of any sibling above, and the reasoning is theirs: this principal’s whole grant is one update on pki/issue/swarm-services, while the controller’s includes rewriting every hive’s policy and login role. Handing a certificate-renewal unit the controller’s leaf would give that separation away in one line.

⚠️ Same collision as its siblings, and the same answer: ./swarm.nix feeds this value into the guard on services.hyperhive.swarm.hives, so a hive named after it fails evaluation rather than silently receiving this grant.

Type: string

Default:

"swarm-services-issuer"

Example:

"swarm-services-issuer.svc"

Declared by:

services.hyperhive.deploy.bao.servicesPkiMountPath

Mount path of the PKI engine the swarm’s service certificates are issued from, and whose root is the anchor those certificates chain to.

An option rather than a literal because two files have to spell it identically: this module enables the mount, generates its root and writes the grant that points at <path>/issue/, while ./hive-tls.nix calls that endpoint. A mount path only one of them knows is a grant naming a location nobody issues from.

⚠️ NOT the store’s own client-auth PKI. That one is ./glue-bao-tls.nix’s self-signed CA on disk, and it stays outside the store permanently — bao cannot issue the credential a host opens bao with. Agent certificates come from services.hyperhive.deploy.bao.agentPkiMountPath.

Type: string

Default:

"pki"

Declared by:

services.hyperhive.deploy.bao.servicesPkiRoleName

Role on services.hyperhive.deploy.bao.servicesPkiMountPath that the swarm-services certificate is issued through, and the whole narrowing of that mount.

A role rather than a name-constrained sub-CA: the engine enforces the same “these names and no others” at issue time, from an allowed_domains read off services.hyperhive.swarm.serviceDomains, that an intermediate would encode in x509 nameConstraints — so a second authority in the chain would re-implement a check that has already happened.

Type: string

Default:

"swarm-services"

Declared by:

services.hyperhive.deploy.bao.tpmGid

Numeric group id owning /dev/tpmrm0, so the store’s seal can open it.

⚠️ A number, and it has a default, because a name cannot do this job. The store runs as a DynamicUser whose uid is allocated inside its container, and NixOS allocates tss — and every other system group — at activation, per machine. A group declared on the host and a group of the same name declared in the container therefore get different ids, and the device node carries the number. Pinning one value is what makes the two sides agree.

The default sits above the range NixOS auto-assigns system groups from (400–999) and above the normal-user range (1000–29999), and below the range systemd allocates DynamicUser ids from (61184–65519), so it collides with nothing those allocate. Override it if it collides with something this module cannot see.

Only read when services.hyperhive.deploy.bao.seal is pkcs11; a shamir store never touches the TPM.

Type: signed integer

Default:

31337

Example:

4242

Declared by:

services.hyperhive.deploy.bao.uiPort

Loopback port of the listener that serves the store’s browser UI. It requires no client certificate, so only the nginx in the store’s container proxies to it; see services.hyperhive.deploy.bao.uiProxyPort.

⚠️ openbao also binds this port + 1 as the listener’s cluster address, so neither may coincide with another port the store or its container binds. An assertion checks this.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default:

8204

Declared by:

services.hyperhive.deploy.bao.uiProxyPort

Loopback port of the nginx inside the store’s container that fronts services.hyperhive.deploy.bao.uiPort. The gateway’s services.hyperhive.swarm.bao.ui.domain vhost proxies here. This nginx forwards only /ui/ and /v1/, and refuses the unseal, seal, step-down, rekey and generate-root endpoints.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default:

8206

Declared by:

services.hyperhive.deploy.builder.enable

Run the swarm builder in a swarm-builder container on this host. It builds each agent config PR’s head on this host’s agent base, through this host’s nix daemon, and swarm-controller writes the result as a swarm-builder commit status on the PR.

Not derived from services.hyperhive.deploy.allSwarmServices: the builder evaluates and builds unreviewed config PRs on this host’s nix daemon, so running one is a decision of its own, as for the CI runner. It needs the builder’s store identity (services.hyperhive.deploy.bao.builderClientCertFile and builderClientKeyFile), which the store’s host mints.

Type: boolean

Default:

false

Example:

true

Declared by:

services.hyperhive.deploy.builder.package

The swarm builder daemon package.

Type: package

Default:

hyperhive.packages.${system}.swarm-builder

Declared by:

services.hyperhive.deploy.ci-runner.enable

Run the swarm’s Forgejo Actions runner in a swarm-ci-runner container on this host. It reaches the forge at services.hyperhive.swarm.forge.domain and registers with the token swarm-controller publishes to the secret store, so it needs neither the forge nor a hive on this host.

Not derived from services.hyperhive.deploy.allSwarmServices: a runner executes pull-request code, so running one is a decision of its own.

Type: boolean

Default:

false

Example:

true

Declared by:

services.hyperhive.deploy.ci-runner.package

gitea-actions-runner package.

Type: package

Default:

pkgs.gitea-actions-runner

Declared by:

services.hyperhive.deploy.ci-runner.concurrency

Maximum number of workflow jobs the runner executes in parallel. Each job gets its own temporary working directory; parallel jobs share the host’s nix store and the container’s cargo registry cache. Higher values trade memory and CPU headroom for throughput.

Type: positive integer, meaning >0

Default:

1

Example:

4

Declared by:

services.hyperhive.deploy.ci-runner.jobTimeout

Per-job wall-clock timeout the runner enforces (act_runner’s runner.timeout). A job that exceeds it is killed, so a hung build does not hold a runner slot indefinitely. Accepts a Go duration string (30m, 1h, 2h30m). Enforced by the runner process, so it only fires while that process is healthy.

Type: string

Default:

"1h"

Example:

"3h"

Declared by:

services.hyperhive.deploy.ci-runner.labels

Runner labels in <name>:<scheme> format. The host scheme runs commands directly in the container (no docker/podman). This repo’s workflows target the default with runs-on: hive-ci.

Type: list of string

Default:

[
  "hive-ci:host"
]

Example:

[
  "hive-ci:host"
  "nix:host"
]

Declared by:

services.hyperhive.deploy.ci-runner.name

Runner name as shown in the Forgejo admin panel.

Type: string

Default:

"swarm-ci-runner"

Declared by:

services.hyperhive.deploy.forgejo.enable

Run the swarm’s forge in a hive-forge container on this host. A swarm has one forge, so one host turns this on. It is the canonical store for the meta flake and every agent’s config repo, so the swarm needs it, but this host running it is a decision like any other shared service’s.

With it off, this hive is a client: it reaches the swarm’s forge at services.hyperhive.swarm.forge.domain, which the operator’s DNS must resolve to the forge’s host. No container is created, and an existing one’s state stays on disk under /var/lib/nixos-containers/hive-forge/.

services.hyperhive.deploy.allSwarmServices turns it on, and singleHostSwarm through that.

Type: boolean

Default:

false

Example:

true

Declared by:

services.hyperhive.deploy.forgejo.package

Forgejo package to run inside the container. Defaults to pkgs.forgejo (the latest release line) rather than the nixpkgs-module default of pkgs.forgejo-lts, because LTS lags far behind on schema and the DB easily ends up “newer than the binary” if the operator ever ran a non-LTS forgejo against the same state dir. Override to pkgs.forgejo-lts if you actively want the slower release train.

Type: package

Default:

pkgs.forgejo

Declared by:

services.hyperhive.deploy.forgejo.actionsFromSelf

Resolve a workflow’s uses: <org>/<action>@vN against this forge instead of data.forgejo.org, and add actions/checkout and actions/upload-artifact pull-mirrors to services.hyperhive.deploy.forgejo.mirrors so those steps have something to resolve to. A CI job’s actions then need no external DNS; only the mirrors’ re-sync does.

Defaults to on when this host also runs the swarm-controller, which seeds the mirrors (set by glue-forge-controller.nix), and off otherwise. Setting it true on a host without the controller leaves both actions unresolved: nothing seeds the mirrors, and the warning about unseeded mirrors fires.

Any other action a workflow names has to be mirrored here too. Set to false to resolve actions from data.forgejo.org and seed no mirror.

Type: boolean

Default:

false

Example:

false

Declared by:

services.hyperhive.deploy.forgejo.mirrors

General-purpose Forgejo pull-mirrors to auto-seed on the local forge. Each entry is created as a real Forgejo pull-mirror (it re-syncs from upstream out-of-band), not a one-off pushed clone — so a host-resolver blip leaves a stale mirror, never a hard failure on whatever reads it.

With services.hyperhive.deploy.forgejo.actionsFromSelf enabled (the default on a host that runs the swarm-controller), actions/checkout and actions/upload-artifact mirrors are appended to this list.

Type: list of (submodule)

Default:

[ ]

Example:

[ { upstream = "https://github.com/actions/checkout"; dest = "actions/checkout"; } ]

Declared by:

services.hyperhive.deploy.forgejo.mirrors.*.dest

Local <owner>/<repo> the pull-mirror is created at. The <owner> org is auto-created if missing. Keep mirror dests in their own orgs (e.g. actions/*) — separate from the hive-c0re-managed namespaces (config/shared/agents/core) so the seed never collides with core’s own provisioning.

Type: string

Example:

"actions/checkout"

Declared by:

services.hyperhive.deploy.forgejo.mirrors.*.upstream

Upstream clone URL to mirror from.

Type: string

Example:

"https://github.com/actions/checkout"

Declared by:

services.hyperhive.deploy.forgejo.openFirewall

Open httpPort + sshPort in the host firewall. Off by default (secure-by-default): agent containers reach the forge at forge.<domain> via the gateway (not directly), and the host reaches it on loopback — so the firewall opens only matter for access from outside the host. Flip to true when you want the operator’s browser or external git clients to hit the forge directly.

Type: boolean

Default:

false

Example:

true

Declared by:

services.hyperhive.deploy.forgejo.sso.clientSecretFile

Path inside the forge container holding the client secret’s plaintext.

A path, never a value: an OIDC client secret has two holders in two containers (authelia keeps a hash, this forge needs the plaintext), and a literal written here would be rendered into the world-readable nix store.

Set to /var/lib/forgejo-oidc/<client id>.secret wherever the forge runs. swarm-bao-forge-oidc writes the secret here from the swarm secret store, whichever path this names.

Null is refused at eval: a forge that boots with SSO half-configured presents as a login button that always fails, which is harder to diagnose than an eval error.

Type: null or string

Default:

null

Example:

"/var/lib/forgejo-oidc/forgejo.secret"

Declared by:

services.hyperhive.deploy.grafana.enable

Run the swarm’s metrics UI on this host.

Off by default and not derived from services.hyperhive.deploy.hive-controller.enable: a swarm has one Grafana, so running it is a decision about this host rather than about whether it runs a hive.

Type: boolean

Default:

false

Declared by:

services.hyperhive.deploy.grafana.package

Grafana package to run.

Type: package

Default:

pkgs.grafana

Declared by:

services.hyperhive.deploy.grafana.datasourceUrl

Where the provisioned datasource points. Defaults to the metrics store’s swarm name, served by the gateway of whichever host runs the store, so Grafana and the store need not share a host. The store’s query routes on that vhost take no credential, so the datasource sends none.

Type: string

Default:

"https://${services.hyperhive.swarm.victoriametrics.domain}"

Declared by:

services.hyperhive.deploy.grafana.logsDatasourceUrl

Where the provisioned logs datasource points. Defaults to the log store on this host, which binds loopback, so this default reaches it only where Grafana and the store share a host.

Provisioned unconditionally, like the metrics datasource — the store being off is a deployment choice rather than a reason to withhold the connection, and an operator whose logs live elsewhere sets this.

Type: string

Default:

"http://127.0.0.1:${toString services.hyperhive.swarm.victorialogs.port}"

Declared by:

services.hyperhive.deploy.grafana.plugins

Grafana plugins to install, as packages. Declarative rather than installed through the UI, which is the only shape that works here: plugin management is server-admin scoped, and on an SSO hive nobody holds that role — users.auto_assign_org_role grants an org role, and the built-in local admin that does hold server admin cannot log in because the login form is disabled whenever SSO is configured.

That is a deliberate pair of decisions rather than an oversight, and this option is the way through it: plugins live in the store and in git, so they survive a container rebuild and a state reset, and the container needs no runtime egress to grafana.com.

⚠️ This list is the ONLY way a plugin reaches this Grafana. Setting it at all disables upstream’s preinstall mechanism (see the declarativePlugins comment below), which is what normally fetches the Drilldown apps on first start — so a plugin left off this list is absent, not merely un-pinned.

Metrics Drilldown is on by default because this swarm’s Grafana exists to read VictoriaMetrics, and the queryless metrics browser is the part of that people actually reach for.

Its Logs / Traces / Profiles siblings are deliberately NOT here, and for two different reasons. Traces and Profiles front Tempo and Pyroscope, which this swarm does not run — a UI for a backend that does not answer. Logs Drilldown is the subtler one: this swarm does run a log store, so that argument does not apply to it, but the app is Loki-only and no configuration here changes that. Its volume views call /loki/api/v1/index/volume, which VictoriaLogs does not implement and answers “unsupported path requested”. Logs are browsed through Explore instead.

Type: list of package

Default:

[
  pkgs.grafanaPlugins.grafana-metricsdrilldown-app
  pkgs.grafanaPlugins.victoriametrics-logs-datasource
]

Example:

[ pkgs.grafanaPlugins.grafana-piechart-panel ]

Declared by:

services.hyperhive.deploy.grafana.socketDir

Directory holding the unix socket Grafana serves on, shared between the host (where nginx runs) and the container (where Grafana runs).

Fixed, not configurable: the directory’s mode is what keeps the socket private, so it has to be dedicated to this one socket, and a settable path could be pointed at a directory that carries something else.

⚠️ Grafana takes no TCP port at all, and that is the point. Every swarm service container shares the host’s network namespace, so a port is a swarm-wide resource that two modules can silently both claim — which is exactly what happened: Grafana defaulted to upstream’s 3000, so does the forge, and grafana.<swarm-domain> served the forge with no bind error and nothing in any log.

A socket has a path, and a path collision is a build-time conflict rather than a runtime coin toss.

Type: string (read only)

Default:

"/run/swarm-grafana"

Declared by:

services.hyperhive.deploy.hive-controller.enable

Run a hive on this host: the hive-c0re coordinator that owns every agent container here, its hive-priv helper, and the bridge, resolver and gateway the agents hang off.

Every hive turns this on. A host that only runs the swarm’s shared services (services.hyperhive.deploy.allSwarmServices) leaves it off.

Type: boolean

Default:

false

Example:

true

Declared by:

services.hyperhive.deploy.hive-controller.queue.agentCredentialDir

Host directory holding this hive’s agent queue credential: secret (the OIDC client secret, 0600) and client_id (the client that secret authenticates, 0644 — it is sent to the token endpoint on every connection and is not itself a secret).

Both files are written by swarm-bao-queue-agent.service, which also creates this directory. Named here because nothing else creates it: the parent /var/lib/hyperhive belongs to hive-c0re.service’s StateDirectory=, which re-applies its own mode on every start, and a second declaration of that path is the two-mechanisms-one-path trap ./hive-gateway/default.nix records — so this directory is the unit’s to make and the parent stays c0re’s.

Absent files mean this hive has no queue credential yet, which is what a swarm looks like before the publisher on the authelia host has run.

Type: absolute path

Default:

"/var/lib/hyperhive/queue-agent"

Declared by:

services.hyperhive.deploy.hive-controller.queue.agentNatsUrl

Where the swarm queue listens, as an agent container on this host reaches it.

Defaults to the queue’s name on every hive. The agent resolves it through the bridge: on the queue’s own host dnsmasq answers it with the bridge address, and elsewhere it forwards to the operator’s DNS, as for the store’s name. ⚠️ Never a loopback address: inside an agent’s network namespace 127.0.0.1 is the agent, not this host, and the queue’s certificate names no address anyway.

Null means this hive’s agents have not been given the queue’s address. Together with services.hyperhive.swarm.statusPublish.tokenEndpoint it is what decides whether the harness is handed queue coordinates at all.

Type: null or string

Default:

"tls://${swarm.nats.domain}:${swarm.nats.port}"

Example:

"tls://nats.example.com:4222"

Declared by:

services.hyperhive.deploy.hive-controller.statusPublish.natsUrl

Where the swarm queue listens, as seen from this hive.

Defaults to the queue’s name on every hive. The queue’s own host resolves it locally, and any other hive through the operator’s DNS. TLS only, and by name, since the queue’s certificate carries the name and no address.

A URL alone does not publish. This hive also needs its own store identity (services.hyperhive.deploy.bao.clientCertFile), under which hive-c0re reads its hive-<hiveName> client secret from the swarm’s secret store; swarm-secret-publish, on the host that runs authelia, puts it there. Without an identity, or with this set to null, this hive computes its own readiness as always and offers it to nobody, and the swarm controller reports it never_reported, which is the honest reading.

Type: null or string

Default:

"tls://${swarm.nats.domain}:${swarm.nats.port}"

Example:

"tls://nats.example.com:4222"

Declared by:

services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityCertFile

This hive’s own store identity. hive-tls-resign presents it to ask the secret store for the gateway leaf, and swarm-services-cert on a hive fronting no swarm name presents it for the handshake of the root fetch.

Its subject has to be <services.hyperhive.deploy.bao.hiveLeafCommonNamePrefix>-<hiveName>; that cert-auth role’s policy may issue from this hive’s gateway-leaf role and nothing else.

Every hive with a self-signed gateway needs it: without it both units fail, naming this option and services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityKeyFile. On the host that runs the store a glue module supplies the leaf as a mkDefault; on every other host an operator places it.

A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/hive-leaf.pem"

Declared by:

services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityKeyFile

Private key for services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityCertFile. Both or neither — a certificate with no key authenticates nothing.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/hive-leaf-key.pem"

Declared by:

services.hyperhive.deploy.hive-controller.tls.stateDir

Host directory holding the gateway leaf and trust bundle for the self-signed gateway mode: gateway.pem / gateway-key.pem (the leaf the store issues and nginx serves) and trust-bundle.pem (the anchor agents and federation peers trust, the store’s pki root).

Type: string

Default:

"/var/lib/hive-tls"

Declared by:

services.hyperhive.deploy.matrix.enable

Run the swarm’s matrix homeserver — matrix-tuwunel, in a hive-matrix container — on this host.

Set it directly to put the homeserver somewhere other than the host holding the rest of the swarm’s services.

Client-side settings stay in services.hyperhive.swarm.matrix.*, which every hive agrees on; this is only the decision to run it here.

Type: boolean

Default:

false

Declared by:

services.hyperhive.deploy.matrix.package

matrix-tuwunel package to run inside the container. Defaults to nixpkgs’s pkgs.matrix-tuwunel. Override to pin a specific upstream if you need an unreleased feature.

Type: package

Default:

pkgs.matrix-tuwunel

Declared by:

services.hyperhive.deploy.matrix.ctlBaoClientCertFile

Client certificate the matrix container’s swarm-matrix-ctl presents to the swarm’s secret store. Its subject must be services.hyperhive.deploy.bao.matrixCtlCommonName — cert auth matches on the CN, and the role accepts nothing else.

⚠️ Not the hive’s own leaf, and that is the whole deliverable of giving this container an identity: the hive’s certificate reads every agent credential in the swarm, while this one may write a single path. Pointing this at deploy.bao.clientCertFile would evaluate, deploy and work — and give away the separation in one line.

No default: a module that guessed would be holding the CA opinion ./swarm-bao.nix deliberately does not hold. ./glue-matrix-ctl-bao-identity.nix points it at the leaf ./glue-bao-tls.nix mints on a host that runs the store (services.hyperhive.deploy.bao.enable); on any other homeserver host it is a file the operator places. Never derived from services.hyperhive.deploy.bao.clientCertFile, which is the hive’s own reader.

The file and its key are bind-mounted into the container read-only. Co-located in the hive’s filesystem and therefore readable by hive root — accepted: the boundary this buys is identity (no hive process holds the appservice token), not physical isolation.

Type: null or string

Default:

null

Declared by:

services.hyperhive.deploy.matrix.ctlBaoClientKeyFile

Private key for services.hyperhive.deploy.matrix.ctlBaoClientCertFile. Both or neither — the unit does not exist unless each is set.

Type: null or string

Default:

null

Declared by:

services.hyperhive.deploy.matrix.ctlPackage

The swarm-matrix-ctl build run inside the matrix container.

⚠️ Named ctlPackage, not folded into package above: that one is the homeserver, and this is a hyperhive binary that happens to run beside it. Same split, and same reason, as services.hyperhive.deploy.nats.authPackage.

Type: package

Default:

hyperhive.packages.${system}.swarm-matrix-ctl

Declared by:

services.hyperhive.deploy.matrix.gui.package

Static web client dist served at gatewayHost’s vhost (chat.<swarm-domain> by default). Override to swap fluffychat for hydrogen-web, cinny, element-web, or an out-of-tree dist — any replacement is mounted at the sub-domain root with the upstream-default <base href "/">, no sub-path gymnastics needed.

Type: package

Default: pkgs.fluffychat-web with a postInstall patch that adds the three files flutter341.buildFlutterApplication skips.

Declared by:

services.hyperhive.deploy.matrix.maxRequestSize

Maximum size in bytes of a single matrix client request body. Default 20 MB matches the matrix-spec recommendation for media uploads + the upstream tuwunel default.

This is the only limit to set: the gateway’s own body cap is derived from it, with headroom, so the homeserver stays the one that rejects an oversized upload.

Type: positive integer, meaning >0

Default:

20000000

Declared by:

services.hyperhive.deploy.matrix.openFirewall

Open httpPort in the host firewall. Off by default (secure-by-default): hive-c0re and agent containers reach the homeserver at gatewayHost’s vhost (chat.<swarm-domain> by default) via the gateway, so the open port only matters for direct access to httpPort from outside the host. Flip to true when announcing the homeserver to other hives or when an external matrix client needs to reach the client-server API directly.

Note: federation (the matrix-spec well-known port 8448) is intentionally not opened here. tuwunel serves the federation API on the same httpPort as the client-server API by default; reaching it on 8448 requires either binding tuwunel to that port explicitly OR a reverse-proxy + .well-known/ matrix/server delegation, neither of which lives in this module. Add that proxy config alongside whatever serves your dashboard or forge on 443.

Type: boolean

Default:

false

Example:

true

Declared by:

services.hyperhive.deploy.matrix.sso.clientSecretFile

Path inside the matrix container holding the client secret’s plaintext.

A path, never a value: an OIDC client secret has two holders in two containers (authelia keeps a hash, this homeserver needs the plaintext), and a literal written here would be rendered into the world-readable nix store.

Set to /var/lib/tuwunel-oidc/<client id>.secret wherever the homeserver runs. swarm-bao-matrix-oidc writes the secret here from the swarm secret store, whichever path this names. The id this pairs with is swarm.matrix.sso.clientId, which is swarm-wide because authelia’s host registers it.

Type: null or string

Default:

null

Example:

"/var/lib/tuwunel-oidc/tuwunel.secret"

Declared by:

services.hyperhive.deploy.matrix.trustedServers

List of trusted matrix servers (homeservers whose signing keys this server will fetch identity-server-style). Empty by default — federation is enabled at the protocol level but no peer is trusted until listed here, so the homeserver is effectively closed until the operator declares hive peers explicitly.

Type: list of string

Default:

[ ]

Example:

[
  "matrix.org"
]

Declared by:

services.hyperhive.deploy.nats.enable

Run the swarm’s message queue in a swarm-nats container on this host. A swarm has one queue, so at most one host turns this on — but which host is its own decision, not necessarily the one running the swarm’s other shared services.

Off by default, and off means absent: no container is created and nothing else in the evaluated config changes.

Type: boolean

Default:

false

Declared by:

services.hyperhive.deploy.nats.authBaoClientCertFile

Client certificate the auth-callout responder presents to the swarm’s secret store to read the callout keys, its own OIDC client secret and agent queue credentials, and that swarm-bao-nats-callout-xkey presents to read the callout keys’ public halves. Its subject must be services.hyperhive.deploy.bao.natsAuthCommonName.

Required when deploy.nats.enable is set; unset fails at eval. ./glue-nats-auth-bao-identity.nix points it at the leaf ./glue-bao-tls.nix mints on a host that runs the store (services.hyperhive.deploy.bao.enable); on any other queue host it is a file the operator places. Never derived from services.hyperhive.deploy.bao.clientCertFile, which is the hive’s own reader. Set to a file that does not exist, swarm-nats-auth-secrets and swarm-bao-nats-callout-xkey fail, and the queue’s server does not start without the xkey.

A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/nats-auth.pem"

Declared by:

services.hyperhive.deploy.nats.authBaoClientKeyFile

Private key for services.hyperhive.deploy.nats.authBaoClientCertFile. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/nats-auth-key.pem"

Declared by:

services.hyperhive.deploy.nats.authPackage

The auth-callout responder package.

⚠️ Named authPackage, not package, on purpose: this module deliberately has no package option for the NATS server itself, because upstream’s services.nats resolves pkgs.nats-server on its own — see the note above options.services.hyperhive.swarm.nats. A bare package here would read as “the NATS package” and mean something else entirely.

Type: package

Default:

hyperhive.packages.${system}.swarm-nats-auth

Declared by:

services.hyperhive.deploy.nats.baoClientCertFile

Client certificate swarm-bao-nats-tls presents to the swarm’s secret store when it asks for the queue’s TLS leaf. Its subject must be services.hyperhive.deploy.bao.natsCommonName: cert auth matches on the CN, and that role’s policy may issue from pki/issue/swarm-nats and nothing else.

No default. ./glue-nats-bao-identity.nix points it at the leaf ./glue-bao-tls.nix mints on a host that runs the store (services.hyperhive.deploy.bao.enable). On a queue host without the store, it is a file the operator copies from the store’s host. Never derived from services.hyperhive.deploy.bao.clientCertFile, which is the hive’s own reader.

A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/nats.pem"

Declared by:

services.hyperhive.deploy.nats.baoClientKeyFile

Private key for services.hyperhive.deploy.nats.baoClientCertFile. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/nats-key.pem"

Declared by:

services.hyperhive.deploy.review-classifier.enable

Run the review classifier in a swarm-review-classifier container on this host. It answers the swarm UI’s review try-outs with claude on the Anthropic API key the operator writes to the secret store at secret/swarm/services/review-classifier/anthropic-api-key, field api_key.

On by default where services.hyperhive.deploy.allSwarmServices is set and this host has the classifier’s store identity (the pair services.hyperhive.deploy.bao.reviewClassifierClientCertFile and reviewClassifierClientKeyFile, minted on the store’s host). The key is never written for you: until the operator writes it the service runs and every run fails with “no API key…”.

Type: boolean

Default:

false

Example:

true

Declared by:

services.hyperhive.deploy.review-classifier.package

The review classifier daemon package.

Type: package

Default:

hyperhive.packages.${system}.swarm-review-classifier

Declared by:

services.hyperhive.deploy.singleHostSwarm

Run the whole swarm on this host. Turning this on asserts the toggles that an all-on-one-box deployment implies: the swarm’s shared services (services.hyperhive.deploy.allSwarmServices), the swarm controller (services.hyperhive.deploy.swarm-controller.enable), and the host’s /etc/hosts entries for the names this hive serves (services.hyperhive.gateway.localHostsEntry) — with no real DNS for those names, the operator is browsing them from the same box that answers for them.

Off by default, and that is the load-bearing part. A swarm’s services and its hives can live on different hosts, and a host has no way to tell which ones it is meant to be — so this is an operator saying “this is that box”, never something inferred. Turn it on for a dev box or a single-hive swarm and get a working deployment with no further configuration; leave it off and every swarm-level artifact is operator-provided.

Each toggle it asserts can still be set explicitly, which wins — so “all local except X” needs no new option.

Type: boolean

Default:

false

Example:

true

Declared by:

services.hyperhive.deploy.swarm-controller.enable

Run the swarm-controller daemon on this host.

Off by default and deliberately not derived from services.hyperhive.deploy.hive-controller.enable: a swarm has one controller, so running it is a decision about this host rather than about whether it runs a hive.

Also serves the swarm UI from this host. The UI is a view onto the controller’s state and reaches it over that daemon’s unix socket, so the host that runs the controller is the only host that can serve it.

Type: boolean

Default:

false

Declared by:

services.hyperhive.deploy.swarm-controller.package

swarm-controller package. Wired by default from this flake’s own package set (see flake.nix); override to run a different build.

Type: package

Default:

hyperhive.packages.${system}.swarm-controller

Declared by:

services.hyperhive.deploy.swarm-controller.authBridgeUrl

Where swarm-authelia-bridge (the only writer of authelia’s users database) answers. The default is the /bridge/ location on the authelia vhost, the same address from every host whether or not it runs swarm-authelia; the daemon appends /requests.

No new credential to configure: the bearer token presented to the bridge is minted from THIS daemon’s own existing queue OIDC identity — its endpoints stay in swarm.controller.queue, its secret is read from the swarm’s secret store — “one identity per principal” already covers it. null means no agent-identity support: CreateIdentity jobs fail with a clear “no auth bridge configured here” error rather than the daemon refusing to start, the same graceful-absence shape forge access has.

Type: null or string

Default:

"${services.hyperhive.swarm.authelia.url}/bridge"

Example:

"https://auth.example.com/bridge"

Declared by:

services.hyperhive.deploy.swarm-controller.baoClientCertFile

Certificate this daemon presents to the swarm’s secret store. Its subject has to match services.hyperhive.deploy.bao.controllerCommonName, which is what the store’s cert-auth role matches on.

Distinct from services.hyperhive.deploy.bao.clientCertFile on purpose, and not an oversight: that one is this host as a reader and carries the hive’s name, while the controller’s policy lets it create roles for every hive. One certificate serving both would hand that power to whatever else reads the store here.

Defaulted by glue-controller-bao-identity.nix where this deployment mints its own; elsewhere the leaf is issued out of band and named here.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-controller/bao-client.pem"

Declared by:

services.hyperhive.deploy.swarm-controller.baoClientKeyFile

Private key for services.hyperhive.deploy.swarm-controller.baoClientCertFile. Both or neither — a certificate with no key authenticates nothing.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-controller/bao-client-key.pem"

Declared by:

services.hyperhive.deploy.swarm-controller.configOrgAvatarPng

PNG uploaded once as the agent-configs Forgejo org’s avatar by the controller’s swarm-wide forge-objects pass (one-shot, marker-guarded — delete forge-config-org-avatar-set under the controller’s state directory to force a re-upload after changing this). Defaults (null) to the bundled agent-configs.png from services.hyperhive.c0re.assets. Set this to override just the org avatar without replacing the whole assets package.

Type: null or absolute path

Default:

null

Declared by:

services.hyperhive.deploy.swarm-controller.hiveClientCaFile

Authority whose leaves are hive client certificates, so that this daemon can create each hive’s cert-auth role. The store matches a presented certificate against the role’s copy of this, which is why the role carries the authority itself rather than a path to it.

The same material as services.hyperhive.deploy.bao.clientCaFile, named separately because that option is the store’s: it says which readers the store trusts, on the host that runs the store. A controller runs anywhere, so it names its own copy, and a glue module supplies this as a mkDefault where the two are co-located.

Public material — a certificate authority, not a key — so unlike every other credential here it leaks nothing. It stays a path anyway, because the file it names is the one the store already installs.

null leaves hive roles uncreated, which is the state a swarm is in before anyone has onboarded a hive.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/ca.pem"

Declared by:

services.hyperhive.deploy.swarm-controller.matrixHomeserverUrl

Client-server API base of the swarm’s homeserver. The controller creates each agent’s own matrix account there, with the swarm’s appservice token, and stores its token where the agent reads it. null leaves agents with no matrix account: the mint node fails, naming this option’s variable, and the agent is deployed anyway.

Also the swarm-wide default homeserver for PUT .../matrix-accounts/{account} requests that omit their own homeserver — see that route’s own doc comment (swarm-controller/src/matrix_account.rs) for why the field is optional in token mode and what omitting it currently resolves to. That route does not consult it yet.

Type: null or string

Default:

"https://${services.hyperhive.swarm.matrix.gatewayHost}"

Example:

"https://matrix.example.org"

Declared by:

services.hyperhive.deploy.swarm-controller.socketPath

Unix socket the daemon serves on, and the path the gateway’s nginx proxies to.

The directory is the access control here, not the socket mode: the socket itself is 0666 (nginx runs as another user, and connect(2) needs write), exactly as hive-c0re publishes the per-agent sockets. What keeps that safe is that the directory holds exactly one socket and is traverse-only (0751) for everyone else. Moving this path under a directory that carries anything else — /run/hyperhive, which holds the host admin socket, above all — exposes whatever else lives there to the same reachability.

Changing this therefore means re-checking what else lives in the new directory, not just the daemon.

Type: string (read only)

Default:

"/run/swarm-controller/controller.sock"

Declared by:

services.hyperhive.deploy.swarm-controller.swarmctlPackage

swarmctl package — the swarm operator’s CLI, installed on this host alongside the daemon and wrapped with the paths it needs.

A separate option from package rather than a second binary in the same derivation: the CLI runs as root and acts directly, the daemon runs unprivileged and serves a socket, and pinning one without the other is a thing an operator may legitimately want.

Type: package

Default:

hyperhive.packages.${system}.swarmctl

Declared by:

services.hyperhive.deploy.swarm-otel.enable

Run the swarm’s telemetry collector on this host.

A swarm has one of these, and it belongs wherever the shared services live rather than on every hive.

Named swarm-otel rather than otel because there are two collectors and the tier is the whole distinction: services.hyperhive.otel.enable is the hive-tier one, which every hive runs. A bare deploy.otel would not say which it meant. A hive that does not run the swarm collector still runs its own, and reaches this one by name at services.hyperhive.swarm.otel.domain.

Type: boolean

Default:

false

Declared by:

services.hyperhive.deploy.swarm-otel.clientSecretFile

Path, inside this collector’s container, to its OIDC client secret.

null means it holds no credential: it still exports, and the authenticated destinations refuse it. Set automatically where authelia is co-located; a deployment that places authelia elsewhere points this at a file it delivers itself.

⚠️ A path, never a value — a secret interpolated into a nix expression renders world-readable into the store.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-otel-oidc/swarm-collector.secret"

Declared by:

services.hyperhive.deploy.swarm-secret-publisher.enable

Publish the OIDC client secrets this host mints into the swarm’s secret store, so a hive that does not run authelia can read its own and its agents’ credentials and a swarm service or the controller can read its own — from wherever it runs, this host included.

Defaults to whether this host mints the OIDC secrets (set by glue-secret-publisher-authelia.nix), which is the only half of the question that is a property of this host.

⚠️ Deliberately not deploy.bao.enable. That asks whether the store stands here, and a publisher beside a remote store, holding a leaf issued out of band, is a deployment this exists to serve — defaulting on co-location would leave exactly that shape silently publishing nothing. Whether the wiring is complete is the client identity’s job (see baoClientCertFile), not this option’s.

Turning it off leaves every hive but this one without its agents’ credential, every hive unable to publish its status, the swarm controller unable to start, the swarm’s Grafana without any login at all, its collector pushing unauthenticated, the queue’s responder unable to start, the homeserver unable to start, and the forge’s login source without its secret. Each secret has exactly one route and this is the producer’s end of it, so the honest reason to set it false is a deployment delivering those secrets by some other mechanism it owns.

Type: boolean

Default:

false

Declared by:

services.hyperhive.deploy.swarm-secret-publisher.baoClientCertFile

Client certificate this publisher presents to the store. Its subject must be services.hyperhive.deploy.bao.secretPublisherCommonName — cert auth matches on the CN, and the role accepts nothing else.

No default: a module that guessed would be holding the CA opinion ./swarm-bao.nix deliberately does not hold. ./glue-secret-publisher-bao-identity.nix points it at the leaf ./glue-bao-tls.nix mints, where this host mints one.

Type: null or string

Default:

null

Declared by:

services.hyperhive.deploy.swarm-secret-publisher.baoClientKeyFile

Private key for services.hyperhive.deploy.swarm-secret-publisher.baoClientCertFile. Both or neither — the unit does not exist unless each is set.

Type: null or string

Default:

null

Declared by:

services.hyperhive.deploy.swarm-ui.package

Static build of the swarm UI. nginx serves this store path directly — there is no server-side component beyond the controller’s own API.

Wired by default from this flake’s own package set (see flake.nix), the same way deploy.swarm-controller.package is. There is deliberately no overlay in this project, so a pkgs.swarm-ui default here would name an attribute that does not exist on any real deployment.

Type: package

Default:

hyperhive.packages.${system}.swarm-ui

Declared by:

services.hyperhive.deploy.victorialogs.enable

Run the swarm’s log store on this host.

A hive that is not the service host is a client of this store, not a second one.

Type: boolean

Default:

false

Declared by:

services.hyperhive.deploy.victorialogs.package

VictoriaLogs package to run.

Type: package

Default:

pkgs.victorialogs

Declared by:

services.hyperhive.deploy.victorialogs.authBaoClientCertFile

Client certificate swarm-logs-auth presents to the swarm’s secret store to read agents’ queue secrets. Its subject must be services.hyperhive.deploy.bao.logsAuthCommonName.

Required when deploy.victorialogs.enable is set; unset fails at eval. ./glue-logs-auth-bao-identity.nix points it at the leaf ./glue-bao-tls.nix mints on a host that runs the store; on any other log-store host it is a file the operator places.

A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/logs-auth.pem"

Declared by:

services.hyperhive.deploy.victorialogs.authBaoClientKeyFile

Private key for services.hyperhive.deploy.victorialogs.authBaoClientCertFile. A path, never a value.

Type: null or string

Default:

null

Example:

"/var/lib/swarm-bao-pki/logs-auth-key.pem"

Declared by:

services.hyperhive.deploy.victorialogs.authBurst

Requests a client address may make above services.hyperhive.deploy.victorialogs.authRate before nginx answers 403, served without delay.

Type: positive integer, meaning >0

Default:

500

Declared by:

services.hyperhive.deploy.victorialogs.authPackage

The swarm-logs-auth package: the gateway’s auth_request responder that checks an agent’s swarm-agent.<agent>.<secret> bearer on /select/logsql/ against the secret store.

Type: package

Default:

hyperhive.packages.${system}.swarm-logs-auth

Declared by:

services.hyperhive.deploy.victorialogs.authRate

nginx limit_req rate, per client address, of /select/logsql/ requests carrying a swarm-agent. bearer, which nginx checks with swarm-logs-auth. Each such request that the responder has not granted within services.hyperhive.deploy.victorialogs.authVerdictTtl costs a secret store login and read, whether the bearer is right or not.

Counts every agent query, granted or not, and is keyed by client address, so every agent on one host shares one budget. The default covers about a hundred agents on a host cold-starting at once, each costing one store login and read for its first query. Requests over the rate and its burst are answered 403.

Type: string

Default:

"50r/s"

Example:

"30r/m"

Declared by:

services.hyperhive.deploy.victorialogs.authVerdictTtl

Seconds swarm-logs-auth grants an agent bearer it has verified again without reading the secret store. A denial is never remembered.

This is also how long a re-minted or deleted queue secret keeps working at the log store’s query route after its last successful check. 0 checks the store on every query.

Type: unsigned integer, meaning >=0

Default:

60

Declared by:

services.hyperhive.deploy.victorialogs.retentionPeriod

How long log data is kept.

Deliberately far shorter than the metrics store’s retention: logs are orders of magnitude larger per unit of time, and their value decays much faster. A log line answers “what happened during that incident”; a metric answers “is this worse than last quarter”.

Type: string

Default:

"30d"

Example:

"90d"

Declared by:

services.hyperhive.deploy.victoriametrics.enable

Run the swarm’s metrics store on this host.

Paired with services.hyperhive.deploy.grafana.enable: a store with no UI is unreadable and a UI with no store is empty, so there is no sensible deployment that takes one and not the other from that switch. Set either directly to run exactly one.

Type: boolean

Default:

false

Declared by:

services.hyperhive.deploy.victoriametrics.package

VictoriaMetrics package to run.

Type: package

Default:

pkgs.victoriametrics

Declared by:

services.hyperhive.deploy.victoriametrics.retentionPeriod

How long samples are kept.

Deliberately a high default rather than a required option: the two failure directions are not symmetric. Too long fills a disk, which is visible and recoverable by lowering this; too short destroys history, silently and permanently. So the safe default is generous and an operator lowers it once they have measured how fast this swarm actually accumulates data.

Type: string

Default:

"5y"

Example:

"90d"

Declared by:

services.hyperhive.deploy.wireguard.enable

Enable the WireGuard inter-hive mesh. When true, a wg-hive interface is brought up connecting to all swarm peers that declare a wireguardPublicKey. Requires privateKeyFile to be set.

Type: boolean

Default:

false

Declared by:

services.hyperhive.deploy.wireguard.address

IP address (with prefix) of this host on the WireGuard mesh. Use a /24 (or broader) prefix so the routing table covers all peer /32 routes. Example: "10.100.0.1/24" for a 256-host mesh.

Type: string

Default:

""

Example:

"10.100.0.1/24"

Declared by:

services.hyperhive.deploy.wireguard.listenPort

UDP port the local WireGuard interface listens on. Must be reachable from peer hosts when they initiate the tunnel. Default: 51820 (standard WireGuard port).

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default:

51820

Declared by:

services.hyperhive.deploy.wireguard.persistentKeepalive

Seconds between keepalive packets sent to each peer. Useful when this host (or a peer) is behind NAT — keeps the UDP hole open. Set to null to disable. Default: 25 seconds.

Type: null or signed integer

Default:

25

Example:

25

Declared by:

services.hyperhive.deploy.wireguard.privateKeyFile

Path to the host’s WireGuard private key file. The file must be readable by root and should have mode 0400. Generate with wg genkey > /etc/wireguard/hive.key. Required when deploy.wireguard.enable = true.

Type: null or absolute path

Default:

null

Example:

"/etc/wireguard/hive.key"

Declared by: