Skip to content
Talk to our solutions team

Configuration

Embedded examples cover every feature — start from these:

Terminal window
gateway.svc config list # 16 annotated examples
gateway.svc config generate quickstart # print one
gateway.svc config generate all -d dir/ # write them all

Profiles include: bootstrap, quickstart, common, single-app, multi-tenant, static-site, spa, spa-http, acme-http01, acme-dns01, dashboard, multi-port, url-rewrite, headers-expr, load-balancing.

Top level of the bootstrap file (-f, default .gateway.yaml):

KeyDefaultPurpose
name, host, portIdentity + public listener
internal.portMesh listener (required unless entrypoints: is used)
internal.trustedipsPeers allowed to set X-Forwarded-Host
entrypoints:Custom listener list (replaces port/internal): per-entry `name, address, protocol (http
timeouts.read/write/idle10s / 10s / 180sListener-level fallbacks
zerotrustmTLS: client certs on the internal listener + mTLS on the gateway→backend leg
svccert, svckey, rootcacertService certificate material
jwt_public_keyKey for local JWT verification (kisai-auth)
config.url / config.apikey / config.cacheRemote config from config.svc (SSE hot-reload)
config.pathLocal chassis service-config folder
config.router.dirGateway-only: local directory of routing YAML
servicediscovery_url / servicediscovery_apikeyDiscovery client for the backend watcher
provider.kisai.throttleduration15sRouter config push throttle
provider.kisai.watcher.refreshinterval5sDiscovery poll interval
router.loglevelEmbedded router’s own log verbosity, independent of loglevel
log, loglevelstdout or fluentd host:port; level
vault.url, datacenter, cluster, sidPlatform wiring
domainmaps:
- name: acme-prod
domains: [app.acme.com, www.acme.com] # MUST be a list, not a scalar
customer: acme
product: forge
environment: prod
tenant: main
corsconfig:
allowedorigins: ["https://app.acme.com"]
backends:
- backend: # note the nested wrapper
name: forge-api
urls: ["https://10.0.0.11:7102", "https://10.0.0.12:7102"]
https: true
profile: steady # optional LB profile
endpoints:
- name: api
path: { prefix: /api } # prefix is the only path rule
backend: forge-api
middlewares: [kisai-auth, customer-domain-mapper]
rewrite:
stripprefix: [/api]
headers:
request:
set: { X-Request-Src: "${gateway.cluster}" }
security_headers: strict # strict | relaxed | none
routes:
- name: acme-public
domainmap: acme-prod
entrypoint: websecure
certresolver: letsencrypt # or tlsoptions / tlspassthrough
endpoints: [api]
staticpaths: [webapp]
extramiddlewares: [strict-rate-limit]
staticpaths:
- name: webapp
type: spa # spa = index fallback; static = 404 page
folderpath: ./public
indexpath: index.html
path: { prefix: / }

Rules enforced at load: redirect: is mutually exclusive with backend:/rewrite:; rewrite.path is exclusive with strip/add prefix; middleware order in middlewares: is the execution order.

Header values accept ${…} expressions from the namespaces request.*, tenant.*, auth.*, response.*, upstream.*, gateway.*. A missing variable resolves empty and the header is stripped; CRLF is stripped (request-smuggling defense).

loadbalance:
default: steady
profiles:
steady:
algo: wrr # wrr | sticky | weighted | mirror | failover | adaptive
healthcheck: { path: /health, interval: 10s }
canary:
algo: adaptive
formula: available_capacity # inflight_count | available_capacity | cpu_then_memory

Adaptive profiles run a weight-reconciliation controller per backend, restarted on every reload.

With config.router.dir, every *.yaml/*.yml in the directory is merged:

  • List keys (routes, domainmaps, backends, endpoints, staticpaths, tlsoptions) concatenate; everything else last-wins.
  • A file’s namespace: prefixes its declared names and bare same-file references (forge.tenant-a); dotted cross-file references pass through untouched; tlsoptions names are never namespaced.
  • Boot-plane keys (port, entrypoints, zerotrust, config, …) found in routing files are stripped with a warning; a bootstrap file physically inside the dir is skipped.
  • Validation is fail-fast: duplicate names, list-type mismatches, unresolved route→domainmap/endpoint/staticpath/tlsoptions references, unresolved endpoint→backend references, unknown certresolver or extramiddlewares — all abort the (re)load.

Anything the kis.ai model doesn’t cover can be declared verbatim under traefik.static / traefik.dynamic — e.g. ACME resolvers, an :80 redirect entrypoint, or a rate-limit middleware:

traefik:
dynamic:
http:
middlewares:
strict-rate-limit:
rateLimit: { average: 100, burst: 50 }

Attach passthrough middlewares to routes via extramiddlewares:. Security-sensitive paths (e.g. the insecure dashboard API) are protected and rejected at boot.

  • External — per route: certresolver (ACME), tlsoptions (custom), or tlspassthrough. Works with or without zerotrust.
  • Internal (zerotrust)zerotrust: true requires client certificates on websecureinternal and uses mTLS on the gateway→backend leg. The tlsoptions names default and kisaitlsinternal are reserved.