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

Daemon configuration settings

This page lists every setting of the daemon’s configuration file, /etc/piqueld/config.toml, with its type and default. It is generated from the daemon’s configuration types, like the file’s JSON Schema, which editors that use Taplo can check the file against. For how the daemon uses the file, with examples, see daemon configuration; NixOS sets these settings through the NixOS module.

Each table’s section is headed by the line that starts it in the file, such as [[dns.providers]]. Each setting is named by its full TOML path, where [] stands for each entry of an array of tables: dns.providers[].kind is the kind of each [[dns.providers]]. Settings ending in _file take the path of a credential file: a relative path resolves against $CREDENTIALS_DIRECTORY.

Top level

The daemon’s configuration file, /etc/piqueld/config.toml unless piqueld --config selects another. Every setting is optional unless it says otherwise. The daemon reads the file once at startup, so restart it to apply a change.

auth

Type: table. Optional.

The website’s origin and API token lifetimes.

build_history

Type: table. Optional.

How much build output is kept, and for how long.

checkouts

Type: table. Optional.

The disk space Git checkouts may take.

dns

Type: table. Optional.

DNS provider accounts, for certificates and routes’ DNS records.

docker

Type: table. Optional.

The Docker Engine piqueld manages.

images

Type: table. Optional.

Cleanup of the images this installation builds.

ingress

Type: table. Optional.

The managed HTTP gateway that serves applications’ routes.

previews

Type: table. Optional.

How many previews may exist, and the resources their services get.

reconciliation

Type: table. Optional.

How often piqueld checks for drift, and how long operations may take.

retention

Type: table. Optional.

How long finished operations, events and the audit trail are kept.

server

Type: table. Optional.

API listeners and state directories.

snapshots

Type: table. Optional.

Uploads of local worktrees by piquelctl preview deploy --local.

tailscale

Type: table. Optional.

The daemon’s own tailnet node, which serves the website over HTTPS.

telemetry

Type: table. Optional.

Export of the daemon’s traces, metrics and logs over OTLP.

[auth] table

The website’s origin and API token lifetimes.

auth.max_token_days

Type: integer of at least 1. Optional.

The longest lifetime, in days, of new API tokens. When unset, tokens may have any lifetime, including none. Existing tokens keep theirs.

auth.public_url

Type: string. Optional.

The website’s canonical origin, such as https://piqueld.example.com. Passkeys only work on this origin, and API mutations and WebSocket upgrades that send an Origin header must match it. It must be HTTPS, except http://localhost or a subdomain of it, such as http://dev.localhost, for development. When unset, it is https:// followed by ingress.private.dashboard_hostname if that is set, otherwise the tailnet node’s HTTPS URL if tailscale.enabled is set, otherwise http://localhost:7845.

[build_history] table

How much output of each build is kept, and for how long. Builds themselves are listed until their environment is deleted.

build_history.log_max_bytes

Type: integer from 1 to 67108864. Default: 4194304 (4 MiB).

The most output kept per build, in bytes.

build_history.log_retention_days

Type: integer from 1 to 3650. Default: 30.

Days a build’s output is kept after it finishes. The build stays listed, marked as expired.

[checkouts] table

The Git checkouts deployments read manifests from and build sources in, under <data_dir>/checkouts.

checkouts.max_bytes

Type: integer of at least 1. Default: 4294967296 (4 GiB).

The most bytes all checkouts, history and working tree, may take at once. A checkout waits until it fits beside the others, and one larger than this, or a local snapshot that would be, is refused.

[dns] table

DNS provider accounts. piqueld uses them to obtain DNS-01 certificates and, where manage_records is set, to maintain routes’ DNS records. It discovers each account’s zones through the provider’s API at startup and hourly; a hostname belongs to the provider with the longest matching zone.

dns.providers

Type: array of tables. Optional.

DNS provider accounts, one [[dns.providers]] table each, selected by kind.

[[dns.providers]] table

A DNS provider account, selected by kind, and whether piqueld manages routes’ DNS records in its zones.

dns.providers[].kind

Type: "cloudflare" or "ovh". Required.

  • "cloudflare": A Cloudflare account.
  • "ovh": An OVH account. The consumer key needs GET on /domain/zone, and POST and DELETE on /domain/zone/*; with manage_records, also GET and PUT on /domain/zone/*. piqueld also reads the server time from /auth/time, which needs no permission.

dns.providers[].api_token_file

Type: credential file. Required with kind = "cloudflare".

An API token scoped to Zone:Read and DNS:Edit on the zones piqueld may use.

dns.providers[].application_key_file

Type: credential file. Required with kind = "ovh".

The application key, which identifies the application.

dns.providers[].application_secret_file

Type: credential file. Required with kind = "ovh".

The application secret, which signs requests.

dns.providers[].consumer_key_file

Type: credential file. Required with kind = "ovh".

The consumer key, which authorizes the application on the account.

dns.providers[].endpoint

Type: "ovh-eu", "ovh-ca" or "ovh-us". Required with kind = "ovh".

The API region of the account: ovh-eu (Europe), ovh-ca (Canada) or ovh-us (United States).

dns.providers[].manage_records

Type: boolean. Default: false.

Create, update and delete routes’ A, AAAA and CNAME records in this provider’s zones. Off by default, so its zones stay manual.

[docker] table

The Docker Engine piqueld deploys to. The daemon serves its API while Docker is down, and starts deploying once Docker answers as a single-node Swarm manager.

docker.auto_initialize_swarm

Type: boolean. Default: true.

Initialize a Docker Engine that is not part of a Swarm as a single-node Swarm.

docker.socket

Type: string. Default: "/var/run/docker.sock".

The absolute path of the Docker Engine’s Unix socket.

[images] table

Cleanup of the images this installation builds. Cleanup keeps what every environment and preview runs or is deploying, and removes the rest. It never removes pulled images, images built by hand, or images other installations built on the same Docker Engine.

images.cleanup_interval_seconds

Type: integer from 1 to 86400. Default: 3600.

Seconds between cleanups. Cleanup also runs after each operation.

images.keep_deployments

Type: integer. Default: 3.

How many of each environment’s latest successful deployments also keep their images, so their releases can be deployed again.

[ingress] table

The managed Caddy gateway that serves applications’ routes.

ingress.acme

Type: table. Optional.

The ACME account DNS-01 certificates are ordered with.

ingress.enabled

Type: boolean. Default: false.

Run the managed gateway and serve public routes on ports 80 and 443, or through tunnel. Requires Docker Engine 28 or later. Disabling it removes the gateway but keeps routes and certificates.

ingress.private

Type: table. Optional.

The apps tailnet node, which serves private routes.

ingress.public_addresses

Type: array of strings. Optional.

This server’s public IPv4 and IPv6 addresses, such as ["203.0.113.10", "2001:db8::10"]. Public routes in zones whose DNS provider sets manage_records get A and AAAA records to them; without any, those records stay manual. Unused with tunnel.

ingress.tunnel

Type: table. Optional.

The Cloudflare Tunnel that replaces ports 80 and 443 for public routes.

ingress.webhook_hostname

Type: hostname. Optional.

A public hostname that serves GitHub push webhooks, and nothing else, for applications whose repository syncs with webhook, while ingress.enabled is set. No application may route it or its subdomains.

[ingress.acme] table

The certificate authority (CA) piqueld orders DNS-01 certificates from, for hostnames a public CA cannot reach over HTTP, such as those of private routes. The gateway obtains other certificates itself.

ingress.acme.directory

Type: string. Default: "https://acme-v02.api.letsencrypt.org/directory".

The ACME directory URL of the CA, which must be HTTPS. The default is Let’s Encrypt’s production CA.

ingress.acme.email

Type: string. Optional.

An email address the CA may send expiry and policy notices to. piqueld sends it only when it first registers its account with the CA.

[ingress.private] table

The apps tailnet node: a second tailnet node, a Tailscale container beside the gateway, that carries private routes’ traffic to the gateway’s private listener. It is separate from the daemon’s own node ([tailscale]), so it can have its own ACLs and tags.

ingress.private.auth_key_file

Type: credential file. Optional.

A Tailscale auth key for the apps node’s first login. Without one, the daemon logs the node’s login URL.

ingress.private.dashboard_hostname

Type: hostname. Optional.

A private hostname, such as piqueld.example.com, on which the gateway serves the website (dashboard and API) to the tailnet, with a DNS-01 certificate. An unset auth.public_url becomes its HTTPS origin. No application may route it or its subdomains. Requires ingress.enabled and ingress.private.enabled, and must differ from ingress.webhook_hostname.

ingress.private.enabled

Type: boolean. Default: false.

Run the apps node and serve private routes on the tailnet. While it is disabled, private routes report disabled. Private routes get DNS-01 certificates, so their zones need a [[dns.providers]] entry.

ingress.private.hostname

Type: string. Default: "piqueld-apps".

The apps node’s name, a single DNS label, which becomes <hostname>.<tailnet>.ts.net. It must differ from tailscale.hostname while both are enabled.

[ingress.tunnel] table

A Cloudflare Tunnel that serves public routes instead of the host’s ports 80 and 443, which are then closed. Each public hostname needs a proxied CNAME record to <tunnel-id>.cfargotunnel.com, and Cloudflare sees public traffic in plaintext.

ingress.tunnel.credentials_file

Type: credential file. Optional.

The tunnel’s credentials file, which cloudflared tunnel create writes. piqueld reads it only while the tunnel is enabled.

ingress.tunnel.enabled

Type: boolean. Default: false.

Serve public routes through the tunnel. Requires credentials_file.

[previews] table

How many previews may exist, and what each preview service may use.

Counts are checked when a preview is created, so lowering one below the current count keeps every existing preview running and only refuses new ones. Resource bounds apply when a preview’s manifest is rendered, so a preview picks up changed bounds on its next deployment. Environments are never bounded.

previews.default_cpu_millis

Type: integer from 1 to 1048576. Default: 500.

CPU limit, in millicores, of preview services that set none.

previews.default_memory_bytes

Type: integer from 1 to 9223372036854775807. Default: 536870912 (512 MiB).

Memory limit, in bytes, of preview services that set none.

previews.max_per_application

Type: integer. Default: 10.

Previews one application may have; creating more fails with preview_limit_reached. 0 refuses every new preview.

previews.max_replicas

Type: integer from 1 to 100. Default: 1.

Most replicas a preview service runs; manifests asking for more are capped with a warning.

previews.max_total

Type: integer. Default: 30.

Previews the whole installation may have; creating more fails with preview_limit_reached. 0 refuses every new preview.

[reconciliation] table

How often piqueld checks that Docker matches what is deployed, and how long a deployment may take.

reconciliation.convergence_timeout_seconds

Type: integer from 1 to 86400. Default: 120.

Seconds a deployment may wait without any service converging. It restarts each time a service converges, so each link of a startup dependency chain gets the full timeout.

reconciliation.prepare_timeout_seconds

Type: integer from 1 to 86400. Default: 300.

Seconds a deployment may take to prepare: fetching its manifest, resolving images and building them, including the time spent waiting for a build slot.

reconciliation.scan_interval_seconds

Type: integer from 1 to 86400. Default: 60.

Seconds between full scans for drift between Docker and what is deployed.

[retention] table

How long history is kept. 0 keeps it forever.

retention.audit_days

Type: integer. Default: 365.

Days the audit trail of API requests is kept; 0 keeps it forever.

retention.daemon_event_days

Type: integer. Default: 90.

Days events not tied to an application, such as those about shared infrastructure, are kept; 0 keeps them forever.

retention.event_days

Type: integer. Default: 90.

Days application events are kept; 0 keeps them forever. Deleting an application also removes its events.

retention.finished_operation_days

Type: integer. Default: 10.

Days finished operations are kept; 0 keeps them forever. Older ones are removed during reconciliation, except each environment’s latest operation and those in its deployment history or with job cleanup pending.

[server] table

Where the daemon keeps its state and serves its API. The Unix socket <runtime_dir>/piqueld.sock always serves the API; listen_mode adds TCP listeners, which also serve the dashboard.

server.allowed_hosts

Type: array of strings. Optional.

DNS hostnames, such as my-host.my-tailnet.ts.net, that TCP requests may use besides localhost and IP addresses. Write exact hostnames, without schemes, ports or wildcards, and only names trusted operators control.

server.data_dir

Type: string. Default: "/var/lib/piqueld".

The absolute path of the private directory holding the database, secrets.key and the rest of the daemon’s state. Missing directories are created with mode 0700.

server.listen_mode

Type: "off", "localhost", "tailscale" or "both". Default: "off".

The TCP addresses that serve the API and dashboard over plain HTTP, besides the Unix socket. Every request must still authenticate.

  • off: none, so only the Unix socket serves the API.
  • localhost: IPv4 and IPv6 loopback, 127.0.0.1 and ::1.
  • tailscale: the host’s Tailscale addresses, read with tailscale status at startup. If Tailscale isn’t running then, piqueld logs a warning and tries again only after a restart.
  • both: loopback and Tailscale addresses.

server.port

Type: integer from 1 to 65535. Default: 7845.

The port every TCP listener uses.

server.runtime_dir

Type: string. Default: "/run/piqueld".

The absolute path of the directory holding the Unix API socket, piqueld.sock. It must already exist, owned by the daemon’s user and with full access for it. Its group may read or traverse it, as with mode 0750, 0740 or 0710, only when it is the daemon’s effective group; otherwise use 0700. Group write and any access by others are refused. Every directory above it must be owned by root or the daemon’s user and writable only by its owner, unless sticky, like /tmp. It must differ from data_dir.

[snapshots] table

Uploads of local worktrees by piquelctl preview deploy --local.

snapshots.max_upload_bytes

Type: integer of at least 1. Default: 268435456 (256 MiB).

The largest Git bundle one upload may carry, in bytes. Larger uploads fail with snapshot_too_large.

[tailscale] table

The daemon’s own tailnet node, which serves the website (dashboard and API) over HTTPS with a tailnet certificate. The tailnet needs MagicDNS and HTTPS certificates enabled.

tailscale.auth_key_file

Type: credential file. Optional.

A Tailscale auth key for the node’s first login. Without one, the daemon logs a login URL and waits until the node is approved. Later starts reuse the node’s state in the data directory. piqueld passes the file to Tailscale on every start without reading it, so it must exist at every start; its key is only used for the first login. Not allowed with socket.

tailscale.enabled

Type: boolean. Default: false.

Join the tailnet as a node and serve the website on its https_port. The tailscale CLI must be on PATH, and so must tailscaled unless socket is set, since piqueld otherwise starts its own.

tailscale.hostname

Type: string. Default: "piqueld".

The node’s name, a single DNS label, which becomes <hostname>.<tailnet>.ts.net. Unused with socket, whose node already has a name.

tailscale.https_port

Type: integer from 1 to 65535. Default: 443.

The node port serving the website over HTTPS.

tailscale.socket

Type: string. Optional.

The absolute path of the socket of a logged-in tailscaled to share instead of starting one. piqueld then only adds https_port to that node’s Serve configuration, so several daemons can share one node, each on its own port. That tailscaled must run as the daemon’s user.

[telemetry] table

Export of the daemon’s traces, metrics and logs over OTLP/gRPC to a collector. Export is off until endpoint is set.

telemetry.containers

Type: boolean. Default: true.

Also export the output and resource usage of every container piqueld runs.

telemetry.endpoint

Type: string. Optional.

The OTLP/gRPC collector receiving every signal: https://host[:port], http://host[:port] or unix:///path for a Unix socket, without credentials or a path.

telemetry.headers_file

Type: credential file. Optional.

gRPC metadata sent with every export, such as a collector token, one name: value per line. Requires endpoint.

Value types

Credential file

Type: string.

The path of a file holding a secret, such as an API token. The daemon reads it once at startup, so restart it after changing the file. Surrounding whitespace, such as a trailing newline, is removed, and the file must be a non-empty regular file; symlinks to one are followed. tailscale.auth_key_file is the exception: Tailscale reads it instead. A relative path resolves against $CREDENTIALS_DIRECTORY, where systemd’s LoadCredential= puts credentials, and may not contain . or ... Errors and the settings shown by the dashboard name the file, never its contents.

Hostname

Type: string.

A fully qualified public DNS name, such as app.example.com, in lowercase ASCII, without a scheme, port, path or wildcard. Write Unicode domains in their IDNA (Punycode) form.