Configuration
Team Server reads config/production.yaml. Container deployments mount it at /app/config/production.yaml.
Environment Variable Templates
Use Tera templates to keep credentials outside the YAML file:
database:
uri: "<%= get_env(name='DATABASE_URL') %>"
server:
host: "<%= get_env(name='SERVER_URL', default='http://localhost:5150') %>"An unset variable without a default stops startup. The older {{ get_env(...) }} syntax still renders but logs a deprecation warning and can be corrupted by YAML formatters. Replace {{ and }} with <%= and %>.
Standard Sections
Logger
logger:
enable: true
pretty_backtrace: false
level: info
format: compact| Setting | Values |
|---|---|
enable | Enable or disable application logging |
pretty_backtrace | Enable formatted Rust backtraces |
level | trace, debug, info, warn, or error |
format | compact, pretty, or json |
override_filter | Optional 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'; 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| Setting | Purpose |
|---|---|
binding, port | Listener address and port |
host | Public URL used by the application |
cors | Browser origins, methods, and exposed headers |
limit_payload | Maximum request body size |
secure_headers | CSP, HSTS, MIME, and framing headers |
static | Team Server frontend files |
timeout_request | Request timeout in milliseconds |
secure_headers.preset does not enable the middleware by itself. Set enable: true.
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: falseUse a URI in this form:
postgresql://username:password@hostname:5432/databaseauto_migrate: true applies database migrations during startup. Keep both dangerously_* settings false outside disposable development databases. Size the connection pool for the database limit and the number of Team Server replicas.
Workers
workers:
mode: BackgroundAsync| Mode | Behavior |
|---|---|
BackgroundAsync | Process asynchronous work in the background; recommended |
BackgroundQueue | Process queued work in the background |
ForegroundBlocking | Process work synchronously |
Notifications and 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:
calculate_statistics:
run: "calculate_statistics"
schedule: "0 0 1 * * * *"
update_status:
run: "update_status"
schedule: "0 */5 * * * * *"
discover_github_pipelines:
run: "discover_github_pipelines"
schedule: "0 2 * * * * *"
discover_github_builds:
run: "discover_github_builds"
schedule: "0 3,18,33,48 * * * * *"calculate_statistics and update_status are required and must remain enabled. Add both discovery jobs for each configured CI/CD provider:
| Provider | Pipeline job | Build job |
|---|---|---|
| Bamboo | discover_bamboo_pipelines | discover_bamboo_builds |
| GitHub | discover_github_pipelines | discover_github_builds |
| GitLab | discover_gitlab_pipelines | discover_gitlab_builds |
| Jenkins | discover_jenkins_pipelines | discover_jenkins_builds |
| TeamCity | discover_teamcity_pipelines | discover_teamcity_builds |
Discovery jobs return without work when their provider has no configured integration, so they are safe to leave enabled.
Application Settings
Outbound HTTP Policy
Outbound integration requests deny private, loopback, link-local, and other reserved addresses by default and trust the public web PKI. Allow only the internal networks used by self-hosted CI/CD systems, 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"| Setting | Purpose |
|---|---|
allowed_networks | CIDRs or individual addresses exempt from the reserved-address block |
ca_certificates | PEM bundles trusted in addition to public roots |
Every other reserved range remains blocked. A malformed network or unusable CA bundle stops startup. Mount CA files into the container and use paths relative to its /app working directory.
JWT
Team Server signs 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: 604800Each 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 48Changing 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 and notifications. base_url must be the public URL used by browsers and Sensors. It also builds Slack OAuth callbacks and links inside alerts.
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://....
If an ingress, reverse proxy, or load balancer terminates TLS, omit settings.tls but keep the public SERVER_URL on HTTPS. Configure the terminating layer to set secure session-cookie attributes.
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-meThis provider supports one administrative account and is intended only for local development and testing. Do not use it in production.
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| Setting | Requirement |
|---|---|
client_id | OIDC client identifier |
client_secret | OIDC client secret |
issuer_url | Provider issuer URL |
redirect_url | Exact callback registered with the provider |
scopes | Include openid, email, and profile |
domains | One or more email domains allowed to sign in |
The callback path always includes /api:
https://team-server.example.com/api/authentication/{provider}/callbackSupported provider keys and typical issuer URLs are:
| Provider key | Issuer URL |
|---|---|
google | https://accounts.google.com |
microsoft | https://login.microsoftonline.com/{tenant-id}/v2.0 |
cyberark | Your CyberArk Identity tenant issuer |
oracle | Your OCI IAM identity-domain issuer |
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 discovery jobs and identity providers your deployment uses.
logger:
enable: true
pretty_backtrace: false
level: info
format: compact
scheduler:
output: stdout
jobs:
calculate_statistics:
run: "calculate_statistics"
schedule: "0 0 1 * * * *"
update_status:
run: "update_status"
schedule: "0 */5 * * * * *"
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'; 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.comRequired Environment Variables
| Variable | Purpose |
|---|---|
DATABASE_URL | PostgreSQL connection URI |
ENDURA_LICENSE_KEY | Team Server license |
JWT_SENSOR_SECRET | Sensor-token signing secret |
JWT_USER_SECRET | User-token signing secret |
SERVER_URL | Public Team Server URL |
TENANT_NAME | Organization name |
Add the client ID and client secret variables referenced by each configured OIDC provider.