Skip to main content

Configuration

OSAPI is configured through a YAML file and optional environment variable overrides.

Config File

By default OSAPI looks for /etc/osapi/osapi.yaml. Override the path with the -f / --osapi-file flag:

osapi -f /path/to/osapi.yaml api server start

Environment Variables

Every config key can be overridden with an environment variable using the OSAPI_ prefix. Dots and nested keys become underscores, and the name is uppercased:

Config KeyEnvironment Variable
debugOSAPI_DEBUG
api.server.portOSAPI_API_SERVER_PORT
api.server.nats.hostOSAPI_API_SERVER_NATS_HOST
api.server.nats.portOSAPI_API_SERVER_NATS_PORT
api.server.nats.client_nameOSAPI_API_SERVER_NATS_CLIENT_NAME
api.server.nats.namespaceOSAPI_API_SERVER_NATS_NAMESPACE
api.server.nats.auth.typeOSAPI_API_SERVER_NATS_AUTH_TYPE
api.server.security.signing_keyOSAPI_API_SERVER_SECURITY_SIGNING_KEY
api.client.security.bearer_tokenOSAPI_API_CLIENT_SECURITY_BEARER_TOKEN
nats.server.hostOSAPI_NATS_SERVER_HOST
nats.server.portOSAPI_NATS_SERVER_PORT
nats.server.namespaceOSAPI_NATS_SERVER_NAMESPACE
nats.server.auth.typeOSAPI_NATS_SERVER_AUTH_TYPE
nats.stream.nameOSAPI_NATS_STREAM_NAME
nats.kv.bucketOSAPI_NATS_KV_BUCKET
nats.kv.response_bucketOSAPI_NATS_KV_RESPONSE_BUCKET
nats.audit.bucketOSAPI_NATS_AUDIT_BUCKET
nats.audit.ttlOSAPI_NATS_AUDIT_TTL
nats.audit.max_bytesOSAPI_NATS_AUDIT_MAX_BYTES
nats.audit.storageOSAPI_NATS_AUDIT_STORAGE
nats.audit.replicasOSAPI_NATS_AUDIT_REPLICAS
nats.registry.bucketOSAPI_NATS_REGISTRY_BUCKET
nats.registry.ttlOSAPI_NATS_REGISTRY_TTL
nats.registry.storageOSAPI_NATS_REGISTRY_STORAGE
nats.registry.replicasOSAPI_NATS_REGISTRY_REPLICAS
telemetry.tracing.enabledOSAPI_TELEMETRY_TRACING_ENABLED
telemetry.tracing.exporterOSAPI_TELEMETRY_TRACING_EXPORTER
telemetry.tracing.otlp_endpointOSAPI_TELEMETRY_TRACING_OTLP_ENDPOINT
agent.nats.hostOSAPI_AGENT_NATS_HOST
agent.nats.portOSAPI_AGENT_NATS_PORT
agent.nats.client_nameOSAPI_AGENT_NATS_CLIENT_NAME
agent.nats.namespaceOSAPI_AGENT_NATS_NAMESPACE
agent.nats.auth.typeOSAPI_AGENT_NATS_AUTH_TYPE
agent.hostnameOSAPI_AGENT_HOSTNAME

Environment variables take precedence over file values.

Required Fields

Two fields carry a required validation tag and must be set before the server or client will start:

KeyPurpose
api.server.security.signing_keyHS256 key for signing JWTs
api.client.security.bearer_tokenJWT sent with client requests

Generate a signing key with openssl rand -hex 32. Generate a bearer token with osapi token generate.

Authentication

Each NATS connection supports pluggable authentication. Set the auth.type field in the relevant section (nats.server, api.server.nats, or agent.nats):

TypeDescriptionExtra Fields
noneNo authentication (default)
user_passUsername and passwordusername, password
nkeyNKey-based auth (server and clients)See examples below

Server-Side Auth

The embedded NATS server (nats.server.auth) accepts a list of users or nkeys:

nats:
server:
auth:
type: user_pass
users:
- username: osapi
password: '<secret>'

Client-Side Auth

API server and agent connections (api.server.nats.auth, agent.nats.auth) authenticate as a single identity:

api:
server:
nats:
auth:
type: user_pass
username: osapi
password: '<secret>'

Permissions

OSAPI uses fine-grained resource:verb permissions for access control. Each API endpoint requires a specific permission. Built-in roles expand to a default set of permissions:

RolePermissions
adminagent:read, node:read, network:read, network:write, job:read, job:write, health:read, audit:read, command:execute
writeagent:read, node:read, network:read, network:write, job:read, job:write, health:read
readagent:read, node:read, network:read, job:read, health:read

Custom Roles

You can define custom roles in the api.server.security.roles section. Custom roles override the default permission mapping for the same name, or define entirely new role names:

api:
server:
security:
roles:
ops:
permissions:
- node:read
- health:read
netadmin:
permissions:
- network:read
- network:write
- health:read

Direct Permissions

Tokens can carry a permissions claim that overrides role-based expansion. When the claim is present, only the listed permissions are granted regardless of the token's roles. Generate a token with direct permissions:

osapi token generate -r admin -u user@example.com \
-p node:read -p health:read

Namespace

The namespace field on NATS connections prefixes all subject names and infrastructure names. This allows multiple OSAPI deployments to share a single NATS cluster without collisions.

Without namespaceWith namespace: osapi
jobs.query._anyosapi.jobs.query._any
JOBS (stream)osapi-JOBS
job-queue (KV bucket)osapi-job-queue

Set the same namespace value in nats.server.namespace, api.server.nats.namespace, and agent.nats.namespace so all components agree on naming. An empty string disables prefixing.

Full Reference

Below is a complete osapi.yaml with every supported field and inline comments. Values shown are representative defaults from the repository's config file.

# Enable verbose logging.
debug: true

api:
client:
# Base URL the CLI client connects to.
url: 'http://0.0.0.0:8080'
security:
# JWT bearer token for client requests (REQUIRED).
# Generate with: osapi token generate
bearer_token: '<jwt>'

server:
# Port the REST API server listens on.
port: 8080
nats:
# NATS server hostname for the API server.
host: 'localhost'
# NATS server port for the API server.
port: 4222
# Client name sent to NATS for identification.
client_name: 'osapi-api'
# Subject namespace prefix. Must match nats.server.namespace.
namespace: 'osapi'
auth:
# Authentication type: "none", "user_pass", or "nkey".
type: 'none'
security:
# HS256 signing key for JWT validation (REQUIRED).
# Generate with: openssl rand -hex 32
signing_key: '<secret>'
cors:
# Origins allowed to make cross-origin requests.
# An empty list disables CORS headers entirely.
allow_origins:
- 'http://localhost:3001'
- 'https://osapi-io.github.io'
# Custom roles with fine-grained permissions.
# Permissions: agent:read, node:read, network:read, network:write,
# job:read, job:write, health:read, audit:read,
# command:execute
# roles:
# ops:
# permissions:
# - node:read
# - health:read

nats:
server:
# Hostname the embedded NATS server binds to.
host: 'localhost'
# Port the embedded NATS server binds to.
port: 4222
# Directory for JetStream file-based storage.
store_dir: '.nats/jetstream/'
# Subject namespace prefix for server-created infrastructure.
namespace: 'osapi'
auth:
# Authentication type: "none", "user_pass", or "nkey".
type: 'none'
# Users for user_pass auth (server-side only).
# users:
# - username: osapi
# password: '<secret>'
# NKeys for nkey auth (server-side only).
# nkeys:
# - '<public-nkey>'

# ── JetStream stream ──────────────────────────────────────
stream:
# JetStream stream name for job notifications.
name: 'JOBS'
# Subject filter for the stream.
subjects: 'jobs.>'
# Maximum age of messages in the stream (Go duration).
max_age: '24h'
# Maximum number of messages retained.
max_msgs: 10000
# Storage backend: "file" or "memory".
storage: 'file'
# Number of stream replicas (1 for single-node).
replicas: 1
# Discard policy when limits are reached: "old" or "new".
discard: 'old'

# ── KV bucket settings ────────────────────────────────────
kv:
# KV bucket for immutable job definitions and status events.
bucket: 'job-queue'
# KV bucket for agent result storage.
response_bucket: 'job-responses'
# TTL for KV entries (Go duration).
ttl: '1h'
# Maximum total size of the bucket in bytes.
max_bytes: 104857600 # 100 MiB
# Storage backend: "file" or "memory".
storage: 'file'
# Number of KV replicas.
replicas: 1

# ── Audit log KV bucket ──────────────────────────────────
audit:
# KV bucket for audit log entries.
bucket: 'audit-log'
# TTL for audit entries (Go duration). Default 30 days.
ttl: '720h'
# Maximum total size of the audit bucket in bytes.
max_bytes: 52428800 # 50 MiB
# Storage backend: "file" or "memory".
storage: 'file'
# Number of KV replicas.
replicas: 1

# ── Agent registry KV bucket ──────────────────────────────
registry:
# KV bucket for agent heartbeat registration.
bucket: 'agent-registry'
# TTL for registry entries (Go duration). Agents refresh
# every 10s; the TTL acts as a liveness timeout.
ttl: '30s'
# Storage backend: "file" or "memory".
storage: 'file'
# Number of KV replicas.
replicas: 1

# ── Dead Letter Queue ─────────────────────────────────────
dlq:
# Maximum age of messages in the DLQ.
max_age: '7d'
# Maximum number of messages retained.
max_msgs: 1000
# Storage backend: "file" or "memory".
storage: 'file'
# Number of DLQ replicas.
replicas: 1

telemetry:
tracing:
# Enable distributed tracing (default: false).
enabled: false
# Exporter type: "stdout" or "otlp".
# exporter: stdout
# gRPC endpoint for OTLP exporter (e.g., Jaeger, Tempo).
# otlp_endpoint: localhost:4317

agent:
nats:
# NATS server hostname for the agent.
host: 'localhost'
# NATS server port for the agent.
port: 4222
# Client name sent to NATS for identification.
client_name: 'osapi-agent'
# Subject namespace prefix. Must match nats.server.namespace.
namespace: 'osapi'
auth:
# Authentication type: "none", "user_pass", or "nkey".
type: 'none'
consumer:
# Durable consumer name.
name: 'jobs-agent'
# Maximum redelivery attempts before sending to DLQ.
max_deliver: 5
# Time to wait for an ACK before redelivering.
ack_wait: '2m'
# Maximum outstanding unacknowledged messages.
max_ack_pending: 1000
# Replay policy: "instant" or "original".
replay_policy: 'instant'
# Backoff durations between redelivery attempts.
back_off:
- '30s'
- '2m'
- '5m'
- '15m'
- '30m'
# Queue group for load-balanced (_any) subscriptions.
queue_group: 'job-agents'
# Agent hostname for direct routing. Defaults to the
# system hostname when empty.
hostname: ''
# Maximum number of concurrent jobs to process.
max_jobs: 10
# Key-value labels for label-based routing.
# Values can be hierarchical with dot separators.
# See Job System Architecture for details.
labels:
group: 'web.dev.us-east'

Section Reference

api.client

KeyTypeDescription
urlstringBase URL the CLI client targets
security.bearer_tokenstringJWT for client auth (required)

api.server

KeyTypeDescription
portintPort the API server listens on
nats.hoststringNATS server hostname
nats.portintNATS server port
nats.client_namestringNATS client identification name
nats.namespacestringSubject namespace prefix
nats.auth.typestringAuth type: none, user_pass
nats.auth.usernamestringUsername for user_pass auth
nats.auth.passwordstringPassword for user_pass auth
security.signing_keystringHS256 JWT signing key (required)
security.cors.allow_origins[]stringAllowed CORS origins
security.rolesmapCustom roles with permissions lists

nats.server

KeyTypeDescription
hoststringHostname the NATS server binds to
portintPort the NATS server binds to
store_dirstringDirectory for JetStream file storage
namespacestringNamespace prefix for infrastructure
auth.typestringAuth type: none, user_pass
auth.userslistUsers for user_pass auth (see below)
auth.nkeyslistPublic nkeys for nkey auth

nats.stream

KeyTypeDescription
namestringJetStream stream name
subjectsstringSubject filter for the stream
max_agestringMaximum message age (Go duration)
max_msgsintMaximum number of messages
storagestring"file" or "memory"
replicasintNumber of stream replicas
discardstringDiscard policy: "old" or "new"

nats.kv

KeyTypeDescription
bucketstringKV bucket for job definitions and events
response_bucketstringKV bucket for agent results
ttlstringEntry time-to-live (Go duration)
max_bytesintMaximum bucket size in bytes
storagestring"file" or "memory"
replicasintNumber of KV replicas

nats.audit

KeyTypeDescription
bucketstringKV bucket for audit log entries
ttlstringEntry time-to-live (Go duration)
max_bytesintMaximum bucket size in bytes
storagestring"file" or "memory"
replicasintNumber of KV replicas

nats.registry

KeyTypeDescription
bucketstringKV bucket for agent heartbeat entries
ttlstringEntry time-to-live / liveness timeout
storagestring"file" or "memory"
replicasintNumber of KV replicas

nats.dlq

KeyTypeDescription
max_agestringMaximum message age (Go duration)
max_msgsintMaximum number of messages
storagestring"file" or "memory"
replicasintNumber of DLQ replicas

telemetry.tracing

KeyTypeDescription
enabledboolEnable distributed tracing (default: false)
exporterstring"stdout", "otlp", or unset (log correlation only, no span export)
otlp_endpointstringgRPC endpoint for OTLP exporter (required when exporter is "otlp")

agent

KeyTypeDescription
nats.hoststringNATS server hostname
nats.portintNATS server port
nats.client_namestringNATS client identification name
nats.namespacestringSubject namespace prefix
nats.auth.typestringAuth type: none, user_pass
nats.auth.usernamestringUsername for user_pass auth
nats.auth.passwordstringPassword for user_pass auth
consumer.namestringDurable consumer name
consumer.max_deliverintMax redelivery attempts before DLQ
consumer.ack_waitstringACK timeout (Go duration)
consumer.max_ack_pendingintMax outstanding unacknowledged msgs
consumer.replay_policystring"instant" or "original"
consumer.back_off[]stringBackoff durations between redeliveries
queue_groupstringQueue group for load-balanced routing
hostnamestringAgent hostname (defaults to OS hostname)
max_jobsintMax concurrent jobs
labelsmap[string]stringKey-value pairs for label-based routing