Skip to content
🐋Cetacean

Configuration

Cetacean reads settings from command-line flags, environment variables, and a TOML config file. When a setting appears in more than one place, the precedence order is flag, environment variable, config file, built-in default.

Sensitive settings accept a _FILE suffix on their environment variable to read the value from a file at startup, which is how a Docker secret reaches the process. The _FILE variant ranks below the direct environment variable.

The acl.*, mcp.*, oauth.*, sizing.*, and tracing.* settings have no command-line flags. Set them through the environment or the config file.

A setting this page doesn’t list isn’t ignored: a config file carrying a key the schema doesn’t know, or an environment carrying a CETACEAN_* variable no setting reads, refuses startup and names it. So does a value a setting can’t parse: an on-off setting takes true, false, 1 or 0.

General settings

server.listen_addr

Address and port the HTTP server binds to. Use 0.0.0.0:9000 to listen on all interfaces, or 127.0.0.1:9000 to restrict to localhost.

  • flag-listen
  • envCETACEAN_LISTEN_ADDR
  • default:9000
server.base_path

URL prefix for serving Cetacean under a sub-path behind a reverse proxy, for example /cetacean. Leave unset when Cetacean owns the root path.

  • flag-base-path
  • envCETACEAN_BASE_PATH
server.public_url

Canonical external URL clients reach Cetacean at, for example https://cetacean.example.com. Origin only—set the path prefix with server.base_path, which is used for both inbound and outbound paths. Supplies the default for oauth.issuer and auth.oidc.redirect_url, and makes Atom and JSON Feed links independent of the X-Forwarded-* headers a client can set. Set it behind a reverse proxy.

  • flag-public-url
  • envCETACEAN_PUBLIC_URL
docker.host

Docker Engine API endpoint: a Unix socket (unix:///path) or TCP (tcp://host:port). Over TCP, set docker.tls.ca and a client certificate; without them nothing is encrypted, and anyone who can reach the port controls the engine. SSH (ssh://) isn’t supported and refuses startup. To reach an engine over SSH, forward its socket with ssh -L and point this at the forwarded end.

  • flag-docker-host
  • envCETACEAN_DOCKER_HOST
  • defaultunix:///var/run/docker.sock
docker.tls.ca

Path to a PEM-encoded CA bundle the engine’s certificate must be signed by, replacing the system roots. Setting any docker.tls.* setting connects over TLS, which requires a tcp:// docker.host.

  • flag-docker-tls-ca
  • envCETACEAN_DOCKER_TLS_CA
docker.tls.cert

Path to the PEM-encoded client certificate presented to an engine started with --tlsverify. Set it together with docker.tls.key or not at all.

  • flag-docker-tls-cert
  • envCETACEAN_DOCKER_TLS_CERT
docker.tls.key

Path to the PEM-encoded private key matching docker.tls.cert.

  • flag-docker-tls-key
  • envCETACEAN_DOCKER_TLS_KEY
prometheus.url

Base URL of a Prometheus server, for example http://prometheus:9090. When set, Cetacean proxies metric queries and enables usage charts, sizing recommendations, and the metrics stream. When unset, every metric-dependent feature is disabled.

  • flag-prometheus-url
  • envCETACEAN_PROMETHEUS_URL
tracing.endpoint

Base URL of an OpenTelemetry collector accepting OTLP over HTTP, for example http://collector:4318. Only MCP requests and tool calls emit spans, so this needs mcp.enabled to have any effect; set without it, nothing is exported and Cetacean logs a warning. With MCP enabled, a malformed endpoint stops startup.

  • envCETACEAN_OTEL_ENDPOINT
logging.level

Minimum log severity. One of debug, info, warn, or error.

  • flag-log-level
  • envCETACEAN_LOG_LEVEL
  • defaultinfo
logging.format

Log output format. json produces structured lines, text produces human-readable console output.

  • flag-log-format
  • envCETACEAN_LOG_FORMAT
  • defaultjson
server.pprof

Expose Go runtime profiling endpoints at /debug/pprof/ for diagnosing CPU, memory, and goroutine issues. Leave off unless you are profiling.

  • flag-pprof
  • envCETACEAN_PPROF
  • defaultfalse
server.self_metrics

Expose a Prometheus-compatible metrics endpoint at /-/metrics with internal counters for SSE connections, cache operations, and HTTP request latency.

  • flag-self-metrics
  • envCETACEAN_SELF_METRICS
  • defaulttrue
server.version_check

Ask api.github.com for the latest Docker Engine release, so a node’s page can point out a newer one. Turn it off where Cetacean must not reach the internet; the node page then shows no update hint.

  • flag-version-check
  • envCETACEAN_VERSION_CHECK
  • defaulttrue
server.recommendations

Enable the recommendation engine, which periodically analyzes swarm state and Prometheus metrics to surface findings. See Recommendations.

  • flag-recommendations
  • envCETACEAN_RECOMMENDATIONS
  • defaulttrue
server.operations_level

Which write operations the dashboard and the API expose. 0 is read-only, 1 allows operational actions, 2 adds configuration edits, 3 allows impactful operations such as deletions and node role changes. See Operations level for the breakdown.

  • flag-operations-level
  • envCETACEAN_OPERATIONS_LEVEL
  • default0
server.sse.batch_interval

How long the SSE broadcaster waits to batch change events into a single push. Lower values cut UI latency, higher values cut network overhead when many resources change at once. Accepts any Go duration string, such as 50ms or 1s.

  • flag-sse-batch-interval
  • envCETACEAN_SSE_BATCH_INTERVAL
  • default100ms
server.cors.origins

Origins allowed to make cross-origin requests to the API, as a comma-separated list, for example https://admin.example.com, or * for any. When unset, no CORS headers are sent and browsers block cross-origin requests.

The same origins are trusted for cross-origin writes; * can’t be, so with a wildcard browsers may read the API from any origin while cross-origin writes are refused.

  • flag-cors-origins
  • envCETACEAN_CORS_ORIGINS
server.trusted_proxies

Comma-separated IP addresses or CIDR ranges of reverse proxies whose forwarding headers are trusted, for example 10.0.0.0/8,172.16.0.0/12. The real client IP is read from the header family server.forwarded_headers names. Required for header-based authentication, and for cert mode behind a TLS-terminating proxy. When unset, every request counts as a direct connection.

  • flag-trusted-proxies
  • envCETACEAN_TRUSTED_PROXIES
server.forwarded_headers

Which forwarding headers a proxy in server.trusted_proxies writes: x-forwarded for X-Forwarded-For, X-Forwarded-Proto and X-Forwarded-Host, or forwarded for Forwarded. The other family is discarded before anything reads it.

Set this to match your proxy. Every common proxy writes the x-forwarded family by default and passes an inbound Forwarded through untouched, so a deployment reading both would let a client name its own address and origin.

  • flag-forwarded-headers
  • envCETACEAN_FORWARDED_HEADERS
  • defaultx-forwarded
storage.snapshot

Persist swarm state to disk after every sync. On restart Cetacean loads the snapshot to serve data immediately while the live sync catches up.

  • flag-snapshot
  • envCETACEAN_SNAPSHOT
  • defaulttrue
storage.data_dir

Directory holding snapshot.json and, when the authorization server is enabled, oauth-tokens.json. The token file is written regardless of storage.snapshot. Must be writable by the Cetacean process; mount it as a volume in Docker.

  • flag-data-dir
  • envCETACEAN_DATA_DIR
  • default./data
tls.cert

Path to the PEM-encoded server certificate for TLS termination. Set it together with tls.key or not at all. Required for client certificate authentication unless a TLS-terminating proxy forwards the certificate instead; optional in every other mode.

  • flag-tls-cert
  • envCETACEAN_TLS_CERT
tls.key

Path to the PEM-encoded private key matching tls.cert.

  • flag-tls-key
  • envCETACEAN_TLS_KEY
config

Path to a TOML config file. See Config file for the format.

  • flag-config
  • envCETACEAN_CONFIG

Authentication and authorization

auth.mode

Authentication provider. One of none (anonymous access), oidc, tailscale, cert (mTLS client certificates), or headers. Only one mode is active at a time. See Authentication for setup guides.

  • flag-auth-mode
  • envCETACEAN_AUTH_MODE
  • defaultnone

OIDC

auth.oidc.issuerrequired

Base URL of the OpenID Connect identity provider, for example https://accounts.google.com. Must support OIDC Discovery at /.well-known/openid-configuration.

  • flag-auth-oidc-issuer
  • envCETACEAN_AUTH_OIDC_ISSUER
auth.oidc.client_idrequired

OAuth 2.0 client ID registered with the identity provider for Cetacean.

  • flag-auth-oidc-client-id
  • envCETACEAN_AUTH_OIDC_CLIENT_ID
auth.oidc.client_secretrequired

OAuth 2.0 client secret for the registered client. Accepts the _FILE suffix.

  • flag-auth-oidc-client-secret
  • envCETACEAN_AUTH_OIDC_CLIENT_SECRET
auth.oidc.redirect_url

URL the identity provider redirects to after authentication, for example https://cetacean.example.com/auth/callback. Must use HTTPS; http://localhost and http://127.0.0.1 are allowed for local development. Defaults to {server.public_url}{server.base_path}/auth/callback; required only when server.public_url is unset, or when the callback lives elsewhere.

  • flag-auth-oidc-redirect-url
  • envCETACEAN_AUTH_OIDC_REDIRECT_URL
auth.oidc.scopes

Comma-separated OAuth 2.0 scopes to request. The defaults cover user identity, display name, and email. Add provider-specific scopes for further claims, such as group membership.

  • flag-auth-oidc-scopes
  • envCETACEAN_AUTH_OIDC_SCOPES
  • defaultopenid,profile,email
auth.oidc.session_key

Hex-encoded 32-byte HMAC key signing browser session cookies. When unset, a random key is generated at startup and restarting invalidates all sessions. Generate a fixed one with openssl rand -hex 32. Accepts the _FILE suffix.

  • flag-auth-oidc-session-key
  • envCETACEAN_AUTH_OIDC_SESSION_KEY

Tailscale

auth.tailscale.mode

How Cetacean reaches Tailscale. local queries the host’s Tailscale daemon. tsnet embeds a Tailscale node in the process, which suits containers. See Authentication for a comparison.

  • flag-auth-tailscale-mode
  • envCETACEAN_AUTH_TAILSCALE_MODE
  • defaultlocal
auth.tailscale.authkey

Tailscale auth key for automatic node enrollment, required in tsnet mode. Generate one in the Tailscale admin console under Settings, Keys. Accepts the _FILE suffix.

  • flag-auth-tailscale-authkey
  • envCETACEAN_AUTH_TAILSCALE_AUTHKEY
auth.tailscale.hostname

Hostname the embedded Tailscale node registers as (tsnet mode only). The dashboard is then reachable at https://cetacean.[[tailnet-name]].ts.net.

  • flag-auth-tailscale-hostname
  • envCETACEAN_AUTH_TAILSCALE_HOSTNAME
  • defaultcetacean
auth.tailscale.state_dir

Directory for persisting tsnet node state (keys, registration). Mount it as a volume in Docker to avoid re-enrolling the node on every restart.

  • flag-auth-tailscale-state-dir
  • envCETACEAN_AUTH_TAILSCALE_STATE_DIR
auth.tailscale.capability

Tailscale ACL capability key mapping tailnet users to application groups, for example example.com/cap/cetacean. Cetacean reads group grants from Tailscale’s CapMap into the identity’s groups array for authorization.

  • flag-auth-tailscale-capability
  • envCETACEAN_AUTH_TAILSCALE_CAPABILITY

Client certificates

auth.cert.carequired

Path to a PEM-encoded CA certificate bundle. Client certificates must be signed by one of its CAs. Supports certificate chains and multiple CAs in one file. Configures Cetacean’s own TLS listener, so it requires tls.cert and tls.key and is required with them. Behind a TLS-terminating proxy the proxy verifies the certificate against its own CA instead, and this setting isn’t consulted.

  • flag-auth-cert-ca
  • envCETACEAN_AUTH_CERT_CA

Trusted proxy headers

Caution

In headers mode Cetacean trusts whatever the proxy sends, so server.trusted_proxies must be set. Without it any client that can reach Cetacean directly can claim any identity.

auth.headers.subjectrequired

Name of the HTTP header carrying the user’s unique identifier, for example X-Remote-User. Becomes the identity’s subject and is used for authorization audience matching.

  • flag-auth-headers-subject
  • envCETACEAN_AUTH_HEADERS_SUBJECT
auth.headers.name

Name of the HTTP header carrying the user’s display name, for example X-Remote-Name. Shown in the dashboard’s user badge.

  • flag-auth-headers-name
  • envCETACEAN_AUTH_HEADERS_NAME
auth.headers.email

Name of the HTTP header carrying the user’s email address, for example X-Remote-Email. Used for authorization audience matching alongside the subject.

  • flag-auth-headers-email
  • envCETACEAN_AUTH_HEADERS_EMAIL
auth.headers.groups

Name of the HTTP header carrying group memberships as a comma-separated list, for example X-Remote-Groups. Used for authorization audience matching.

  • flag-auth-headers-groups
  • envCETACEAN_AUTH_HEADERS_GROUPS
auth.headers.secret_header

Name of an HTTP header that must carry a shared secret for the request to be accepted. Optional protection on top of the IP check in server.trusted_proxies.

  • flag-auth-headers-secret-header
  • envCETACEAN_AUTH_HEADERS_SECRET_HEADER
auth.headers.secret_value

Expected value of the shared secret header. Required when auth.headers.secret_header is set. Accepts the _FILE suffix.

  • flag-auth-headers-secret-value
  • envCETACEAN_AUTH_HEADERS_SECRET_VALUE

Authorization

Authorization is grant-based RBAC layered on the active authentication mode. With no policy configured every authenticated user has full access; once a policy is present the default is deny. Auth mode none bypasses authorization. See Authorization for the grant syntax.

acl.policy

Inline authorization policy as JSON, YAML, or TOML. Suitable for a short policy passed through the environment. Prefer acl.policy_file for anything longer, since only a file is watched for changes.

  • envCETACEAN_ACL_POLICY
acl.policy_file

Path to a policy file (JSON, YAML, or TOML). The file is watched and reloaded on change, so grants can be edited without restarting Cetacean.

  • envCETACEAN_ACL_POLICY_FILE

The following three settings read grants carried by the identity itself. They add to whatever the policy already grants, and each applies only to its own authentication mode.

acl.tailscale_capability

Tailscale CapMap key holding per-user grants, for example example.com/cap/cetacean-acl. Read in tailscale mode only.

  • envCETACEAN_AUTH_TAILSCALE_ACL_CAPABILITY
acl.oidc_claim

Name of the OIDC token claim holding grants, for example cetacean_grants. Read in oidc mode only.

  • envCETACEAN_AUTH_OIDC_ACL_CLAIM
acl.headers_acl

Name of the HTTP header holding grants as JSON, for example X-Remote-Grants. Read in headers mode only, and only from a request that passed the server.trusted_proxies check.

  • envCETACEAN_AUTH_HEADERS_ACL
acl.headers_capability

Key of the grants array when the acl.headers_acl header holds a JSON object rather than an array, for example example.com/cap/cetacean for the Tailscale-App-Capabilities header tailscale serve sends. A missing key or a value of the wrong shape grants nothing. Unset, the header must be a bare array.

  • envCETACEAN_AUTH_HEADERS_ACL_CAPABILITY

OAuth authorization server

Cetacean can run an OAuth 2.1 authorization server, which issues the bearer tokens clients present to protected resources. It’s disabled by default and has to be asked for: it mints credentials for your cluster, so it should never appear as a side effect of enabling something else.

Two resources can be protected: /mcp, and the web API when oauth.api_tokens is on. /mcp authenticates itself rather than going through the authentication middleware. So under an auth mode other than none it needs one of two things, and Cetacean refuses to start with neither: this server, or the active mode listed in mcp.auth_bypass, which has the upstream provider authenticate every request instead. The bypass is how an mTLS deployment runs no authorization server at all—those clients can’t drive a browser consent screen, so one would only sit unused.

oauth.enabled

Run the authorization server, mounting /oauth/* and the RFC 8414 and RFC 9728 discovery documents. Requires an auth mode other than none, since the server has no identity of its own to consent as.

  • envCETACEAN_OAUTH_ENABLED
  • defaultfalse
oauth.issuer

Canonical external base URL, for example https://cetacean.example.com. Becomes the OAuth issuer identifier and the base of the resource audience, so it must be the URL clients reach. Defaults to server.public_url; set this only to give the authorization server a different URL from the rest of Cetacean. With neither set, it’s derived from the listen address, and startup fails if that yields no reachable host.

  • envCETACEAN_OAUTH_ISSUER
oauth.signing_key

Root secret the token-signing key and the consent page’s CSRF key are each derived from. When unset, a fresh key is generated at startup and every existing token becomes invalid, so set it for any deployment that should survive a restart. Generate one with openssl rand -hex 32. Cetacean refuses to start unless the value decodes as hex or base64 to exactly 32 bytes: the public half of the signing key is published and unauthenticated, so a guessable root could be recovered from it. Accepts the _FILE suffix.

  • envCETACEAN_OAUTH_SIGNING_KEY
oauth.access_token_ttl

How long an access token stays valid.

  • envCETACEAN_OAUTH_ACCESS_TOKEN_TTL
  • default1h
oauth.refresh_token_ttl

How long a refresh token stays valid (30 days). Refresh tokens rotate single-use and persist under storage.data_dir, so clients keep working across restarts.

  • envCETACEAN_OAUTH_REFRESH_TOKEN_TTL
  • default720h
oauth.consent_ttl

How long a remembered approval lets a client skip the consent screen (90 days). Keep it above oauth.refresh_token_ttl, or an expiring refresh token costs a second prompt. Set 0s to prompt on every authorization.

  • envCETACEAN_OAUTH_CONSENT_TTL
  • default2160h
oauth.api_tokens

Offer the web API as a protected resource, so a client can obtain a token for it and authenticate with Authorization: Bearer instead of a browser session. The API and /mcp are separate resources: a token for one is refused by the other, whichever path it sits under. Turning this off makes the API resource undiscoverable as well as unusable—there’s no metadata document for it, and the authorize endpoint refuses to mint one.

  • envCETACEAN_OAUTH_API_TOKENS
  • defaultfalse
oauth.token_operations_level

What a caller holding a token may do on the web API: 0 reads only, 1 operational, 2 configuration, 3 impactful. Inherits server.operations_level when unset, and narrows it rather than replacing it—a token never reaches past the tier the deployment itself runs at. Set it lower to leave a token on a device that can read the cluster but not change it. /mcp is governed by mcp.operations_level instead: MCP registers its tool list once, so it can’t hold two callers to different tiers.

  • envCETACEAN_OAUTH_TOKEN_OPERATIONS_LEVEL
oauth.require_resource_indicator

Require the RFC 8707 resource parameter on authorize and token requests, which stops a token issued for Cetacean being replayed against another server and is how a client says which resource it wants. Turn it off only for a client that can’t send the parameter; a request without one is then bound to the web API, or to /mcp where oauth.api_tokens is off.

  • envCETACEAN_OAUTH_REQUIRE_RESOURCE_INDICATOR
  • defaulttrue
oauth.dcr_enabled

Accept RFC 7591 Dynamic Client Registration at /oauth/register. Registrations are kept across a restart, beside the refresh tokens in oauth-tokens.json. MCP revision 2026-07-28 deprecates DCR in favor of Client ID Metadata Documents, and it stays on for clients that don’t support those yet.

  • envCETACEAN_OAUTH_DCR_ENABLED
  • defaulttrue
oauth.dcr_rate_limit

Maximum dynamic client registrations accepted per IP address per hour.

  • envCETACEAN_OAUTH_DCR_RATE_LIMIT
  • default10
oauth.dcr_max_clients

Global cap on registered clients. Once reached, the oldest registration is evicted, and the eviction is logged.

  • envCETACEAN_OAUTH_DCR_MAX_CLIENTS
  • default1000
oauth.cimd_enabled

Accept Client ID Metadata Documents, where a client identifies itself by an https:// URL Cetacean fetches. Fetches pass an SSRF blocklist and are cached as the response’s Cache-Control or Expires allows, for at most a day, or an hour when it says nothing.

  • envCETACEAN_OAUTH_CIMD_ENABLED
  • defaulttrue

MCP server

Cetacean can expose cluster data to AI agents over the Model Context Protocol. The server is disabled by default. When enabled it mounts at /mcp and requires an OAuth 2.1 bearer token from the authorization server, unless the active auth mode is listed in mcp.auth_bypass. Every tool call is also checked against the authorization grants, so an agent gets no more access than the calling identity already has.

mcp.enabled

Enable the embedded MCP server at /mcp.

  • envCETACEAN_MCP
  • defaultfalse
mcp.operations_level

Which tools MCP clients may call: 0 reads only, 1 operational, 2 configuration, 3 impactful. Inherits server.operations_level when unset, and narrows it rather than replacing it—a value above the global one grants nothing. Set it lower to allow writes from the dashboard that agents can’t make. This is the ceiling for every MCP client, whatever it authenticated with; oauth.token_operations_level governs the web API.

  • envCETACEAN_MCP_OPERATIONS_LEVEL
mcp.max_concurrent_tasks

Cap on in-flight task-augmented tool calls. Mutations that wait for a service to converge run as tasks, so this bounds how many such waits can be outstanding.

  • envCETACEAN_MCP_MAX_CONCURRENT_TASKS
  • default32
mcp.task_ttl

How long a task’s result is retained when the call omits a TTL of its own. Set 0s to disable the fill-in, which then keeps such results for the life of the process.

  • envCETACEAN_MCP_TASK_TTL
  • default15m
mcp.max_task_ttl

Ceiling on the retention a call may ask for; longer requests are clamped to it. Set 0s to accept whatever a client asks for.

  • envCETACEAN_MCP_MAX_TASK_TTL
  • default1h
mcp.auth_bypass

Comma-separated authentication modes that skip the bearer check at /mcp, for example cert. Use it where the transport already carries a verified identity. Authorization still applies; only the OAuth handshake is skipped. A mode listed here is authenticated by its own provider on every request, so it satisfies /mcp on its own and oauth.enabled can stay off. Only cert, headers, and tailscale may be listed, and Cetacean refuses to start on anything else: those carry identity in the transport, where oidc authenticates from a session cookie—an ambient credential that /mcp’s exemption from cross-origin protection assumes is absent.

  • envCETACEAN_MCP_AUTH_BYPASS

See MCP for the tools, resources, prompts, and widgets the server exposes.

Recommendation sizing

These tune the resource right-sizing checker, the only recommendation category with configurable thresholds. It requires Prometheus, since it compares reservations and limits against measured usage. The other checkers use fixed thresholds.

sizing.headroom_multiplier

Multiplier applied to observed usage when suggesting a new reservation or limit. Accepts 1.0 to 10.0.

  • envCETACEAN_SIZING_HEADROOM_MULTIPLIER
  • default2.0
sizing.thresholds.over_provisioned

Usage below this fraction of the reservation marks a service over-provisioned. Accepts 0.0 to 1.0.

  • envCETACEAN_SIZING_THRESHOLD_OVER_PROVISIONED
  • default0.20
sizing.thresholds.approaching_limit

Usage above this fraction of the limit raises a warning. Accepts 0.0 to 1.0.

  • envCETACEAN_SIZING_THRESHOLD_APPROACHING_LIMIT
  • default0.80
sizing.thresholds.at_limit

Usage above this fraction of the limit raises a critical finding. Accepts 0.0 to 1.0. Startup refuses thresholds out of order: over_provisioned ≤ approaching_limit ≤ at_limit.

  • envCETACEAN_SIZING_THRESHOLD_AT_LIMIT
  • default0.95
sizing.thresholds.lookback

Window over which p95 usage is queried when deciding whether a service is over-provisioned (7 days). A short window makes the check react to a quiet weekend; a long one needs that much history in Prometheus.

  • envCETACEAN_SIZING_LOOKBACK
  • default168h

Config file

Pass a TOML file with -config or CETACEAN_CONFIG. Without either, Cetacean reads the first of these that exists: ./cetacean.toml, $XDG_CONFIG_HOME/cetacean/cetacean.toml (or ~/.config/cetacean/cetacean.toml), ~/.cetacean.toml, and /etc/cetacean/cetacean.toml. Every field is optional; an omitted key uses the default.

CETACEAN_CONFIG=/etc/cetacean/config.toml cetacean

Without either, Cetacean loads the first of these that exists: ./cetacean.toml, $XDG_CONFIG_HOME/cetacean/cetacean.toml (or ~/.config/cetacean/cetacean.toml), ~/.cetacean.toml, and /etc/cetacean/cetacean.toml. The startup log names the file it loaded and whether it was discovered.

docs/config.reference.toml in the repository lists every option with its default. Copy it as a starting point and uncomment what you need.

Subcommands

cetacean                  Start the server
cetacean healthcheck      Exit 0 if ready, 1 otherwise (for Docker HEALTHCHECK)

Snapshots

Cetacean writes all cached swarm state to ${data_dir}/snapshot.json after every sync. On startup it loads the snapshot to serve stale-but-fast data while the live sync catches up, in every representation: JSON, CSV, MCP, and the dashboard alike. Without a snapshot, reads of cluster state answer 503 until the first sync, and /-/ready answers 503 until then either way. Snapshot writes are atomic, so a crash mid-write can’t corrupt the file.

Health checks

Two meta endpoints, exempt from authentication and content negotiation:

EndpointBehaviorUse for
GET /-/healthAlways 200 if the process is runningUptime monitoring, restart policies
GET /-/ready200 after the first sync that reaches the swarm; 503 until thenLoad balancers, Docker health checks

GET /-/health also reports the version, the operations level, and whether Cetacean is still tracking the cluster; the API page has the fields.

The cetacean healthcheck subcommand probes /-/ready and is what the built-in Docker HEALTHCHECK runs. It loads its configuration the way the server does, so it probes the configured listen address, base path, and TLS setting. Docker runs it as a separate process without the service’s command-line flags, though: set anything it must honor in the environment, in a file named by CETACEAN_CONFIG, or in a file at one of the discovered paths. Flags given to the subcommand itself go before healthcheck.

Operations level

server.operations_level sets the ceiling on which write operations the dashboard and the API expose. Each level includes everything below it. A request above the configured level gets 403 Forbidden with error code OPS001.

Operation0 read-only1 operational2 configuration3 impactful
Browse all resources✔✔✔✔
Scale, restart, roll back, update image—✔✔✔
Edit service definitions (env, labels, resources, ports, placement, policies)——✔✔
Attach configs, secrets, networks, volumes, and tmpfs mounts to a service——✔✔
Edit node labels——✔✔
Create configs and secrets, edit their labels——✔✔
Enable, disable, or configure plugins——✔✔
Edit swarm settings (raft, orchestration, dispatcher)——✔✔
Delete any resource———✔
Add a bind or named-pipe mount, a volume driver, or a capability to a service———✔
Change node availability or role———✔
Change a service’s endpoint mode———✔
Install, upgrade, or remove plugins———✔
Manage CA and encryption, read and rotate join tokens, unlock the swarm———✔

Operations level and grants are independent checks and both must pass. Operations level is the global ceiling, grants control per-user scope. Set mcp.operations_level to give MCP clients a lower ceiling than the dashboard, and oauth.token_operations_level to do the same for API tokens.

Profiling

When server.pprof is enabled, the standard Go profiling endpoints are available at /debug/pprof/:

go tool pprof http://localhost:9000/debug/pprof/profile   # 30s CPU profile
go tool pprof http://localhost:9000/debug/pprof/heap      # heap snapshot