Skip to content

Configuration

Team Server reads config/production.yaml. Container deployments mount it at /app/config/production.yaml.

Environment Variable Templates

Use Tera environment templates for credentials:

database:
  uri: "<%= get_env(name='DATABASE_URL') %>"
server:
  host: "<%= get_env(name='SERVER_URL') %>"

Missing variables without defaults stop startup. Replace deprecated {{ get_env(...) }} delimiters with <%= and %>; old syntax warns and can be damaged by YAML formatters.

Standard Sections

Logger

logger:
  enable: true
  pretty_backtrace: false
  level: info
  format: compact
SettingValues
enableEnable or disable application logging
pretty_backtraceEnable formatted Rust backtraces
leveltrace, debug, info, warn, or error
formatcompact, pretty, or json
override_filterOptional filter that includes third-party library logs

Server

server:
  binding: 0.0.0.0
  port: 5150
  host: "<%= get_env(name='SERVER_URL') %>"
  middlewares:
    compression:
      enable: true
    cors:
      enable: true
      allow_origins:
        - "<%= get_env(name='SERVER_URL') %>"
      allow_headers: ["*"]
      allow_methods: ["*"]
      expose_headers: ["x-total-count"]
    fallback:
      enable: false
    limit_payload:
      body_limit: 5mb
    logger:
      enable: true
    secure_headers:
      enable: true
      preset: github
      overrides:
        "Content-Security-Policy": "default-src 'self'; script-src 'self' 'sha256-HvYZHxmCfa13ffpFFfnqlSwYhOKQhnA3t3xMKSF0QsE='; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'"
    static:
      enable: true
      must_exist: false
      folder:
        uri: "/"
        path: "public"
      fallback: "public/index.html"
    timeout_request:
      enable: true
      timeout: 30000
SettingPurpose
binding, portListener address and port
hostPublic URL used by the application
corsBrowser origins, methods, and exposed headers
limit_payloadMaximum request body size
secure_headersCSP, HSTS, MIME, and framing headers
staticTeam Server frontend files
timeout_requestRequest timeout in milliseconds

Set secure_headers.enable: true; a preset alone is insufficient. Use the deployed release’s CSP script hash or the frontend may fail to load.

Login, logout, and browser-session changes require an Origin matching settings.tenant.base_url, regardless of CORS. See origin rules.

Database

Team Server requires PostgreSQL in production:

database:
  uri: "<%= get_env(name='DATABASE_URL') %>"
  enable_logging: false
  connect_timeout: 1500
  idle_timeout: 500
  min_connections: 1
  max_connections: 1
  auto_migrate: true
  dangerously_truncate: false
  dangerously_recreate: false

Use a URI in this form:

postgresql://username:password@hostname:5432/database

auto_migrate: true runs startup migrations. Keep dangerously_* false outside disposable databases. Size the pool for database limits and workload. Helm uses one instance because workers/scheduler lack leader election.

Workers

workers:
  mode: BackgroundAsync
ModeBehavior
BackgroundAsyncProcess asynchronous work in the background; recommended
BackgroundQueueProcess queued work in the background
ForegroundBlockingProcess work synchronously

Email, Slack, and Microsoft Teams notifications, plus other background work, require a functioning worker mode.

Scheduler

Schedules use seven fields: second minute hour day month day-of-week year.

scheduler:
  output: stdout
  jobs:
    statistics_calculate:
      run: "statistics_calculate"
      schedule: "0 0 1 * * * *"
    status_reconcile:
      run: "status_reconcile"
      schedule: "0 */5 * * * * *"
    github_pipelines:
      run: "github_sync mode:pipelines trigger:scheduled"
      schedule: "0 2 * * * * *"
    github_builds:
      run: "github_sync mode:builds trigger:scheduled"
      schedule: "0 3,18,33,48 * * * * *"
    log_prune:
      run: "log_prune confirm:true"
      schedule: "0 30 2 * * * *"

statistics_calculate and status_reconcile are required and must remain enabled. Keep log_prune confirm:true enabled to enforce the retention periods configured in Administration > Log Settings. Add both synchronization jobs for each configured CI/CD provider:

ProviderPipeline jobBuild job
Bamboobamboo_sync mode:pipelines trigger:scheduledbamboo_sync mode:builds trigger:scheduled
GitHubgithub_sync mode:pipelines trigger:scheduledgithub_sync mode:builds trigger:scheduled
GitLabgitlab_sync mode:pipelines trigger:scheduledgitlab_sync mode:builds trigger:scheduled
Jenkinsjenkins_sync mode:pipelines trigger:scheduledjenkins_sync mode:builds trigger:scheduled
Kojikoji_sync mode:pipelines trigger:scheduledkoji_sync mode:builds trigger:scheduled
TeamCityteamcity_sync mode:pipelines trigger:scheduledteamcity_sync mode:builds trigger:scheduled

Without id, sync jobs process every provider integration; with none configured, they do no work.

Administrative Settings

Manage retention, Days Until Stale, and Build Discovery Hours in Administration, not this YAML. Retention pruning covers application logs, submitted Sensor logs, and terminal discovery history; it does not delete policies, builds, violations, or host-local logs. See recency calculations.

Application Settings

Outbound HTTP Policy

Outbound OIDC and integration requests deny private, loopback, link-local, and other reserved addresses by default and trust the public web PKI. This policy also applies to SMTP relay resolution. Allow only the internal networks used by private identity providers, self-hosted CI/CD systems, or SMTP relays, and add internal certificate authorities when required:

settings:
  http:
    allowed_networks:
      - "10.20.0.0/16"
      - "192.168.50.14"
    ca_certificates:
      - "config/corporate-ca.pem"
SettingPurpose
allowed_networksCIDRs or individual addresses exempt from the reserved-address block
ca_certificatesPEM bundles trusted in addition to public roots

Other reserved ranges stay blocked. The policy includes OIDC discovery, keys, and token exchange. Invalid networks/CA bundles stop startup. Mount CAs and use container paths relative to /app.

Credential Encryption

Every Team Server process, including local tasks, needs ENDURA_CREDENTIAL_ENCRYPTION_KEY to encrypt stored integration credentials. Generate exactly 32 bytes in standard base64:

openssl rand -base64 32

Store it outside production.yaml. Missing/invalid keys or unreadable stored credentials prevent startup.

Existing databases with plaintext credentials cannot be upgraded yet

Earlier plaintext integration credentials cannot be converted: startup fails even with a valid key. Keep the earlier release until conversion is supported. New databases and databases without plaintext credentials can start.

For rotation, put earlier keys in ENDURA_CREDENTIAL_ENCRYPTION_PREVIOUS_KEYS, comma-separated, same format, without spaces, empty entries, or duplicates. Startup validates every credential and atomically re-encrypts old-key values. Remove previous keys only after successful credential validation.

JWT

Team Server signs Runtime Sensor and user tokens with separate secrets:

settings:
  jwt:
    sensor:
      secret: "<%= get_env(name='JWT_SENSOR_SECRET') %>"
      expiration: 31557600
    user:
      secret: "<%= get_env(name='JWT_USER_SECRET') %>"
      expiration: 604800

Each value must be base64 that decodes to at least 32 bytes, and the values must differ. Team Server refuses to start otherwise. Generate them separately:

openssl rand -base64 48
openssl rand -base64 48

Changing a secret invalidates tokens signed with its previous value.

Tenant

settings:
  tenant:
    name: "<%= get_env(name='TENANT_NAME') %>"
    base_url: "<%= get_env(name='SERVER_URL') %>"

name appears in the UI, email tests, and alerts. Public base_url drives Slack callbacks, Teams messaging endpoints, alert links, browser Origin checks, and cookie security. Teams requires publicly reachable HTTPS with a trusted certificate.

TLS

To terminate TLS in Team Server:

settings:
  tls:
    certificate: "/run/secrets/server_cert"
    private_key: "/run/secrets/server_key"

Both files must be PEM encoded and readable by the Team Server process. Set SERVER_URL to https://....

For ingress/proxy TLS, omit settings.tls and keep public SERVER_URL on HTTPS. HTTPS tenant URLs add Secure cookies; HttpOnly and SameSite=Lax always apply. No cookie rewriting is needed.

Authentication

Configure at least one OIDC provider for production. Users authenticate first and receive the Viewer role; permissions are then managed through Access Control.

Built-in Username and Password

Set both variables to enable the built-in account:

ENDURA_AUTH_USERNAME=developer
ENDURA_AUTH_PASSWORD=replace-me

Use this single login only for development/testing. First login creates an unscoped Viewer with email <username>@localhost; promote it using the deployment guide’s first-Administrator procedure.

OpenID Connect

All providers share this structure:

settings:
  oidc:
    google:
      client_id: "<%= get_env(name='GOOGLE_OIDC_CLIENT_ID') %>"
      client_secret: "<%= get_env(name='GOOGLE_OIDC_CLIENT_SECRET') %>"
      issuer_url: "https://accounts.google.com"
      redirect_url: "<%= get_env(name='SERVER_URL') %>/api/authentication/google/callback"
      scopes: [openid, email, profile]
      domains:
        - example.com
SettingRequirement
client_idOIDC client identifier
client_secretOIDC client secret
issuer_urlProvider issuer URL
redirect_urlExact callback registered with the provider
scopesInclude openid, email, and profile
domainsOne or more email domains allowed to sign in

Providers must support authorization code response/grant types, RS256 ID tokens, client_secret_basic, and S256 PKCE (fresh per login). Include openid, email, and profile for identity claims; omitted openid is added automatically.

Metadata comes from {issuer_url}/.well-known/openid-configuration; its issuer must match exactly. Issuer and discovered authorization/token/key endpoints require HTTPS; discovery/key/token requests cannot redirect. Configure outbound policy for private providers/CAs.

The callback path always includes /api:

https://team-server.example.com/api/authentication/{provider}/callback

Supported provider keys and typical issuer URLs are:

Provider keyIssuer URL
googlehttps://accounts.google.com
microsofthttps://login.microsoftonline.com/{tenant-id}/v2.0
cyberarkYour CyberArk Identity tenant issuer
oracleYour OCI IAM identity-domain issuer

For Oracle, the discovery document’s issuer must equal the configured identity-domain URL. If the domain uses Oracle’s default https://identity.oraclecloud.com/ issuer, configure an identity-domain custom issuer with the same identity-domain prefix before using that URL as issuer_url.

Register the provider-specific callback, store the client secret outside the YAML file, and list every email domain that should be allowed to authenticate.

Production Example

This example contains the core configuration and Google OIDC. Add the synchronization jobs and identity providers your deployment uses.

logger:
  enable: true
  pretty_backtrace: false
  level: info
  format: compact

scheduler:
  output: stdout
  jobs:
    statistics_calculate:
      run: "statistics_calculate"
      schedule: "0 0 1 * * * *"
    status_reconcile:
      run: "status_reconcile"
      schedule: "0 */5 * * * * *"
    log_prune:
      run: "log_prune confirm:true"
      schedule: "0 30 2 * * * *"

server:
  binding: 0.0.0.0
  port: 5150
  host: "<%= get_env(name='SERVER_URL') %>"
  middlewares:
    compression:
      enable: true
    cors:
      enable: true
      allow_origins:
        - "<%= get_env(name='SERVER_URL') %>"
      allow_headers: ["*"]
      allow_methods: ["*"]
      expose_headers: ["x-total-count"]
    fallback:
      enable: false
    limit_payload:
      body_limit: 5mb
    logger:
      enable: true
    secure_headers:
      enable: true
      preset: github
      overrides:
        "Content-Security-Policy": "default-src 'self'; script-src 'self' 'sha256-HvYZHxmCfa13ffpFFfnqlSwYhOKQhnA3t3xMKSF0QsE='; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'"
    static:
      enable: true
      must_exist: false
      folder:
        uri: "/"
        path: "public"
      fallback: "public/index.html"
    timeout_request:
      enable: true
      timeout: 30000

database:
  uri: "<%= get_env(name='DATABASE_URL') %>"
  enable_logging: false
  connect_timeout: 1500
  idle_timeout: 500
  min_connections: 1
  max_connections: 1
  auto_migrate: true
  dangerously_truncate: false
  dangerously_recreate: false

workers:
  mode: BackgroundAsync

settings:
  jwt:
    sensor:
      secret: "<%= get_env(name='JWT_SENSOR_SECRET') %>"
      expiration: 31557600
    user:
      secret: "<%= get_env(name='JWT_USER_SECRET') %>"
      expiration: 604800
  tenant:
    name: "<%= get_env(name='TENANT_NAME') %>"
    base_url: "<%= get_env(name='SERVER_URL') %>"
  oidc:
    google:
      client_id: "<%= get_env(name='GOOGLE_OIDC_CLIENT_ID') %>"
      client_secret: "<%= get_env(name='GOOGLE_OIDC_CLIENT_SECRET') %>"
      issuer_url: "https://accounts.google.com"
      redirect_url: "<%= get_env(name='SERVER_URL') %>/api/authentication/google/callback"
      scopes: [openid, email, profile]
      domains:
        - example.com

Required Environment Variables

VariablePurpose
DATABASE_URLPostgreSQL connection URI
ENDURA_CREDENTIAL_ENCRYPTION_KEYCurrent 32-byte credential-encryption key, encoded with standard base64
ENDURA_LICENSE_KEYTeam Server license
JWT_SENSOR_SECRETRuntime Sensor token-signing secret
JWT_USER_SECRETUser-token signing secret
SERVER_URLPublic Team Server URL
TENANT_NAMEOrganization name

Add the client ID and client secret variables referenced by each configured OIDC provider. ENDURA_CREDENTIAL_ENCRYPTION_PREVIOUS_KEYS is optional and used only while rotating the credential-encryption key.