A3S Docs
A3S Gateway

Routing

Rule-based request matching with Host, Path, Headers, Method, and SNI matchers

Routing

A3S Gateway uses a Traefik-compatible rule syntax for matching incoming requests to services.

Rule Syntax

rule = "Matcher(`value`) && Matcher(`value`)"

Supported Matchers

Prop

Type

Combining Matchers

Use && to combine multiple matchers (AND logic):

routers "api-v1" {
  rule    = "Host(`api.example.com`) && PathPrefix(`/v1`)"
  service = "api-v1"
}

routers "webhooks" {
  rule    = "Method(`POST`) && PathPrefix(`/webhooks`)"
  service = "webhook-handler"
}

routers "internal" {
  rule    = "Headers(`X-Internal`, `true`) && PathPrefix(`/admin`)"
  service = "admin-service"
}

Priority

When multiple routers match, the lowest priority value wins (default: 0):

routers "specific" {
  rule     = "Host(`api.example.com`) && Path(`/health`)"
  service  = "health-service"
  priority = 0
}

routers "general" {
  rule     = "Host(`api.example.com`)"
  service  = "api-service"
  priority = 10
}

Entrypoint Binding

Routers only receive traffic from their bound entrypoints:

entrypoints "web" {
  address = "0.0.0.0:80"
}

entrypoints "websecure" {
  address = "0.0.0.0:443"
  tls {
    cert_file = "cert.pem"
    key_file  = "key.pem"
  }
}

# HTTPS only
routers "api" {
  rule        = "Host(`api.example.com`)"
  service     = "api-service"
  entrypoints = ["websecure"]
}

# Both HTTP and HTTPS
routers "web" {
  rule        = "Host(`www.example.com`)"
  service     = "web-service"
  entrypoints = ["web", "websecure"]
}

Middleware Chain

Middlewares are applied in the order listed. If any middleware rejects the request, the pipeline short-circuits immediately.

routers "api" {
  rule        = "Host(`api.example.com`)"
  service     = "api-service"
  middlewares = ["ip-allow", "auth-jwt", "rate-limit", "cors"]
  # Order: IP check → JWT auth → rate limit → CORS headers
}

TCP/UDP Routing

TCP entrypoints use SNI from the TLS ClientHello:

entrypoints "tcp-secure" {
  address  = "0.0.0.0:5432"
  protocol = "tcp"
}

routers "postgres" {
  rule        = "HostSNI(`db.example.com`)"
  service     = "postgres-service"
  entrypoints = ["tcp-secure"]
}

UDP routing is port-based — each UDP entrypoint maps to a single service.

Examples

API Versioning

routers "api-v2" {
  rule     = "Host(`api.example.com`) && PathPrefix(`/v2`)"
  service  = "api-v2"
  priority = 0
}

routers "api-v1" {
  rule     = "Host(`api.example.com`) && PathPrefix(`/v1`)"
  service  = "api-v1"
  priority = 1
}

routers "api-fallback" {
  rule     = "Host(`api.example.com`)"
  service  = "api-v2"
  priority = 100
}

Multi-Tenant

routers "tenant-a" {
  rule    = "Host(`a.example.com`)"
  service = "tenant-a-backend"
}

routers "tenant-b" {
  rule    = "Host(`b.example.com`)"
  service = "tenant-b-backend"
}

Header-Based Canary

routers "canary" {
  rule     = "Headers(`X-Canary`, `true`) && PathPrefix(`/api`)"
  service  = "canary-backend"
  priority = 0
}

routers "stable" {
  rule     = "PathPrefix(`/api`)"
  service  = "stable-backend"
  priority = 10
}

On this page