Skip to content

Environment-variable reference

Scalar fields and simple lists are settable from environment variables, so common container deployments need no mounted config file. Maps and lists of structured entries remain file-only. The env layer overrides any file that is present, so secrets can stay outside YAML. See configuration.md for the layering model and the prose reference, and ../config.example.yaml for the same fields as a commented file.

Naming. Take the dotted config key, prefix it with TS2OTEL_, uppercase it, and replace each . with __ (a single _ inside a name is preserved):

tailscale.auth.oauth.client_secret  ->  TS2OTEL_TAILSCALE__AUTH__OAUTH__CLIENT_SECRET
collectors.flowlogs.interval        ->  TS2OTEL_COLLECTORS__FLOWLOGS__INTERVAL

Lists are comma-separated (e.g. TS2OTEL_TAILSCALE__AUTH__OAUTH__SCOPES=all:read,log_streaming). A TS2OTEL_* variable that matches no known key is logged as a startup WARN.

This table is generated from ../config.example.yaml. Do not edit between the markers; run just gen envref (or go test ./internal/config -run TestEnvReferenceDocInSync -update) to refresh it.

File-only — these take structured values (a map or a list of objects) and must be set in the YAML config, not via an environment variable: tailnets (restart), otlp.headers (restart), otlp.metrics.headers (restart), otlp.logs.headers (restart), otlp.traces.headers (restart), collectors.devices.posture_compliance_checks (restart), collectors.node_metrics.targets (restart), collectors.node_metrics.discovery.port_overrides (restart), streaming.routes (restart), webhook.routes (restart), profiling.pyroscope.tags (restart), profiling.pyroscope.headers (restart), resource.attributes (restart).

Environment variableDefaultReloadDescription
TS2OTEL_LOG_LEVELinforestartexporter's own log verbosity: debug | info | warn | error
TS2OTEL_LOG_FORMATtextrestartoperational log encoding: text | json (json = one record per line)
TS2OTEL_PROVIDERtailscalerestartcontrol-plane backend: tailscale (default) | headscale
TS2OTEL_HEADSCALE__URL""restartHeadscale origin only (scheme + host, optional port; no path, credentials, query, or fragment), e.g. https://headscale.example.org (TS2OTEL_HEADSCALE__URL)
TS2OTEL_HEADSCALE__API_KEY""restartBearer API key — keep in env (TS2OTEL_HEADSCALE__API_KEY)
TS2OTEL_HEADSCALE__API_KEY_FILE""restartread the value from this file instead (Docker secrets); set the value or the file, not both; content is whitespace-trimmed
TS2OTEL_HEADSCALE__IP_PREFIXES[]restarttailnet address CIDRs allocated by this Headscale; empty = Tailscale defaults. Must be canonical and fully inside RFC1918, fc00::/7, or 100.64.0.0/10 (comma-separated list)
TS2OTEL_HEADSCALE__HTTP__TIMEOUT30srestartper-attempt timeout; retry queueing/rate-limit wait is outside this budget
TS2OTEL_HEADSCALE__HTTP__RETRY__MAX_ATTEMPTS0restartretry policy for retryable transport errors, HTTP 429 and HTTP 5xx
TS2OTEL_HEADSCALE__HTTP__RETRY__BASE_DELAY0srestartretry policy for retryable transport errors, HTTP 429 and HTTP 5xx
TS2OTEL_HEADSCALE__HTTP__RETRY__MAX_DELAY0srestartretry policy for retryable transport errors, HTTP 429 and HTTP 5xx
TS2OTEL_HEADSCALE__HTTP__RATE_LIMIT0restartHTTP client used for all Headscale API calls
TS2OTEL_HEADSCALE__MAX_RESPONSE_BYTES4194304restartcap (4 MiB) on ONE Headscale API response body before decoding; ~5800 nodes at ~715 B each — raise it (and the container memory limit) on a bigger deployment, these endpoints are not paginated
TS2OTEL_TAILSCALE__TAILNET-restart"-" = the authenticated principal's default tailnet (works out of the box); or set your tailnet's name explicitly, e.g. "example.com"
TS2OTEL_TAILSCALE__AUTH__METHODoauthrestartoauth (recommended) | apikey | workload_identity (keyless OIDC exchange)
TS2OTEL_TAILSCALE__AUTH__OAUTH__CLIENT_ID""restartOAuth client ID (set via TS2OTEL_TAILSCALE__AUTH__OAUTH__CLIENT_ID)
TS2OTEL_TAILSCALE__AUTH__OAUTH__CLIENT_SECRET""restartOAuth client secret — keep in env, not here (..._CLIENT_SECRET)
TS2OTEL_TAILSCALE__AUTH__OAUTH__CLIENT_SECRET_FILE""restartread the value from this file instead (Docker secrets); set the value or the file, not both; content is whitespace-trimmed
TS2OTEL_TAILSCALE__AUTH__OAUTH__SCOPES[all:read]restartleast-privilege read scopes requested for the token (comma-separated list)
TS2OTEL_TAILSCALE__AUTH__APIKEY""restartpersonal API key (set via TS2OTEL_TAILSCALE__AUTH__APIKEY); used only when method: apikey — expires <=90d and is tied to its creator
TS2OTEL_TAILSCALE__AUTH__APIKEY_FILE""restartread the value from this file instead (Docker secrets); set the value or the file, not both; content is whitespace-trimmed
TS2OTEL_TAILSCALE__AUTH__WORKLOAD_IDENTITY__CLIENT_ID""restartfederated OAuth client ID from the Tailscale admin console (TS2OTEL_TAILSCALE__AUTH__WORKLOAD_IDENTITY__CLIENT_ID)
TS2OTEL_TAILSCALE__AUTH__WORKLOAD_IDENTITY__ID_TOKEN_FILE""restartpath to the OIDC ID token, e.g. a Kubernetes projected service-account token; re-read on every exchange (rotation-safe)
TS2OTEL_TAILSCALE__HTTP__TIMEOUT30srestartper-attempt timeout (each retry attempt; a retried request may take longer, and long Retry-After waits are honored)
TS2OTEL_TAILSCALE__HTTP__RETRY__MAX_ATTEMPTS4restarttotal attempts per request (1 = no retry); exponential backoff between tries
TS2OTEL_TAILSCALE__HTTP__RETRY__BASE_DELAY500msrestartinitial backoff delay
TS2OTEL_TAILSCALE__HTTP__RETRY__MAX_DELAY10srestartbackoff ceiling
TS2OTEL_TAILSCALE__HTTP__RATE_LIMIT0restartglobal requests/sec across ALL collectors (0 = unlimited)
TS2OTEL_TAILSCALE__MAX_RESPONSE_BYTES4194304restartcap (4 MiB) on ONE snapshot-endpoint response body before decoding; ~2400 devices at ~1.8 KiB each — raise it (and the container memory limit) on a bigger tailnet, these endpoints are not paginated
TS2OTEL_TAILSCALE__MAX_LOG_RESPONSE_BYTES33554432restartcap (32 MiB) on ONE flow-log/audit-log response body; ~12000 flow records per poll — shrink the collector's window instead of raising this if you hit it
TS2OTEL_TAILSCALE__ORGANIZATION""restartalpha roster inventory via first runtime credential (needs tailnets:read); runtimes still require explicit credentials
TS2OTEL_PAM__TAILNET""restartconfigured tailnet name hosting PAM; empty selects the primary runtime; restart required
TS2OTEL_PAM__TOKEN""restartstatic read-only Border0 service-account bearer token; keep in TS2OTEL_PAM__TOKEN
TS2OTEL_PAM__API_URLhttps://api.border0.com/api/v1restartoverride only for a compatible proxy or local test endpoint
TS2OTEL_OTLP__PROTOCOLhttprestarthttp | grpc | stdout (stdout = print signals to the console for local debug, no backend)
TS2OTEL_OTLP__ENDPOINThttps://otlp-gateway-prod-us-central-0.grafana.net/otlprestartOTLP base URL (the exporter appends /v1/metrics, /v1/logs and /v1/traces itself)
TS2OTEL_OTLP__GRAFANA_CLOUD__INSTANCE_ID""restartGrafana Cloud stack/instance ID (set via TS2OTEL_OTLP__GRAFANA_CLOUD__INSTANCE_ID)
TS2OTEL_OTLP__GRAFANA_CLOUD__TOKEN""restartGrafana Cloud OTLP token — keep in env (..._GRAFANA_CLOUD__TOKEN)
TS2OTEL_OTLP__GRAFANA_CLOUD__TOKEN_FILE""file_contentread the value from this file instead (Docker secrets); set the value or the file, not both; content is whitespace-trimmed
TS2OTEL_OTLP__TLS__INSECUREfalserestartdisable TLS entirely (plaintext h2c/http) — NOT a cert-verify skip; do not use in production
TS2OTEL_OTLP__TLS__INSECURE_SKIP_VERIFYfalserestartkeep TLS but skip server-cert verification (self-signed/private-CA gateways, testing only — prefer ca_file)
TS2OTEL_OTLP__TLS__CA_FILE""file_contentpath to a custom CA bundle to trust
TS2OTEL_OTLP__TLS__CERT_FILE""file_contentclient certificate path (for mutual TLS)
TS2OTEL_OTLP__TLS__KEY_FILE""file_contentclient private key path (for mutual TLS)
TS2OTEL_OTLP__METRIC_INTERVAL60srestarthow often metrics are pushed (60s aligns with a 1-data-point-per-minute scrape)
TS2OTEL_OTLP__METRIC_EXPORT_BATCH_SIZE10000restartmaximum datapoints per OTLP metric request; lower this when a backend has a small request-size limit (serialized bytes vary with labels)
TS2OTEL_OTLP__METRIC_TEMPORALITYcumulativerestartcumulative (Grafana Cloud default) | delta
TS2OTEL_OTLP__OUTAGE_SUMMARY_INTERVAL5mrestartrepeat a concise diagnostic while an OTLP outage continues
TS2OTEL_OTLP__LIMITS__LOG_BODY_BYTES32768restartcap a log record's body; UTF-8 safe, applied AFTER redaction, leaves a truncation marker. Minimum 64 — there is no unlimited setting
TS2OTEL_OTLP__LIMITS__LOG_ATTRIBUTE_VALUE_BYTES4096restartcap each string-valued log ATTRIBUTE; never applied to metric labels (those must stay byte-exact or series split)
TS2OTEL_OTLP__COMPRESSION""restartgzip | none. Empty defers to OTEL_EXPORTER_OTLP[_]_COMPRESSION, then the exporter default. TS2OTEL_OTLP__COMPRESSION
TS2OTEL_OTLP__TIMEOUT0srestartper-request export timeout; 0 defers to OTEL_EXPORTER_OTLP[_]_TIMEOUT, then the exporter's 10s. TS2OTEL_OTLP__TIMEOUT
TS2OTEL_OTLP__MAX_REQUEST_SIZE0restartbytes; a client-side REJECTION guard, not a splitter — it fails an oversized request instead of shipping it into a 413. Use metric_export_batch_size to actually stay under an ingest limit
TS2OTEL_OTLP__GRPC_RECONNECTION_PERIOD0srestartforce a fresh gRPC connection attempt after this long; gRPC only, 0 = the gRPC client default
TS2OTEL_OTLP__RETRY__ENABLEDtruerestartset false to disable retry
TS2OTEL_OTLP__RETRY__INITIAL_INTERVAL5srestartfirst backoff delay
TS2OTEL_OTLP__RETRY__MAX_INTERVAL30srestartbackoff ceiling
TS2OTEL_OTLP__RETRY__MAX_ELAPSED_TIME1mrestartgive up after this long
TS2OTEL_OTLP__BATCH__LOGS__MAX_QUEUE_SIZE0restartrecords buffered before new ones are dropped (non-blocking by design)
TS2OTEL_OTLP__BATCH__LOGS__EXPORT_MAX_BATCH_SIZE0restartrecords per export; must be <= max_queue_size when both are set
TS2OTEL_OTLP__BATCH__LOGS__EXPORT_INTERVAL0srestarthow often a partial batch is flushed
TS2OTEL_OTLP__BATCH__LOGS__EXPORT_TIMEOUT0srestartbound on one export attempt
TS2OTEL_OTLP__BATCH__TRACES__MAX_QUEUE_SIZE0restartspans buffered before new ones are dropped
TS2OTEL_OTLP__BATCH__TRACES__EXPORT_MAX_BATCH_SIZE0restartspans per export; must be <= max_queue_size when both are set
TS2OTEL_OTLP__BATCH__TRACES__EXPORT_INTERVAL0srestarthow often a partial batch is flushed
TS2OTEL_OTLP__BATCH__TRACES__EXPORT_TIMEOUT0srestartbound on one export attempt
TS2OTEL_OTLP__STDOUT__METRIC_INTERVAL5srestartshort cadence so a debug run doesn't wait 60s for a metric; logs and spans are emitted synchronously
TS2OTEL_OTLP__STDOUT__PRETTYfalserestartindent the emitted JSON
TS2OTEL_OTLP__CREDENTIAL_RELOAD__ENABLEDfalserestartgoverns the background poller only; last-known-good is always retained for a configured file
TS2OTEL_OTLP__CREDENTIAL_RELOAD__INTERVAL30srestartpoll period; minimum 5s. Ignored when enabled is false
TS2OTEL_OTLP__METRICS__ENABLED""restartnull inherits (the signal is on); false stops exporting this signal WITHOUT disturbing the others
TS2OTEL_OTLP__METRICS__PROTOCOL""restartempty inherits otlp.protocol
TS2OTEL_OTLP__METRICS__ENDPOINT""restartempty inherits otlp.endpoint
TS2OTEL_OTLP__METRICS__TLS__INSECURE""restartnull inherits; explicit true/false overrides
TS2OTEL_OTLP__METRICS__TLS__INSECURE_SKIP_VERIFY""restartnull inherits; explicit true/false overrides
TS2OTEL_OTLP__METRICS__TLS__CA_FILE""restartevery empty/null field inherits the matching otlp.tls value
TS2OTEL_OTLP__METRICS__TLS__CERT_FILE""restartevery empty/null field inherits the matching otlp.tls value
TS2OTEL_OTLP__METRICS__TLS__KEY_FILE""restartevery empty/null field inherits the matching otlp.tls value
TS2OTEL_OTLP__METRICS__COMPRESSION""restartempty inherits otlp.compression
TS2OTEL_OTLP__METRICS__TIMEOUT0srestart0 inherits otlp.timeout
TS2OTEL_OTLP__METRICS__MAX_REQUEST_SIZE0restart0 inherits otlp.max_request_size
TS2OTEL_OTLP__METRICS__GRPC_RECONNECTION_PERIOD0srestart0 inherits otlp.grpc_reconnection_period
TS2OTEL_OTLP__METRICS__RETRY__ENABLED""restartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_OTLP__METRICS__RETRY__INITIAL_INTERVAL0srestartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_OTLP__METRICS__RETRY__MAX_INTERVAL0srestartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_OTLP__METRICS__RETRY__MAX_ELAPSED_TIME0srestartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_OTLP__LOGS__ENABLED""restartnull inherits (the signal is on); false stops exporting this signal WITHOUT disturbing the others
TS2OTEL_OTLP__LOGS__PROTOCOL""restartempty inherits otlp.protocol
TS2OTEL_OTLP__LOGS__ENDPOINT""restartempty inherits otlp.endpoint
TS2OTEL_OTLP__LOGS__TLS__INSECURE""restartnull inherits; explicit true/false overrides
TS2OTEL_OTLP__LOGS__TLS__INSECURE_SKIP_VERIFY""restartnull inherits; explicit true/false overrides
TS2OTEL_OTLP__LOGS__TLS__CA_FILE""restartevery empty/null field inherits the matching otlp.tls value
TS2OTEL_OTLP__LOGS__TLS__CERT_FILE""restartevery empty/null field inherits the matching otlp.tls value
TS2OTEL_OTLP__LOGS__TLS__KEY_FILE""restartevery empty/null field inherits the matching otlp.tls value
TS2OTEL_OTLP__LOGS__COMPRESSION""restartempty inherits otlp.compression
TS2OTEL_OTLP__LOGS__TIMEOUT0srestart0 inherits otlp.timeout
TS2OTEL_OTLP__LOGS__MAX_REQUEST_SIZE0restart0 inherits otlp.max_request_size
TS2OTEL_OTLP__LOGS__GRPC_RECONNECTION_PERIOD0srestart0 inherits otlp.grpc_reconnection_period
TS2OTEL_OTLP__LOGS__RETRY__ENABLED""restartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_OTLP__LOGS__RETRY__INITIAL_INTERVAL0srestartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_OTLP__LOGS__RETRY__MAX_INTERVAL0srestartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_OTLP__LOGS__RETRY__MAX_ELAPSED_TIME0srestartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_OTLP__TRACES__ENABLED""restartnull inherits (the signal is on); false stops exporting this signal WITHOUT disturbing the others
TS2OTEL_OTLP__TRACES__PROTOCOL""restartempty inherits otlp.protocol
TS2OTEL_OTLP__TRACES__ENDPOINT""restartempty inherits otlp.endpoint
TS2OTEL_OTLP__TRACES__TLS__INSECURE""restartnull inherits; explicit true/false overrides
TS2OTEL_OTLP__TRACES__TLS__INSECURE_SKIP_VERIFY""restartnull inherits; explicit true/false overrides
TS2OTEL_OTLP__TRACES__TLS__CA_FILE""restartevery empty/null field inherits the matching otlp.tls value
TS2OTEL_OTLP__TRACES__TLS__CERT_FILE""restartevery empty/null field inherits the matching otlp.tls value
TS2OTEL_OTLP__TRACES__TLS__KEY_FILE""restartevery empty/null field inherits the matching otlp.tls value
TS2OTEL_OTLP__TRACES__COMPRESSION""restartempty inherits otlp.compression
TS2OTEL_OTLP__TRACES__TIMEOUT0srestart0 inherits otlp.timeout
TS2OTEL_OTLP__TRACES__MAX_REQUEST_SIZE0restart0 inherits otlp.max_request_size
TS2OTEL_OTLP__TRACES__GRPC_RECONNECTION_PERIOD0srestart0 inherits otlp.grpc_reconnection_period
TS2OTEL_OTLP__TRACES__RETRY__ENABLED""restartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_OTLP__TRACES__RETRY__INITIAL_INTERVAL0srestartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_OTLP__TRACES__RETRY__MAX_INTERVAL0srestartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_OTLP__TRACES__RETRY__MAX_ELAPSED_TIME0srestartan untouched block inherits otlp.retry; setting ANY field overrides the whole policy for this signal
TS2OTEL_DELIVERY__MODEotlprestartotlp keeps historical push-only delivery; prometheus serves /metrics and suppresses inherited OTLP metrics/logs/traces; dual enables both. An otlp..endpoint explicitly opts that signal back in under prometheus mode
TS2OTEL_ENRICHMENT__CACHE_TTL5mrestartstaleness alarm threshold for the IP/nodeID -> name device cache
TS2OTEL_ENRICHMENT__DEVICE_CACHE_STALE_AFTER0srestartmark cached identity stale after this age; 0 preserves fresh-until-replaced behaviour
TS2OTEL_ENRICHMENT__REVERSE_DNS__ENABLEDfalserestartoff by default (can add ~one flow-metric series per external IP when on)
TS2OTEL_ENRICHMENT__REVERSE_DNS__SERVER""restartresolver "ip" or "ip:port" (default :53); empty = system/container resolver
TS2OTEL_ENRICHMENT__REVERSE_DNS__TIMEOUT2srestartper-lookup timeout
TS2OTEL_ENRICHMENT__REVERSE_DNS__CACHE_TTL24hrestarthow long a resolved name is cached (PTRs rarely change, so a long TTL keeps resolver load low)
TS2OTEL_ENRICHMENT__REVERSE_DNS__NEGATIVE_TTL5mrestarthow long a failed lookup is remembered (suppresses retries)
TS2OTEL_ENRICHMENT__REVERSE_DNS__STALE_TTL1hrestartkeep serving a resolved name this long past cache_ttl while one refresh runs (0 disables; stops the flow label flapping to external at every expiry)
TS2OTEL_ENRICHMENT__REVERSE_DNS__MAX_ENTRIES50000restartPTR cache size bound (new external IPs beyond this are not resolved; ~150 bytes/entry)
TS2OTEL_ENRICHMENT__REVERSE_DNS__ACKNOWLEDGE_CARDINALITYfalserestartset true (once metric_limit is sized) to silence the enabled+node_dims cardinality advisory
TS2OTEL_ENRICHMENT__GEOIP__ENABLEDfalserestartoff by default; tailnet addresses (CGNAT 100.64/10, ULA fd7a:115c:a1e0::/48) are NEVER geolocated
TS2OTEL_ENRICHMENT__GEOIP__COUNTRY_DATABASE""file_contentpath to a GeoLite2/GeoIP2 Country .mmdb; a City database also works and additionally fills locality/region/coordinates on flow LOGS
TS2OTEL_ENRICHMENT__GEOIP__ASN_DATABASE""file_contentpath to a GeoLite2/GeoIP2 ASN .mmdb; the AS number and organization ride flow LOGS only, never a metric
TS2OTEL_ENRICHMENT__GEOIP__RELOAD_INTERVAL6hrestartre-stat the files above and hot-swap a changed one (this is what makes an external geoipupdate cron work; 0 disables)
TS2OTEL_ENRICHMENT__GEOIP__ACKNOWLEDGE_CARDINALITYfalserestartset true (once metric_limit is sized) to silence the geo_dims-on-raw-flow-metrics advisory
TS2OTEL_ENRICHMENT__GEOIP__DOWNLOAD__ENABLEDfalserestartoff by default; leave off if something else supplies the .mmdb files
TS2OTEL_ENRICHMENT__GEOIP__DOWNLOAD__ACCOUNT_ID""restartMaxMind account ID (a free GeoLite2 account is enough)
TS2OTEL_ENRICHMENT__GEOIP__DOWNLOAD__LICENSE_KEY""restartMaxMind license key — set via TS2OTEL_ENRICHMENT__GEOIP__DOWNLOAD__LICENSE_KEY, never in YAML
TS2OTEL_ENRICHMENT__GEOIP__DOWNLOAD__LICENSE_KEY_FILE""restartread the license key from a file instead (Docker/Kubernetes secret style)
TS2OTEL_ENRICHMENT__GEOIP__DOWNLOAD__EDITIONS[GeoLite2-Country, GeoLite2-ASN]restartMaxMind edition IDs; each installs as /.mmdb (swap in GeoLite2-City for locality/coordinates on logs) (comma-separated list)
TS2OTEL_ENRICHMENT__GEOIP__DOWNLOAD__DIRECTORY""restartwhere databases are installed; empty = /geoip (same place as the checkpoint file)
TS2OTEL_ENRICHMENT__GEOIP__DOWNLOAD__INTERVAL24hrestarthow often to ask MaxMind for a newer build; each check is conditional, so an unchanged database costs a 304 and no download quota
TS2OTEL_ENRICHMENT__GEOIP__DOWNLOAD__TIMEOUT5mrestartper-edition download timeout
TS2OTEL_ENRICHMENT__GEOIP__DOWNLOAD__ENDPOINThttps://download.maxmind.com/geoip/databasesrestartdownload API base; override only for a local mirror
TS2OTEL_CARDINALITY__METRIC_LIMIT10000restarthard per-metric series cap; beyond it the SDK collapses extras into otel_metric_overflow (0/negative = unlimited)
TS2OTEL_CARDINALITY__DERP_REGION_ROLLUPtruerestartemit tailnet-wide per-DERP-region rollup gauges (tailscale.derp.region.*)
TS2OTEL_CARDINALITY__SUBNET_ROUTE_ROLLUPtruerestartemit per-CIDR tailscale.subnet_routes.routers redundancy gauge (one series per subnet CIDR); fleet exit/subnet counts emit regardless
TS2OTEL_CARDINALITY__WARNING_THRESHOLD2000restartstatus-page cardinality view flags a metric at/above this active-series count (self-obs only; 0 disables)
TS2OTEL_CARDINALITY__CRITICAL_THRESHOLD8000restartstatus-page cardinality view flags a metric critically at/above this count (must be >= warning_threshold; <= metric_limit when set; 0 disables)
TS2OTEL_CARDINALITY__LABEL_VALUE_SAMPLE_CAP100restartdistinct values retained per (metric,label) for the label-cardinality views; beyond it the label is capped and examples truncated (0 disables label capture)
TS2OTEL_CARDINALITY__FLOW__METRICS_MODErolluprestartrollup (bounded top-N, lowest cardinality) | all (raw per-connection) | both (≈2x series; summing double-counts)
TS2OTEL_CARDINALITY__FLOW__ROLLUP_TOP_N500restartrollup mode: busiest src/dst node pairs kept per flush; the rest fold into an other series (0 = default 500)
TS2OTEL_CARDINALITY__FLOW__SOURCE_PORTfalserestartadd source.port to flow metrics. INERT under metrics_mode: rollup (raw modes only) — and the most expensive knob here, ephemeral ports are unbounded
TS2OTEL_CARDINALITY__FLOW__DESTINATION_PORTfalserestartadd destination.port to flow metrics. INERT under metrics_mode: rollup (raw modes only); dst.service below is the bounded stand-in and is always on
TS2OTEL_CARDINALITY__FLOW__NODE_DIMStruerestartinclude src/dst device names on flow metrics (who talked to whom); off keeps totals but drops the per-peer breakdown and suppresses the unique.* gauges
TS2OTEL_CARDINALITY__FLOW__IDENTITY_DIMSfalserestartadd per-flow tailscale.{src,dst}.{user,tags,os} to flow metrics, on BOTH families. REQUIRES node_dims (identity is node-derived, so without it identity becomes the only splitting dimension); flow LOGS always carry them
TS2OTEL_CARDINALITY__FLOW__COLLAPSE_EXTERNALtruerestartbucket unresolved IPs as external/unknown (keeps cardinality bounded)
TS2OTEL_CARDINALITY__FLOW__EXIT_NODE_ATTRIBUTIONtruerestartemit bounded tailscale.exit_node.io/packets attributing exit traffic to the relaying node (bounded by exit-node count)
TS2OTEL_CARDINALITY__FLOW__GEO_DIMSfalserestartadd source/destination geo.country.iso_code + geo.continent.code to flow METRICS (needs enrichment.geoip). Nearly free under metrics_mode: rollup (top-N bounded); on the RAW families it splits the single "external" series ~250 ways. ASN/city NEVER reach a metric; flow LOGS carry everything regardless
TS2OTEL_CARDINALITY__PER_ENTITY__DEVICEtruerestartper-device gauges (online/last_seen/key_expiry/derp/routes)
TS2OTEL_CARDINALITY__PER_ENTITY__USERtruerestartper-user gauges (devices/connected/last_seen)
TS2OTEL_CARDINALITY__PER_ENTITY__KEYtruerestartper-key expiry gauge (the expiry WARN log fires regardless)
TS2OTEL_CARDINALITY__PER_ENTITY__WEBHOOKtruerestartper-endpoint webhook-subscriptions gauge
TS2OTEL_CARDINALITY__PER_ENTITY__SERVICEtruerestartper-service ports/hosts gauges
TS2OTEL_COLLECTORS__DEVICES__ENABLEDtruerestartdevice inventory — REQUIRED for flow/audit IP->name enrichment (disabling it degrades names to unknown/external)
TS2OTEL_COLLECTORS__DEVICES__INTERVAL60srestarthow often the device snapshot is polled
TS2OTEL_COLLECTORS__DEVICES__CHANGE_LOG_ENABLEDfalserestartemit structured device add/remove and field-change records. PII-bearing fields still follow pii_filter. TS2OTEL_COLLECTORS__DEVICES__CHANGE_LOG_ENABLED
TS2OTEL_COLLECTORS__DEVICES__COLLECT_ROUTESfalserestartalso fetch advertised/primary subnet routes per device
TS2OTEL_COLLECTORS__DEVICES__COLLECT_CONNECTIVITYtruerestartemit per-device NAT/connectivity health (hard_nat/endpoints/direct_capable/udp/ipv6) + fleet rollups from the device payload (no extra API calls)
TS2OTEL_COLLECTORS__DEVICES__COLLECT_POSTUREfalserestartalso fetch device posture (MDM/EDR) — enables the posture metrics + log
TS2OTEL_COLLECTORS__DEVICES__COLLECT_DEVICE_INVITEStruerestartalso fetch outstanding device share invites per device (one extra API call per device, N+1); emits tailscale.device_invites.count
TS2OTEL_COLLECTORS__DEVICES__SUBREQUEST_CONCURRENCY1restartbounded posture/invite request pool; 1 preserves sequential requests
TS2OTEL_COLLECTORS__DEVICES__POSTURE_LOG_MODEchangesrestartneeds collect_posture: changes (log only on change) | always (every scrape) | off (no log); the posture METRIC is always emitted
TS2OTEL_COLLECTORS__DEVICES__EXPIRY_LOG_MODEdailyrestartnode-key AND posture-attribute expiry WARN cadence: daily (change + at most one reminder/24h, default) | always (every scrape, legacy) | off; metrics always emit
TS2OTEL_COLLECTORS__DEVICES__ATTRIBUTE_NAMESPACES[intune, jamf, kandji, crowdstrike, sentinelone, kolide, ip]restartneeds collect_posture: posture-key namespaces promoted to attribute metrics; ["*"] = all, [] = disable (comma-separated list)
TS2OTEL_COLLECTORS__DEVICES__ATTRIBUTE_KEY_LIMIT200restartbusiest posture attribute keys promoted fleet-wide; overflow keys are dropped and counted (0/negative = unlimited); cardinality.metric_limit is still the final SDK guard
TS2OTEL_COLLECTORS__DEVICES__ATTRIBUTE_VALUE_LIMIT50restartbusiest values per attribute key on the .info gauge; overflow folds to value="other" (0/negative = unlimited)
TS2OTEL_COLLECTORS__DEVICES__COLLECT_TAG_ROLLUPtruerestartemit tailscale.devices.by_tag (one series per ACL tag); false keeps the other fleet-hygiene aggregates
TS2OTEL_COLLECTORS__DEVICES__TAG_ROLLUP_LIMIT50restartcap distinct tag series on by_tag; busiest N kept, rest fold into tag="other" (0/negative = unlimited)
TS2OTEL_COLLECTORS__FLOWLOGS__ENABLEDtruerestartnetwork flow logs -> traffic counters + per-connection logs
TS2OTEL_COLLECTORS__FLOWLOGS__SOURCEpollrestartpoll (this exporter PULLS) | stream (Tailscale PUSHES to the streaming receiver) | objectstore (read Tailscale's S3 export) | both (discouraged: double-counts)
TS2OTEL_COLLECTORS__FLOWLOGS__INTERVAL60srestartpoll only — how often a window is polled
TS2OTEL_COLLECTORS__FLOWLOGS__LAG120srestartpoll only — query only up to now-lag so late-arriving records aren't missed
TS2OTEL_COLLECTORS__FLOWLOGS__INITIAL_LOOKBACK5mrestartpoll only — cold-start reach-back when there is no checkpoint yet
TS2OTEL_COLLECTORS__FLOWLOGS__MAX_WINDOW1hrestartpoll only — cap one tick's window so a long outage catches up over several ticks
TS2OTEL_COLLECTORS__FLOWLOGS__DEDUP_CAPACITY16384restartidentities retained for poll-window AND cross-source dedup; must be >0 (unlimited would leak memory)
TS2OTEL_COLLECTORS__FLOWLOGS__REPLAY_OVERLAP5mrestartpoll only — reread this completed-window overlap for records that became available late (0 disables)
TS2OTEL_COLLECTORS__FLOWLOGS__REPLAY_SEEN_CAPACITY131072restartpoll only — durable hashed connection identities retained for overlap dedup (1..1048576 when enabled)
TS2OTEL_COLLECTORS__FLOWLOGS__TRUSTED_REPORTER_NODE_IDS[]restartverified FlowLog.NodeID values classified as configured; empty with trusted_reporter_tags means trust policy is unconfigured (comma-separated list)
TS2OTEL_COLLECTORS__FLOWLOGS__TRUSTED_REPORTER_TAGS[]restartauthoritative device tags (e.g. ["tag:router"]) classified as tagged; embedded flow tags never grant trust (comma-separated list)
TS2OTEL_COLLECTORS__FLOWLOGS__LOG_MODEper_connectionrestartper_connection | per_record | off — log detail level (applies to poll AND stream)
TS2OTEL_COLLECTORS__FLOWLOGS__MAX_LOG_RECORDS_PER_WINDOW0restartcap flow LOG records per window (0 = unlimited); excess -> tailscale.network.flow.logs_dropped (metrics are never capped)
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__ENDPOINT""restartrequired — service URL, e.g. https://s3.eu-west-2.amazonaws.com, or a MinIO/Ceph address (never derived from the region)
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__REGION""restartrequired — part of the request signature; a wrong value fails every request with HTTP 403
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__BUCKET""restartrequired — the bucket Tailscale exports into
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__PREFIX""restartthe export's root within the bucket, above the YYYY/MM/DD partitions; NO leading slash (it becomes part of this feed's durable checkpoint identity, so removing it later re-emits history)
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__LAYOUTpartitionedrestartpartitioned (Tailscale's own export: objects under prefix/YYYY/MM/DD/) | flat (a COPIED export whose self-contained YYYY-MM-DD-HH-MM-SS basenames sit directly under prefix; finds partitioned objects too, but costs more LIST requests since nothing bounds the re-walk)
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__PATH_STYLEfalserestartaddress as //; required by most non-AWS implementations
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__ALLOW_INSECURE_HTTPfalserestartremote plaintext endpoints are rejected by default; loopback HTTP remains available for local MinIO development
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__ACCESS_KEY_ID""restartSET VIA ENV ONLY. Leave empty to use the ambient chain: environment, then IRSA/web identity, then the ECS/EKS container credential endpoint, then EC2 instance profile
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__ACCESS_KEY_ID_FILE""restartread the access key ID from this path instead; value XOR file
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__SECRET_ACCESS_KEY""restartSET VIA ENV ONLY
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__SECRET_ACCESS_KEY_FILE""restartread the secret access key from this path instead; value XOR file
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__SESSION_TOKEN""restartSET VIA ENV ONLY — temporary credentials only
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__SESSION_TOKEN_FILE""restartread the temporary session token from this path instead; value XOR file
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__INTERVAL60srestarthow often the bucket is listed
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__LOOKBACK1hrestarthow far back past the cursor each listing reaches, so a late-arriving object is still found
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__INITIAL_LOOKBACK6hrestartcold-start reach-back, so a first run against a long history doesn't ingest all of it; CAPPED IN EFFECT AT 14 DAYS under layout: partitioned (a larger value silently ingests only the newest 14 day partitions — use layout: flat to reach further back)
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__MAX_OBJECTS200restartobjects ingested per cycle; the remainder is counted, logged and picked up next cycle
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__MAX_SEEN_KEYS5000restartdurable seen-object identities retained per destination; too low can re-ingest an evicted object inside the lookback
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__MAX_OBJECT_WIRE_BYTES67108864restartreject and quarantine one object requiring more than 64 MiB of GET response bytes
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__MAX_OBJECT_DECOMPRESSED_BYTES33554432restartreject and quarantine one object that expands beyond 32 MiB
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__MAX_OBJECT_RECORDS100000restartreject and quarantine one object containing more than this many records
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__MAX_CYCLE_WIRE_BYTES536870912restartdefer untouched objects after 512 MiB of GET response data in one cycle
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__MAX_CYCLE_DECOMPRESSED_BYTES268435456restartdefer untouched objects after 256 MiB of decoded data in one cycle
TS2OTEL_COLLECTORS__FLOWLOGS__OBJECTSTORE__MAX_CYCLE_RECORDS500000restartdefer untouched objects after this many decoded records in one cycle
TS2OTEL_COLLECTORS__AUDITLOGS__ENABLEDtruerestartconfiguration/audit events -> event logs + a counter
TS2OTEL_COLLECTORS__AUDITLOGS__SOURCEpollrestartpoll | stream | both | objectstore (see flowlogs)
TS2OTEL_COLLECTORS__AUDITLOGS__INTERVAL60srestartpoll only
TS2OTEL_COLLECTORS__AUDITLOGS__LAG60srestartpoll only
TS2OTEL_COLLECTORS__AUDITLOGS__INITIAL_LOOKBACK5mrestartpoll only
TS2OTEL_COLLECTORS__AUDITLOGS__MAX_WINDOW6hrestartpoll only
TS2OTEL_COLLECTORS__AUDITLOGS__DEDUP_CAPACITY4096restartidentities retained for poll-window AND audit/webhook cross-source dedup; must be >0
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__ENDPOINT""restartrequired — service URL, e.g. https://s3.eu-west-2.amazonaws.com, or a MinIO/Ceph address (never derived from the region)
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__REGION""restartrequired — part of the request signature; a wrong value fails every request with HTTP 403
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__BUCKET""restartrequired — the bucket Tailscale exports configuration logs into
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__PREFIX""restartthe export's root within the bucket, above the YYYY/MM/DD partitions; use a distinct prefix when flow and configuration logs share one bucket. NO leading slash (see flowlogs)
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__LAYOUTpartitionedrestartpartitioned (Tailscale's own export: objects under prefix/YYYY/MM/DD/) | flat (a COPIED export whose self-contained YYYY-MM-DD-HH-MM-SS basenames sit directly under prefix; finds partitioned objects too, but costs more LIST requests since nothing bounds the re-walk)
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__PATH_STYLEfalserestartaddress as //; required by most non-AWS implementations
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__ALLOW_INSECURE_HTTPfalserestartremote plaintext endpoints are rejected by default; loopback HTTP remains available for local MinIO development
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__ACCESS_KEY_ID""restartSET VIA ENV ONLY. Leave empty to use the ambient chain: environment, then IRSA/web identity, then the ECS/EKS container credential endpoint, then EC2 instance profile
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__ACCESS_KEY_ID_FILE""restartread the access key ID from this path instead; value XOR file
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__SECRET_ACCESS_KEY""restartSET VIA ENV ONLY
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__SECRET_ACCESS_KEY_FILE""restartread the secret access key from this path instead; value XOR file
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__SESSION_TOKEN""restartSET VIA ENV ONLY — temporary credentials only
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__SESSION_TOKEN_FILE""restartread the temporary session token from this path instead; value XOR file
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__INTERVAL60srestarthow often the bucket is listed
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__LOOKBACK1hrestarthow far back past the cursor each listing reaches, so a late-arriving object is still found
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__INITIAL_LOOKBACK6hrestartcold-start reach-back, so a first run against a long history doesn't ingest all of it; CAPPED IN EFFECT AT 14 DAYS under layout: partitioned (a larger value silently ingests only the newest 14 day partitions — use layout: flat to reach further back)
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__MAX_OBJECTS200restartobjects ingested per cycle; the remainder is counted, logged and picked up next cycle
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__MAX_SEEN_KEYS5000restartdurable seen-object identities retained per destination
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__MAX_OBJECT_WIRE_BYTES67108864restartreject and quarantine one object requiring more than 64 MiB of GET response bytes
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__MAX_OBJECT_DECOMPRESSED_BYTES33554432restartreject and quarantine one object that expands beyond 32 MiB
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__MAX_OBJECT_RECORDS100000restartreject and quarantine one object containing more than this many records
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__MAX_CYCLE_WIRE_BYTES536870912restartdefer untouched objects after 512 MiB of GET response data in one cycle
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__MAX_CYCLE_DECOMPRESSED_BYTES268435456restartdefer untouched objects after 256 MiB of decoded data in one cycle
TS2OTEL_COLLECTORS__AUDITLOGS__OBJECTSTORE__MAX_CYCLE_RECORDS500000restartdefer untouched objects after this many decoded records in one cycle
TS2OTEL_COLLECTORS__K8S_AUDIT__ENABLEDfalserestartKubernetes API-audit events from Tailscale's tsrecorder -> request logs + bounded counters. Requires enableEvents in the tailscale.com/cap/kubernetes ACL grant (BETA upstream). NOTE: the source carries no response status, latency or byte count, so allowed-vs-denied and error rates are NOT derivable
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__ENDPOINT""restartrequired — service URL, e.g. https://s3.eu-west-1.amazonaws.com, or a MinIO/Ceph address
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__REGION""restartrequired — part of the request signature; a wrong value fails every request with HTTP 403
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__BUCKET""restartrequired — the bucket tsrecorder writes recordings into. Never inherited from the flowlogs/auditlogs destinations: this is a separate bucket with its own key layout
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__PREFIX""restartusually EMPTY: tsrecorder keys are /events/.event and /.cast, and differs per recorder replica so it cannot be pinned in a prefix. NO leading slash
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__LAYOUTrecorderrestartrecorder is the only accepted value here; partitioned and flat are REFUSED because tsrecorder writes no YYYY/MM/DD partitions and its RFC3339Nano basenames sort differently
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__PATH_STYLEfalserestartaddress as //; required by most non-AWS implementations
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__ALLOW_INSECURE_HTTPfalserestartremote plaintext endpoints are rejected by default; loopback HTTP remains available for local MinIO development
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__ACCESS_KEY_ID""restartSET VIA ENV ONLY. Leave empty to use the ambient chain: environment, then IRSA/web identity, then the ECS/EKS container credential endpoint, then EC2 instance profile
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__ACCESS_KEY_ID_FILE""restartread the access key ID from this path instead; value XOR file
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__SECRET_ACCESS_KEY""restartSET VIA ENV ONLY
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__SECRET_ACCESS_KEY_FILE""restartread the secret access key from this path instead; value XOR file
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__SESSION_TOKEN""restartSET VIA ENV ONLY — temporary credentials only
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__SESSION_TOKEN_FILE""restartread the temporary session token from this path instead; value XOR file
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__INTERVAL60srestarthow often the bucket is listed
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__LOOKBACK1hrestarthow far back past the cursor each listing reaches, so a late-arriving object is still found
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__INITIAL_LOOKBACK6hrestartcold-start reach-back, so a first run against a long history doesn't ingest all of it
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__MAX_OBJECTS200restartobjects ingested per cycle; the remainder is counted, logged and picked up next cycle. tsrecorder writes ONE event per object, so a busy cluster needs a higher value here than a flow/audit export does
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__MAX_SEEN_KEYS5000restartdurable seen-object identities retained per destination
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__MAX_OBJECT_WIRE_BYTES67108864restartreject and quarantine one object requiring more than 64 MiB of GET response bytes
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__MAX_OBJECT_DECOMPRESSED_BYTES33554432restartreject and quarantine one object that expands beyond 32 MiB. RAISE THIS if you record long terminal sessions: only the .cast header line is read for meaning, but the whole object is still streamed, and an oversized one is quarantined rather than partially read
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__MAX_OBJECT_RECORDS100000restartreject and quarantine one object containing more than this many records
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__MAX_CYCLE_WIRE_BYTES536870912restartdefer untouched objects after 512 MiB of GET response data in one cycle
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__MAX_CYCLE_DECOMPRESSED_BYTES268435456restartdefer untouched objects after 256 MiB of decoded data in one cycle
TS2OTEL_COLLECTORS__K8S_AUDIT__OBJECTSTORE__MAX_CYCLE_RECORDS500000restartdefer untouched objects after this many decoded records in one cycle
TS2OTEL_COLLECTORS__USERS__ENABLEDtruerestartuser inventory (devices/connected/last_seen per user)
TS2OTEL_COLLECTORS__USERS__INTERVAL300srestartuser inventory (devices/connected/last_seen per user)
TS2OTEL_COLLECTORS__KEYS__ENABLEDtruerestartauth-key inventory + expiry warnings
TS2OTEL_COLLECTORS__KEYS__INTERVAL300srestartauth-key inventory + expiry warnings
TS2OTEL_COLLECTORS__KEYS__EXPIRY_WARN168hrestartlog a WARN when a key expires within this window (default 7d)
TS2OTEL_COLLECTORS__KEYS__EXPIRY_LOG_MODEdailyrestartWARN cadence: daily (change + at most one reminder/24h, default) | always (every scrape, legacy) | off; metrics always emit
TS2OTEL_COLLECTORS__SETTINGS__ENABLEDtruerestarttailnet settings snapshot
TS2OTEL_COLLECTORS__SETTINGS__INTERVAL600srestarttailnet settings snapshot
TS2OTEL_COLLECTORS__SETTINGS__SNAPSHOT_ENABLEDfalserestartemit the complete settings response to logs on change plus a heartbeat. TS2OTEL_COLLECTORS__SETTINGS__SNAPSHOT_ENABLED
TS2OTEL_COLLECTORS__PAM__ENABLEDfalserestartrequires a read-only service-account token in TS2OTEL_PAM__TOKEN
TS2OTEL_COLLECTORS__PAM__INTERVAL600srestartconnector/service/policy/identity/org inventory and config-shape interval
TS2OTEL_COLLECTORS__PAM__SESSIONS_INTERVAL60srestartincremental newest-first session polling interval
TS2OTEL_COLLECTORS__PAM__SESSION_LOG_ENABLEDfalserestartemit newly observed authorized sessions as logs under pii_filter; grant-layer denials produce no record
TS2OTEL_COLLECTORS__PAM__SNAPSHOT_ENABLEDfalserestartopt in to redacted PAM configuration snapshots; secrets are stripped before serialization
TS2OTEL_COLLECTORS__PAM__SNAPSHOT_HEARTBEAT24hrestartrefresh unchanged snapshots at this cadence
TS2OTEL_COLLECTORS__PAM__SNAPSHOT_BODY_BYTES32768restartmaximum serialized snapshot event body
TS2OTEL_COLLECTORS__ACL__ENABLEDtruerestartACL policy snapshot
TS2OTEL_COLLECTORS__ACL__INTERVAL600srestartACL policy snapshot
TS2OTEL_COLLECTORS__ACL__SNAPSHOT_ENABLEDfalserestartEXPLICIT PII CONSENT: ship the raw policy and diffs, including every user email and group member, to the logs backend. This overrides pii_filter for those bodies, so logs retention holds tailnet identity data. TS2OTEL_COLLECTORS__ACL__SNAPSHOT_ENABLED
TS2OTEL_COLLECTORS__ACL__SNAPSHOT_HEARTBEAT24hrestartrefresh an unchanged raw policy snapshot at this cadence. TS2OTEL_COLLECTORS__ACL__SNAPSHOT_HEARTBEAT
TS2OTEL_COLLECTORS__ACL__VALIDATEtruerestartrun the non-mutating POST /acl/validate (policy_file:read scope) each tick; set false to keep the client strictly GET-only
TS2OTEL_COLLECTORS__DNS__ENABLEDtruerestartDNS/MagicDNS settings snapshot
TS2OTEL_COLLECTORS__DNS__INTERVAL600srestartDNS/MagicDNS settings snapshot
TS2OTEL_COLLECTORS__DNS__SNAPSHOT_ENABLEDfalserestartemit the complete DNS response to logs on change plus a heartbeat. TS2OTEL_COLLECTORS__DNS__SNAPSHOT_ENABLED
TS2OTEL_COLLECTORS__CONTACTS__ENABLEDtruerestartaccount/support/security contact verification status (no emails emitted)
TS2OTEL_COLLECTORS__CONTACTS__INTERVAL600srestartaccount/support/security contact verification status (no emails emitted)
TS2OTEL_COLLECTORS__WEBHOOKS__ENABLEDtruerestartwebhook-endpoint inventory: count + per-endpoint subscription count (no url/secret)
TS2OTEL_COLLECTORS__WEBHOOKS__INTERVAL600srestartwebhook-endpoint inventory: count + per-endpoint subscription count (no url/secret)
TS2OTEL_COLLECTORS__WEBHOOKS__SNAPSHOT_ENABLEDfalserestartemit the complete webhook inventory response to logs on change plus a heartbeat. TS2OTEL_COLLECTORS__WEBHOOKS__SNAPSHOT_ENABLED
TS2OTEL_COLLECTORS__WEBHOOKS__DESIRED_EVENTS[]restartoptional expected event categories (e.g. ["nodeCreated","userSuspended"]); empty means no expectation (comma-separated list)
TS2OTEL_COLLECTORS__POSTURE_INTEGRATIONS__ENABLEDtruerestartMDM/EDR posture-integration sync health: matched counts + last_sync staleness
TS2OTEL_COLLECTORS__POSTURE_INTEGRATIONS__INTERVAL600srestartMDM/EDR posture-integration sync health: matched counts + last_sync staleness
TS2OTEL_COLLECTORS__POSTURE_INTEGRATIONS__SNAPSHOT_ENABLEDfalserestartemit the complete posture-integration response to logs on change plus a heartbeat. TS2OTEL_COLLECTORS__POSTURE_INTEGRATIONS__SNAPSHOT_ENABLED
TS2OTEL_COLLECTORS__LOG_STREAM__ENABLEDtruerestartlog-streaming delivery health to a SIEM sink (self-gates to configured=0 when no sink)
TS2OTEL_COLLECTORS__LOG_STREAM__INTERVAL600srestartlog-streaming delivery health to a SIEM sink (self-gates to configured=0 when no sink)
TS2OTEL_COLLECTORS__LOG_STREAM__CONFIGURATION_INTERVAL0srestart0 inherits interval; otherwise probe configuration-log delivery independently
TS2OTEL_COLLECTORS__LOG_STREAM__NETWORK_INTERVAL0srestart0 inherits interval; otherwise probe network-log delivery independently
TS2OTEL_COLLECTORS__OAUTH_APPS__ENABLEDtruerestartOAuth-application inventory (alpha API; idles silently — no error — on tailnets without it)
TS2OTEL_COLLECTORS__OAUTH_APPS__INTERVAL300srestartOAuth-application inventory (alpha API; idles silently — no error — on tailnets without it)
TS2OTEL_COLLECTORS__SERVICES__ENABLEDtruerestartTailscale Services (VIP) inventory
TS2OTEL_COLLECTORS__SERVICES__INTERVAL600srestartTailscale Services (VIP) inventory
TS2OTEL_COLLECTORS__SERVICES__COLLECT_HOSTSfalserestartalso fetch per-service backing-host detail — one extra API call per service (N+1)
TS2OTEL_COLLECTORS__SERVICES__SUBREQUEST_CONCURRENCY1restartbounded backing-host request pool; 1 preserves sequential requests
TS2OTEL_COLLECTORS__SERVICES__COLLECT_TAG_ROLLUPtruerestartemit tailscale.services.by_tag (one series per ACL tag); false disables the rollup
TS2OTEL_COLLECTORS__SERVICES__TAG_ROLLUP_LIMIT50restartcap distinct service-tag series; busiest N kept, rest fold into tailscale.tag="other" (0/negative = unlimited)
TS2OTEL_COLLECTORS__NODE_METRICS__ENABLEDfalserestartOPTIONAL: scrape tailscaled per-node Prometheus /metrics and forward them centrally. Off by default; see docs/node-metrics.md
TS2OTEL_COLLECTORS__NODE_METRICS__INTERVAL60srestarthow often each target is scraped
TS2OTEL_COLLECTORS__NODE_METRICS__TIMEOUT10srestartper-scrape HTTP timeout
TS2OTEL_COLLECTORS__NODE_METRICS__MAX_RESPONSE_BYTES4194304restartper-target response cap (4 MiB) — bounds memory
TS2OTEL_COLLECTORS__NODE_METRICS__MAX_SAMPLES50000restartper-target sample cap per scrape — bounds cardinality
TS2OTEL_COLLECTORS__NODE_METRICS__MAX_DISTINCT_METRICS2000restartcap on DISTINCT forwarded metric NAMES over the process lifetime (targets choose their own names and each new one creates a permanent instrument); 0 = 2000 default, negative = unlimited (over-budget names are dropped and counted)
TS2OTEL_COLLECTORS__NODE_METRICS__METRIC_ALLOW[]restartif non-empty, only forwarded metric names matching one of these anchored regexes are kept (comma-separated list)
TS2OTEL_COLLECTORS__NODE_METRICS__METRIC_DENY[]restartforwarded metric names matching any of these anchored regexes are dropped (after allow) (comma-separated list)
TS2OTEL_COLLECTORS__NODE_METRICS__DROP_LABELS[]restartlabel keys stripped from every forwarded series (the tailscale.node identity label is never dropped) (comma-separated list)
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__ENABLEDfalserestartOPTIONAL: discover scrape targets from the Tailscale devices API (unioned with static targets)
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__INTERVAL5mrestarthow often the device inventory is re-scanned for targets
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__MAX_TARGETS1000restartcap emitted discovered targets per refresh (one target per selected port, not one per device)
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__SCHEMEhttprestarthttp | https — metrics endpoint scheme on each device
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__PORT5252restarttailscaled client-metrics port
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__PATH/metricsrestartmetrics endpoint path
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__ONLINE_ONLYtruerestartonly devices currently connected to the control plane
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__EXCLUDE_EXTERNALtruerestartskip shared/external devices
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__INCLUDE_TAGS[]restartonly devices with one of these tags (empty = all), e.g. ["tag:server"] (comma-separated list)
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__EXCLUDE_TAGS[]restartdevices with any of these tags are skipped (wins over include_tags) (comma-separated list)
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__ADDRESS_ORDERipv4restartipv4 | ipv6 — preferred address family (falls back to the other)
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__INSTANCE_SOURCEnamerestartidentity label per target: name (MagicDNS short name, unique+friendly — default) | address (Tailscale host:port, always unique) | hostname (OS hostname, NOT unique — collisions like "localhost" are auto-suffixed)
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__INCLUDE_HOST_LABELStruerestartattach host.name/host.id for joins with tailscale.device.*
TS2OTEL_COLLECTORS__NODE_METRICS__DISCOVERY__INCLUDE_TAGS_LABELtruerestartattach tailscale.tags to each target's series
TS2OTEL_SCHEDULER__INITIAL_STAGGER_WINDOW3srestartspread initial collector ticks; current single-runtime default is 3s
TS2OTEL_COORDINATION__MODEnonerestartnone (default singleton behavior) | kubernetes (Lease-based active-passive)
TS2OTEL_COORDINATION__LEASE_NAMEtailscale2otelrestartDNS-1123 Lease name; all replicas use the same name
TS2OTEL_COORDINATION__NAMESPACEdefaultrestartDNS-1123 namespace containing the Lease
TS2OTEL_COORDINATION__LEASE_DURATION15srestartleader lease expiry; must be > renew_deadline > retry_period
TS2OTEL_COORDINATION__RENEW_DEADLINE10srestartstep down when the apiserver cannot renew within this period
TS2OTEL_COORDINATION__RETRY_PERIOD2srestartstandby acquire and leader renew retry interval
TS2OTEL_CHECKPOINT__STOREfilerestartfile (persists window cursors across restarts; falls back to memory + WARN if the path isn't writable) | memory (RAM only; cold-starts from initial_lookback after a restart) | kubernetes (one gzip binaryData ConfigMap per collector namespace, owned by coordination.lease_name)
TS2OTEL_CHECKPOINT__EVIDENCE_STOREfilerestartfile (default; preserves ACL revision/audit provenance across restarts) | memory (unsafe except disposable runs; produces a specific warning). Independent of store, so streamed deployments may use store: memory with evidence_store: file.
TS2OTEL_CHECKPOINT__FILE_PATH/var/lib/tailscale2otel/checkpoints.jsonrestartused when either store is file — both file-backed classes share this atomic JSON file, preserving existing checkpoint keys. Mount a writable, persistent path here. This default suits a CONTAINER (the image pre-seeds it for uid 65532); a native run that cannot write it falls back to the platform state dir (~/.local/state, ~/Library/Application Support, %LocalAppData%) and logs where it went. Set this explicitly and it is used as-is — an explicit path is never relocated.
TS2OTEL_CHECKPOINT__WRITE_DEBOUNCE0srestartcoalesce nearby file writes; 0 preserves synchronous Set durability
TS2OTEL_INGRESS_WAL__ENABLEDfalserestartopt in to durable local acceptance and oldest-first replay for receiver payloads
TS2OTEL_INGRESS_WAL__DIRECTORY/var/lib/tailscale2otel/ingress-walrestartabsolute, filepath-clean, non-root directory; mount durable state here when reschedule survival matters
TS2OTEL_INGRESS_WAL__MAX_BYTES268435456restartencoded WAL byte ceiling (256 MiB); full WAL fails new requests closed; no TTL/eviction
TS2OTEL_INGRESS_WAL__MAX_ENTRIES10000restartencoded entry ceiling; full WAL fails new requests closed; no TTL/eviction
TS2OTEL_INGRESS_WAL__CORRUPTIONfailrestartonly supported mode: fail closed rather than discard corrupt state
TS2OTEL_STREAMING__ENABLEDfalserestartrun the Splunk-HEC receiver to INGEST pushed logs (set the relevant collectors' source: stream)
TS2OTEL_STREAMING__LISTEN:8088restartbind address for the Splunk-HEC-compatible receiver
TS2OTEL_STREAMING__PATH/services/collector/eventrestartHEC endpoint path Tailscale POSTs to
TS2OTEL_STREAMING__TOKEN""restartshared secret; Tailscale sends HTTP Basic auth (base64 user:token), "Authorization: Splunk " also accepted as a fallback (set via TS2OTEL_STREAMING__TOKEN); REQUIRED when enabled on a non-loopback bind (loopback may remain credential-free for local-only use)
TS2OTEL_STREAMING__TOKEN_FILE""file_contentread the value from this file instead (Docker secrets); set the value or the file, not both; content is whitespace-trimmed
TS2OTEL_STREAMING__PUBLIC_URL""restartexternally reachable receiver URL; REQUIRED only when auto_configure: true
TS2OTEL_STREAMING__TLS__CERT_FILE""file_contentHTTPS cert (Tailscale requires HTTPS; a tailscale cert works for private endpoints)
TS2OTEL_STREAMING__TLS__KEY_FILE""file_contentHTTPS key
TS2OTEL_STREAMING__DECOMPRESSautorestartauto | gzip | zstd | none — request body decompression
TS2OTEL_STREAMING__AUTO_CONFIGUREfalserestarton startup, register THIS receiver as the tailnet's log-streaming sink for BOTH log types (network/flow AND configuration/audit), OVERWRITING any existing sink for either; needs enabled + public_url + the log_streaming OAuth scope
TS2OTEL_STREAMING__MAX_BODY_BYTES0restartcap on the DECOMPRESSED body; 0 = 64 MiB default, negative = unlimited (over-cap = 413); when ingress_wal.enabled this receiver must set a positive value <= 64 MiB
TS2OTEL_STREAMING__MAX_CONCURRENT_REQUESTS0restarthow many requests may buffer a body AT ONCE (max_body_bytes caps one body, this caps their sum); 0 = 4 default, negative = unlimited (over-limit = 503 + Retry-After)
TS2OTEL_STREAMING__PER_ROUTE_MAX_CONCURRENT_REQUESTS0restartper-tailnet admission cap; 0 selects an automatic fair share of the global budget
TS2OTEL_WEBHOOK__ENABLEDfalserestartrun the receiver for real-time Tailscale webhook events
TS2OTEL_WEBHOOK__LISTEN:8089restartbind address for the webhook receiver
TS2OTEL_WEBHOOK__PATH/tailscale/webhookrestartendpoint path Tailscale POSTs events to
TS2OTEL_WEBHOOK__SECRET""restartHMAC-SHA256 verification secret (set via TS2OTEL_WEBHOOK__SECRET); REQUIRED when enabled on a non-loopback bind (loopback may remain credential-free for local-only use)
TS2OTEL_WEBHOOK__SECRET_FILE""file_contentread the value from this file instead (Docker secrets); set the value or the file, not both; content is whitespace-trimmed
TS2OTEL_WEBHOOK__TLS__CERT_FILE""file_contentserve native HTTPS when paired with key_file; leave both empty behind an HTTPS reverse proxy
TS2OTEL_WEBHOOK__TLS__KEY_FILE""file_contentprivate key paired with cert_file; both paths are validated as readable at startup
TS2OTEL_WEBHOOK__TOLERANCE5mrestartreject signed timestamps older than this (replay window); "0" disables the check
TS2OTEL_WEBHOOK__DEDUP_AUDIT_EVENTSfalserestartbest-effort: drop a webhook event already counted via the audit logs
TS2OTEL_WEBHOOK__MAX_BODY_BYTES0restartcap on the raw body read before signature verification; 0 = 1 MiB default, negative = unlimited (over-cap = 413); when ingress_wal.enabled this receiver must set a positive value <= 64 MiB
TS2OTEL_WEBHOOK__MAX_CONCURRENT_REQUESTS0restarthow many requests may buffer a body AT ONCE, BEFORE the HMAC is checked (max_body_bytes caps one body, this caps their sum); 0 = 4 default, negative = unlimited (over-limit = 503 + Retry-After)
TS2OTEL_WEBHOOK__PER_ROUTE_MAX_CONCURRENT_REQUESTS0restartper-tailnet admission cap; 0 selects an automatic fair share of the global budget
TS2OTEL_PII_FILTER__EMAILStruerestartuser/actor login names (often email addresses)
TS2OTEL_PII_FILTER__USER_DISPLAY_NAMEStruerestartactor display (human) names
TS2OTEL_PII_FILTER__USER_IDStruerestartnumeric/opaque user IDs (user.id)
TS2OTEL_PII_FILTER__HOSTNAMEStruerestartdevice + collector-host hostnames
TS2OTEL_PII_FILTER__NODE_IDStruerestartTailscale node IDs
TS2OTEL_PII_FILTER__TAILSCALE_IPStruerestart100.64.0.0/10 + fd7a:115c:a1e0::/48 addresses
TS2OTEL_PII_FILTER__INTERNAL_IPStruerestartRFC1918 / ULA / link-local addresses
TS2OTEL_PII_FILTER__EXTERNAL_IPStruerestartpublic/routable addresses
TS2OTEL_PII_FILTER__SERVICE_ADDRStruerestartVIP service names and optional display names
TS2OTEL_PII_FILTER__ENDPOINT_PATHStruerestartTailscale API endpoint paths (self-obs)
TS2OTEL_PII_FILTER__NETWORK_TOPOLOGYtruerestartroute CIDRs + split-DNS domains + search paths
TS2OTEL_PII_FILTER__TAILNET_NAMEtruerestarttailnet identifier
TS2OTEL_PII_FILTER__FREE_TEXT_DETAILStruerestartaudit old/new/details, target names, key descriptions, posture values
TS2OTEL_PII_FILTER__COMMAND_TEXTtruerestartverbatim commands on Kubernetes-audit and opt-in PAM session logs; can carry pasted secrets. Turning it off KEEPS the bounded tailscale.k8s.command_class classification the exec metrics are built on
TS2OTEL_SELF_OBSERVABILITY__ENABLEDtruerestartemit tailscale2otel.up, api.requests, runtime metrics, etc.
TS2OTEL_SELF_OBSERVABILITY__INSTANCE_ID""restartservice.instance.id resource attr; empty => host name. Set via env, e.g. TS2OTEL_SELF_OBSERVABILITY__INSTANCE_ID=$POD_NAME
TS2OTEL_ADMIN__ENABLEDtruerestartrun the admin HTTP server (probes + status page + optional pprof mount)
TS2OTEL_ADMIN__LISTEN127.0.0.1:9091restartserves /healthz, /readyz, and the status page. Loopback by default: the status page is REFUSED (403) on a network-reachable bind without admin.auth.token, so widen this only together with a token
TS2OTEL_ADMIN__LANDING_PAGEtruerestartserve the human status page at / and machine-readable /api/status.json
TS2OTEL_ADMIN__STATUS_REFRESH_INTERVAL5srestarthow often the status page re-polls /api/status.json (1s freshness ticker is independent)
TS2OTEL_ADMIN__SUPPORT_BUNDLE_LOG_TAIL_RECORDS200restartbounded redaction-safe recent log records included in support bundles; 0 disables capture
TS2OTEL_ADMIN__AUTH__TOKEN""restartgate the status page + pprof behind this token (set via TS2OTEL_ADMIN__AUTH__TOKEN); empty is allowed only on a loopback listen — on any other bind the status page + JSON APIs are REFUSED with 403 (/healthz and /readyz stay open)
TS2OTEL_ADMIN__AUTH__TOKEN_FILE""file_contentread the value from this file instead (Docker secrets); set the value or the file, not both; content is whitespace-trimmed
TS2OTEL_ADMIN__AUTH__FAILURE_LIMIT5restartfailures from one source inside failure_window before throttling; 0 disables
TS2OTEL_ADMIN__AUTH__FAILURE_WINDOW1mrestartrolling window for failed authentication attempts
TS2OTEL_ADMIN__AUTH__FAILURE_BACKOFF30srestartthrottle duration after the per-source limit is reached
TS2OTEL_ADMIN__TLS__CERT_FILE""file_contentserve the admin listener over HTTPS instead of plain HTTP; set together with key_file (both-or-neither)
TS2OTEL_ADMIN__TLS__KEY_FILE""file_contentHTTPS key for admin.tls.cert_file
TS2OTEL_ADMIN__TLS__CLIENT_CA_FILE""file_contentrequire a client certificate signed by this CA; needs cert_file/key_file
TS2OTEL_ADMIN__TLS__CLIENT_AUTH""restartrequire_and_verify by default when client_ca_file is set; same modes as prometheus.tls
TS2OTEL_FLOWS__ENABLEDtruerestartkeep a bounded, in-memory picture of recent traffic and serve /flows; needs admin.enabled + admin.landing_page (no effect otherwise)
TS2OTEL_FLOWS__RETENTION6hrestarthow far back /flows can see, as one-minute buckets (1m–24h). Memory scales with this, and with the number of tailnets in multi-tailnet mode. Lost on restart — OTLP stays the system of record
TS2OTEL_FLOWS__MAX_FUTURE_SKEW5mrestartlocal-view admission only: reject records further ahead of this process clock (0–1h); OTLP emission is unchanged
TS2OTEL_FLOWS__CAPACITY_PROFILEdefaultrestarttrade memory for fidelity on every per-bucket dimension + the raw-connection ring: compact (~half), default (unchanged), or expanded (~double). Fixed, hard-coded presets only — never a raw number
TS2OTEL_FLOWS__STORE__DIRECTORY""restartOPTIONAL, opt-in: a directory for the on-disk /flows backend (internal/flowstore/sqlitestore). Empty (default) is memory-only. Relative paths resolve against this config file, like ingress_wal.directory. Setting this writes flow rows, including user identities, to disk — they then survive restarts and land in backups
TS2OTEL_FLOWS__STORE__RETENTION720hrestarthow far back the on-disk store keeps rows (1h–8760h/365d), independent of flows.retention which still only sizes the in-memory ring. Only takes effect once directory is set
TS2OTEL_FLOWS__STORE__MAX_ROWS5000000restarthard cap on retained rows (10000–1000000000), enforced independently of retention so a traffic flood cannot fill the disk before the next sweep. Only takes effect once directory is set
TS2OTEL_FLOWS__STORE__MAX_EXPORT_ROWS50000restartcap on rows a single CSV/JSON export may read (100–1000000), so a large window cannot be materialized into memory in one request. Only takes effect once directory is set
TS2OTEL_FLOWS__STORE__QUEUE_SIZE8192restartbound on the write-behind queue between Record and the disk writer (64–1048576); a full queue drops and counts rather than blocking. Only takes effect once directory is set
TS2OTEL_FLOWS__STORE__BATCH_SIZE512restartrows committed per write transaction (1–100000); must not exceed queue_size. Only takes effect once directory is set
TS2OTEL_FLOWS__STORE__FLUSH_INTERVAL5srestartforce a partial batch to disk on this timer (100ms–5m) so a quiet tailnet's last few rows do not sit in memory indefinitely. Only takes effect once directory is set
TS2OTEL_FLOWS__STORE__QUERY_TIMEOUT15srestartgive up a single read against the store after this long (1s–5m) rather than hang the admin page. Only takes effect once directory is set
TS2OTEL_FLOWS__STORE__SWEEP_INTERVAL1hrestarthow often retention and the row cap are enforced (1m–24h). Only takes effect once directory is set
TS2OTEL_FLOWS__STORE__INCREMENTAL_VACUUM_INTERVAL0srestartperiodic SQLite page reclamation; 0 inherits sweep_interval
TS2OTEL_FLOWS__STORE__INCREMENTAL_VACUUM_PAGES1000restartmaximum pages reclaimed per vacuum tick
TS2OTEL_EVENTS__ENABLEDtruerestartkeep a bounded, in-memory ring of recent audit/webhook events and serve /events; needs admin.enabled + admin.landing_page (no effect otherwise)
TS2OTEL_EVENTS__MAX_EVENTS5000restarthow many individual events /events can see (100–100000). A plain count, not a time span — oldest evicted first. Lost on restart — OTLP stays the system of record
TS2OTEL_PROMETHEUS__ENABLEDfalserestartbackwards-compatible pull opt-in alongside OTLP; delivery.mode prometheus or dual also enables it
TS2OTEL_PROMETHEUS__LISTEN127.0.0.1:2112restartbind for /metrics (default loopback-only 127.0.0.1:2112); keep distinct from admin.listen
TS2OTEL_PROMETHEUS__AUTH__TOKEN""restartgate /metrics behind this token (Bearer or Basic password); empty + a network bind = REFUSED 403 unless allow_unauthenticated. Set via TS2OTEL_PROMETHEUS__AUTH__TOKEN
TS2OTEL_PROMETHEUS__AUTH__TOKEN_FILE""file_contentread the value from this file instead (Docker secrets); set the value or the file, not both; content is whitespace-trimmed
TS2OTEL_PROMETHEUS__AUTH__ALLOW_UNAUTHENTICATEDfalserestartacknowledge serving /metrics with NO token on a network-reachable bind (e.g. in-cluster scraping behind a NetworkPolicy); a loopback bind never needs this
TS2OTEL_PROMETHEUS__MAX_REQUESTS_IN_FLIGHT4restartcap concurrent /metrics gathers (excess gets 503); must be positive while Prometheus is enabled
TS2OTEL_PROMETHEUS__TIMEOUT8srestartgive up on a single /metrics gather after this long (503); keep below the scraper's own timeout
TS2OTEL_PROMETHEUS__COALESCE_GATHERtruerestartserve overlapping scrapes from the same in-flight gather (bounds duplicate work; costs slight staleness)
TS2OTEL_PROMETHEUS__TLS__CERT_FILE""file_contentserve the Prometheus /metrics listener over HTTPS instead of plain HTTP; set together with key_file (both-or-neither)
TS2OTEL_PROMETHEUS__TLS__KEY_FILE""file_contentHTTPS key for prometheus.tls.cert_file
TS2OTEL_PROMETHEUS__TLS__CLIENT_CA_FILE""restartrequire scrapers to present a client certificate signed by this CA (mTLS); needs cert_file/key_file, composes with auth.token
TS2OTEL_PROMETHEUS__TLS__CLIENT_AUTH""restarthow hard to check the client cert: require_and_verify (default when client_ca_file set)|verify_if_given|require|request|none
TS2OTEL_PROFILING__PPROF__ENABLEDfalserestartmount net/http/pprof on the admin server (REQUIRES admin.enabled + admin.auth.token — heap dumps can expose in-memory secrets)
TS2OTEL_PROFILING__PYROSCOPE__ENABLEDfalserestartrun the Pyroscope continuous-profiling push agent
TS2OTEL_PROFILING__PYROSCOPE__SERVER_ADDRESS""restartREQUIRED when enabled, e.g. http://pyroscope:4040 or https://profiles-prod-NNN.grafana.net
TS2OTEL_PROFILING__PYROSCOPE__BASIC_AUTH_USER""restartGrafana Cloud: the profiles instance ID (set via TS2OTEL_PROFILING__PYROSCOPE__BASIC_AUTH_USER)
TS2OTEL_PROFILING__PYROSCOPE__BASIC_AUTH_PASSWORD""restartGrafana Cloud: a profiles:write access-policy token (..._BASIC_AUTH_PASSWORD)
TS2OTEL_PROFILING__PYROSCOPE__BASIC_AUTH_PASSWORD_FILE""restartread the value from this file instead (Docker secrets); set the value or the file, not both; content is whitespace-trimmed
TS2OTEL_PROFILING__PYROSCOPE__TENANT_ID""restartX-Scope-OrgID for multi-tenant servers (leave empty for Grafana Cloud)
TS2OTEL_PROFILING__PYROSCOPE__UPLOAD_RATE60srestarthow often profiles are flushed
TS2OTEL_PROFILING__PYROSCOPE__TLS__INSECURE_SKIP_VERIFYfalserestartkeep TLS but skip server-certificate verification — a footgun; prefer ca_file
TS2OTEL_PROFILING__PYROSCOPE__TLS__CA_FILE""file_contentPEM bundle of the CA to trust for the profiles endpoint (private CA / self-signed gateway)
TS2OTEL_PROFILING__PYROSCOPE__TLS__CERT_FILE""file_contentclient certificate for mTLS to the profiles endpoint; set together with key_file (both-or-neither)
TS2OTEL_PROFILING__PYROSCOPE__TLS__KEY_FILE""file_contentclient key for profiling.pyroscope.tls.cert_file
TS2OTEL_PROFILING__PYROSCOPE__TAILNET_LABELoffrestartoff | hashed | name — whether continuous profiles carry a tailnet dimension. A tailnet name is a CUSTOMER identifier and profiles go to a different destination from metrics/logs, so this is opt-in and NOT covered by pii_filter. hashed = a stable 12-hex SHA-256 prefix (answers "which tenant is burning CPU" for an MSP without shipping the name; pseudonymous, not anonymous — a small name space is enumerable). Emitted only for a single configured tailnet; multi-tailnet gets no tag, since there is one profiler per process. TS2OTEL_PROFILING__PYROSCOPE__TAILNET_LABEL
TS2OTEL_PROFILING__PYROSCOPE__SPAN_PROFILES__ENABLEDfalserestartREQUIRES tracing.enabled AND profiling.pyroscope.enabled. CPU profiles ONLY — Go attaches pprof labels to CPU samples, so heap/mutex/block/goroutine profiles cannot carry span identity
TS2OTEL_PROFILING__PYROSCOPE__CREDENTIAL_RELOAD__ENABLEDfalserestartgoverns the background poller only
TS2OTEL_PROFILING__PYROSCOPE__CREDENTIAL_RELOAD__INTERVAL30srestartpoll period; minimum 5s. Ignored when enabled is false
TS2OTEL_PROFILING__MUTEX_PROFILE_FRACTION5restartruntime.SetMutexProfileFraction; on by default (applied only when pprof or pyroscope is enabled), 0 = disabled
TS2OTEL_PROFILING__BLOCK_PROFILE_RATE100000restartruntime.SetBlockProfileRate (ns); on by default (100µs), 0 = disabled
TS2OTEL_TRACING__ENABLEDfalserestartemit spans. TS2OTEL_TRACING__ENABLED
TS2OTEL_TRACING__SAMPLERparentbased_always_onrestarthead sampler: always_on|always_off|traceidratio|parentbased_always_on|parentbased_traceidratio. TS2OTEL_TRACING__SAMPLER
TS2OTEL_TRACING__SAMPLER_ARG1.0restartsample ratio in [0,1] for the *traceidratio samplers (ignored otherwise). TS2OTEL_TRACING__SAMPLER_ARG
TS2OTEL_TRACING__REMOTE_PARENTtrustrestarthow an INBOUND traceparent's sampled bit is treated by the stream/webhook receivers: trust (today's behavior) | ignore (the local sampler alone decides, so a sender cannot force sampling) | link (start a new local root trace and link the remote one). TS2OTEL_TRACING__REMOTE_PARENT
TS2OTEL_TRACING__SAMPLERS__SCRAPE__SAMPLER""restartsame enum as tracing.sampler. TS2OTEL_TRACING__SAMPLERS__SCRAPE__SAMPLER
TS2OTEL_TRACING__SAMPLERS__SCRAPE__ARG0.0restartratio in [0,1] for the *traceidratio samplers. TS2OTEL_TRACING__SAMPLERS__SCRAPE__ARG
TS2OTEL_TRACING__SAMPLERS__RECEIVER__SAMPLER""restartTS2OTEL_TRACING__SAMPLERS__RECEIVER__SAMPLER
TS2OTEL_TRACING__SAMPLERS__RECEIVER__ARG0.0restartTS2OTEL_TRACING__SAMPLERS__RECEIVER__ARG
TS2OTEL_TRACING__SAMPLERS__BACKGROUND__SAMPLER""restartTS2OTEL_TRACING__SAMPLERS__BACKGROUND__SAMPLER
TS2OTEL_TRACING__SAMPLERS__BACKGROUND__ARG0.0restartTS2OTEL_TRACING__SAMPLERS__BACKGROUND__ARG
TS2OTEL_RESOURCE__SERVICE_NAMESPACE""restartservice.namespace — promoted to a job-adjacent LABEL on every series. Keep it low-cardinality and stable across deploys. TS2OTEL_RESOURCE__SERVICE_NAMESPACE
TS2OTEL_RESOURCE__DEPLOYMENT_ENVIRONMENT""restartdeployment.environment.name — outside service.*, so it lands in target_info only and may vary per environment. TS2OTEL_RESOURCE__DEPLOYMENT_ENVIRONMENT
TS2OTEL_RESOURCE__FROM_ENVfalserestartalso read OTEL_RESOURCE_ATTRIBUTES / OTEL_SERVICE_NAME, filtered by the same rules. Off by default: it hands the ambient environment a channel onto a per-series label surface. TS2OTEL_RESOURCE__FROM_ENV
TS2OTEL_VERSION_CHECKS__SELF__ENABLEDtruerestartemit tailscale2otel.update_available (running build vs latest tailscale2otel GitHub release)
TS2OTEL_VERSION_CHECKS__DEVICES__ENABLEDtruerestartemit per-device tailscale.device.version_skew + fleet rollups (device client version vs latest Tailscale stable). Needs the devices collector.
TS2OTEL_VERSION_CHECKS__DEVICES__OUTDATED_MINOR_THRESHOLD3restarta device this many minor releases behind counts toward tailscale.devices.outdated
TS2OTEL_VERSION_CHECKS__CACHE_TTL1hrestarthow long a fetched "latest version" is cached before re-fetching (minimum 5m)
TS2OTEL_VERSION_CHECKS__TIMEOUT10srestartper-request timeout for the external version fetch
TS2OTEL_GRAFANA_ANNOTATIONS__URL""restartGrafana base URL, e.g. https://mystack.grafana.net. Setting it IS the opt-in; empty = feature off entirely. TS2OTEL_GRAFANA_ANNOTATIONS__URL
TS2OTEL_GRAFANA_ANNOTATIONS__TOKEN""restartGrafana service-account token (needs annotations:create and nothing else). Keep it in env/file, never in YAML. TS2OTEL_GRAFANA_ANNOTATIONS__TOKEN
TS2OTEL_GRAFANA_ANNOTATIONS__TOKEN_FILE""restartpath to a file holding the token (Docker/k8s secret mount). Value XOR file — setting both is a config error. TS2OTEL_GRAFANA_ANNOTATIONS__TOKEN_FILE
TS2OTEL_GRAFANA_ANNOTATIONS__DASHBOARD_UID""restartconfine annotations to ONE dashboard. Empty (default) writes organization annotations, visible on every board and in Explore — which is the point of pushing them. TS2OTEL_GRAFANA_ANNOTATIONS__DASHBOARD_UID
TS2OTEL_GRAFANA_ANNOTATIONS__TIMEOUT10srestartper-request timeout for POST /api/annotations. TS2OTEL_GRAFANA_ANNOTATIONS__TIMEOUT
TS2OTEL_GRAFANA_ANNOTATIONS__MAX_PER_MINUTE60restarttoken-bucket CEILING on annotations written per process. Overage is dropped and counted, never delayed — a marker arriving after the moment it explains is worse than absent. TS2OTEL_GRAFANA_ANNOTATIONS__MAX_PER_MINUTE
TS2OTEL_GRAFANA_ANNOTATIONS__QUEUE_SIZE512restarthand-off buffer between the collector goroutines and the single publisher. A full queue drops and counts rather than blocking collection. TS2OTEL_GRAFANA_ANNOTATIONS__QUEUE_SIZE
TS2OTEL_GRAFANA_ANNOTATIONS__ROLLUP_INTERVAL5mrestartbucket width for rolled-up categories: one region annotation per interval per category per tailnet, instead of one marker per event. TS2OTEL_GRAFANA_ANNOTATIONS__ROLLUP_INTERVAL
TS2OTEL_GRAFANA_ANNOTATIONS__DEDUPE_RETENTION48hrestarthow long a published annotation's dedupe key is remembered, so a restart cannot republish it. Must comfortably exceed the longest source overlap window. TS2OTEL_GRAFANA_ANNOTATIONS__DEDUPE_RETENTION
TS2OTEL_GRAFANA_ANNOTATIONS__STATE_FILE""restartwhere the dedupe set persists. Empty = annotations.json beside checkpoint.file_path. Deliberately NOT inside the checkpoint file, which the window pollers rewrite every tick. TS2OTEL_GRAFANA_ANNOTATIONS__STATE_FILE
TS2OTEL_GRAFANA_ANNOTATIONS__EXTRA_TAGS[]restartextra tags added to every annotation, e.g. [env:prod]. Every annotation already carries tailscale2otel, category: and rule:. TS2OTEL_GRAFANA_ANNOTATIONS__EXTRA_TAGS (comma-separated list)
TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__CONFIG_CHANGE__ENABLEDtruerestartACL edits, device approval and churn, key lifecycle, user role changes, DNS and tailnet settings — the curated audit-log subset. Needs collectors.auditlogs. TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__CONFIG_CHANGE__ENABLED
TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__CONFIG_CHANGE__ROLLUPtruerestarthighest-volume category: rolled up by default so a busy tailnet draws a timeline rather than a picket fence. TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__CONFIG_CHANGE__ROLLUP
TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__EXPIRY__ENABLEDtruerestarta node key or auth key entering its expiry warning window — the marker that explains a device count stepping down. Needs collectors.keys / collectors.devices. TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__EXPIRY__ENABLED
TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__EXPIRY__ROLLUPtruerestarta fresh deployment finds every currently-expiring key at once, and one summary beats fifty markers at the same instant. TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__EXPIRY__ROLLUP
TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__POLICY_CHANGE__ENABLEDtruerestartACL revision and policy-diff markers from the policy snapshot family. TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__POLICY_CHANGE__ENABLED
TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__POLICY_CHANGE__ROLLUPfalserestartpolicy changes are rare and individually meaningful. TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__POLICY_CHANGE__ROLLUP
TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__INVENTORY__ENABLEDtruerestartdevice additions, removals and material field changes. TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__INVENTORY__ENABLED
TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__INVENTORY__ROLLUPtruerestartdevice churn can be high-volume; summarize it into one region per interval. TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__INVENTORY__ROLLUP
TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__RISK__ENABLEDtruerestartnewly observed ACL, SSH and auto-approver risk findings. TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__RISK__ENABLED
TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__RISK__ROLLUPfalserestarteach new risk finding remains individually visible. TS2OTEL_GRAFANA_ANNOTATIONS__CATEGORIES__RISK__ROLLUP