Configuration
Embedded examples cover every feature — start from these:
gateway.svc config list # 16 annotated examplesgateway.svc config generate quickstart # print onegateway.svc config generate all -d dir/ # write them allProfiles 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.
Boot keys
Section titled “Boot keys”Top level of the bootstrap file (-f, default .gateway.yaml):
| Key | Default | Purpose |
|---|---|---|
name, host, port | — | Identity + public listener |
internal.port | — | Mesh listener (required unless entrypoints: is used) |
internal.trustedips | — | Peers allowed to set X-Forwarded-Host |
entrypoints: | — | Custom listener list (replaces port/internal): per-entry `name, address, protocol (http |
timeouts.read/write/idle | 10s / 10s / 180s | Listener-level fallbacks |
zerotrust | — | mTLS: client certs on the internal listener + mTLS on the gateway→backend leg |
svccert, svckey, rootcacert | — | Service certificate material |
jwt_public_key | — | Key for local JWT verification (kisai-auth) |
config.url / config.apikey / config.cache | — | Remote config from config.svc (SSE hot-reload) |
config.path | — | Local chassis service-config folder |
config.router.dir | — | Gateway-only: local directory of routing YAML |
servicediscovery_url / servicediscovery_apikey | — | Discovery client for the backend watcher |
provider.kisai.throttleduration | 15s | Router config push throttle |
provider.kisai.watcher.refreshinterval | 5s | Discovery poll interval |
router.loglevel | — | Embedded router’s own log verbosity, independent of loglevel |
log, loglevel | — | stdout or fluentd host:port; level |
vault.url, datacenter, cluster, sid | — | Platform wiring |
Routing entities
Section titled “Routing entities”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).
Load balancing
Section titled “Load balancing”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_memoryAdaptive profiles run a weight-reconciliation controller per backend, restarted on every reload.
Multi-file routing directory
Section titled “Multi-file routing directory”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;tlsoptionsnames 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
certresolverorextramiddlewares— all abort the (re)load.
Raw passthrough
Section titled “Raw passthrough”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.
TLS: two independent planes
Section titled “TLS: two independent planes”- External — per route:
certresolver(ACME),tlsoptions(custom), ortlspassthrough. Works with or without zerotrust. - Internal (zerotrust) —
zerotrust: truerequires client certificates onwebsecureinternaland uses mTLS on the gateway→backend leg. Thetlsoptionsnamesdefaultandkisaitlsinternalare reserved.