Configuration Guide

Every component of an origin config, with working examples

The Config File

All SBproxy configuration lives in a YAML file called sb.yml. It has two top-level keys:

  • proxy - Server settings (bind ports, TLS, global options)
  • origins - A map of hostnames to origin configurations
proxy:
  http_bind_port: 8080
  https_bind_port: 8443

origins:
  "app.example.com":
    action:
      type: proxy
      url: https://backend.example.com

Each key under origins is a hostname. Wildcard hostnames are supported: *.example.com matches any single-level subdomain (e.g., api.example.com, app.example.com) but not deeper subdomains (e.g., deep.sub.example.com).

An origin needs at minimum a hostname and an action.

Origins

An origin is a hostname-to-backend mapping with optional security, caching, and transformation layers. Here are all the top-level fields an origin can have, grouped by purpose:

GroupFields
Action (required)action
Securityauthentication, policies
Request pipelinerequest_modifiers, request_rules, forward_rules, must_match_rules, allowed_methods
Response pipelineresponse_modifiers, transforms, response_cache
Hooks and valueson_request, on_response, variables
Sessionsession_config
Error handlingerror_pages, fallback_origin
Transportcors, compression, proxy_headers, streaming_proxy_config, force_ssl

The key structural rule: authentication, policies, request_modifiers, response_modifiers, transforms, forward_rules, and response_cache are all siblings of action at the origin level. They are never nested inside the action block.

Action

The action block is required. It determines what happens to the request. Every action has a type field, and the remaining fields depend on the type.

The most common action types:

  • proxy - Reverse proxy to an upstream URL
  • ai_proxy - Multi-provider LLM gateway with OpenAI-compatible API
  • static - Return a fixed response (health checks, maintenance pages)
  • redirect - HTTP redirect (301, 302, 307, 308), with optional bulk-redirect tables
  • load_balancer - Distribute across multiple backends
  • websocket - WebSocket proxying with connection pooling
  • graphql - GraphQL-aware proxy with query validation and depth limiting
  • grpc - gRPC proxying with HTTP/2
  • mcp - Model Context Protocol server for LLM tool integration
  • a2a - Google Agent-to-Agent protocol
  • storage - Serve files from cloud storage (S3, GCS, Azure)
  • mock - Synthetic responses with simulated delay for testing
  • echo - Return request details for debugging

Proxy action

origins:
  "api.example.com":
    action:
      type: proxy
      url: https://backend.example.com
      timeout: 30s
      skip_tls_verify_host: false

AI proxy action

origins:
  "ai.example.com":
    action:
      type: ai_proxy
      providers:
        - name: openai
          api_key: sk-your-openai-key
          models: [gpt-4o, gpt-4o-mini]
        - name: anthropic
          api_key: sk-ant-your-anthropic-key
          models: [claude-sonnet-4-20250514]
      default_model: gpt-4o-mini
      routing:
        strategy: fallback_chain

For production, use secrets management instead of inline keys.

Static action

origins:
  "health.example.com":
    action:
      type: static
      status_code: 200
      content_type: application/json
      json_body: {"status": "ok"}

See Action Types for the full reference on all action types and their fields.

Authentication

The authentication block defines how requests are authenticated. It runs after policy enforcement. Available types:

  • api_key - Static keys checked via header or query parameter
  • basic_auth - Username/password pairs
  • bearer - Token-based authentication via Authorization header
  • jwt - JSON Web Tokens with JWKS auto-discovery and key rotation
  • forward_auth - Delegate to an external authentication service
  • digest - HTTP Digest authentication
  • bot_auth - Web Bot Auth (RFC 9421 HTTP Message Signatures) for verifying signed AI agents

Authenticated claims are available as template variables via {{auth.data.*}} in later stages.

API key authentication

origins:
  "api.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    authentication:
      type: api_key
      api_keys:
        - my-secret-key-1
        - my-secret-key-2
curl -H "Host: api.example.com" -H "X-API-Key: my-secret-key-1" http://localhost:8080/

JWT authentication

origins:
  "api.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    authentication:
      type: jwt
      jwks_url: https://auth.example.com/.well-known/jwks.json
      issuer: https://auth.example.com
      audience: my-api

Basic auth

origins:
  "admin.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    authentication:
      type: basic_auth
      users:
        - username: admin
          password: "{{secrets.admin_password}}"

See Authentication for the full reference.

Policies

Policies are an array of security rules that execute before authentication, in the order they appear. If any policy blocks the request, processing stops immediately. Available types:

  • rate_limiting - Token bucket and fixed window rate limiting
  • ip_filter - Whitelist/blacklist by IP address or CIDR range
  • waf - Web Application Firewall with ModSecurity rules and OWASP CRS
  • ddos - Adaptive thresholds with challenge-response mitigation
  • security_headers - HSTS, CSP, X-Frame-Options, and more
  • csrf - Double-submit cookie pattern with signed tokens
  • request_limit - Request size, header count, and body size limits
  • concurrent_limit - Cap in-flight requests per route, IP, or API key
  • openapi_validation - Reject requests that do not match a published OpenAPI 3.0 spec
  • page_shield - Stamp a CSP header on every response and collect violation reports
  • exposed_credentials - Detect known-leaked passwords on Basic-auth requests
  • dlp - Data Loss Prevention scan over request URI and headers
  • ai_crawl_control - HTTP 402 challenges for AI crawlers without payment tokens
  • prompt_injection_v2 - Score inbound prompts against a heuristic detector

Each policy supports an optional match field to scope it to specific paths or methods.

Rate limiting

origins:
  "api.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    policies:
      - type: rate_limiting
        requests_per_second: 60
        burst: 10
        key: ip

IP filter

origins:
  "internal.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    policies:
      - type: ip_filter
        whitelist:
          - 10.0.0.0/8
          - 192.168.1.0/24

See Security Policies and Policies Reference for the full reference.

Request Modifiers

Request modifiers change the request before it reaches the action. Each modifier can target headers, query parameters, the URL path, the HTTP method, or the body.

origins:
  "api.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    request_modifiers:
      - headers:
          set:
            X-Request-ID: "{{request.id}}"
            X-Forwarded-User: "{{auth.data.sub}}"
          delete:
            - X-Internal-Debug
        url:
          path:
            prefix: /v2

For complex request logic, use an inline Lua script:

    request_modifiers:
      - lua_script: |
          function modify_request(req, ctx)
            if req.method == "POST" then
              return { set_headers = { ["X-Modified"] = "true" } }
            end
          end

See Rules & Modifiers for the full reference.

Response Modifiers

Response modifiers change the response before it reaches the client. They can adjust headers, status codes, and body content.

origins:
  "api.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    response_modifiers:
      - headers:
          set:
            X-Response-Time: "{{request.duration}}"
            Cache-Control: "public, max-age=300"
          delete:
            - X-Powered-By
            - Server

See Rules & Modifiers for the full reference.

Transforms

Transforms modify response content at the body level. They run after the action returns a response but before response modifiers. Types include:

  • json - Remove empty fields, pretty print, JSONPath rules
  • json_projection - Include or exclude specific JSON fields
  • lua_json - Lua-scripted JSON transformations
  • js_json - JavaScript-scripted JSON transformations (QuickJS)
  • javascript - General-purpose JavaScript body transform
  • wasm - WASM module transform with a sandboxed module per request
  • html - HTML formatting and tag injection
  • optimize_html - Lightweight HTML minification
  • html_to_markdown - Convert HTML responses to Markdown
  • markdown - Markdown to HTML rendering
  • replace_strings - Find-and-replace with optional regex
  • normalize - Normalize whitespace, line endings, and Unicode forms
  • encoding - Convert between text encodings
  • format_convert - Convert between supported formats
  • payload_limit - Cap the response body size
  • sse_chunking - Rechunk Server-Sent Events for downstream readers
  • template - Render the response body through the template engine

JSON projection

origins:
  "api.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    transforms:
      - type: json_projection
        include:
          - id
          - name
          - email

Lua JSON transform

origins:
  "api.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    transforms:
      - type: lua_json
        lua_script: |
          function modify_json(data, ctx)
            return {
              set_fields = {
                processed = true,
                timestamp = os.time()
              },
              remove_fields = { "internal_id", "debug_info" }
            }
          end

See Transforms for the full reference.

Forwarding Rules

Forwarding rules route requests to different origin configurations based on path, headers, method, or expressions. Each rule can embed an inline origin with its own action, authentication, and policies. Rules are evaluated in order; the first match wins.

origins:
  "app.example.com":
    action:
      type: static
      status_code: 200
      body: "Default response"
    forward_rules:
      - origin:
          hostname: api-backend
          action:
            type: proxy
            url: https://api-backend.internal
          authentication:
            type: api_key
            api_keys:
              - my-api-key
        rules:
          - path:
              prefix: /api/
      - origin:
          hostname: static-backend
          action:
            type: proxy
            url: https://cdn.example.com
        rules:
          - path:
              prefix: /assets/

See Forwarding Rules for the full reference.

Response Cache

The response_cache block enables caching of responses at the origin level. Cache hits skip action execution entirely.

origins:
  "api.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    response_cache:
      enabled: true
      ttl: 5m
      conditions:
        status_codes:
          - 200
          - 301
        methods:
          - GET
          - HEAD
      stale_while_revalidate:
        enabled: true
        duration: 30s

See Caching Guide for the full multi-tier caching reference.

Variables and Webhooks

The variables map holds static values available to templates as {{ variables.name }}. The on_request and on_response hooks fire HMAC-signable webhook notifications as traffic crosses the origin; they notify external systems, they do not inject data into the request.

origins:
  "api.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    variables:
      api_version: "v2"
    request_modifiers:
      - headers:
          set:
            X-API-Version: "{{ variables.api_version }}"
    on_request:
      - url: https://audit.internal/hook
        secret: ${AUDIT_HMAC_SECRET}
        on_error: ignore

Template variables use {{ scope.path }} syntax. Scopes: request, variables, secrets, config, session, env, server.

See Template Engine, Callbacks, and Secrets Management for details.

Session Config

The session_config block controls cookie-based session tracking. Session data is available as {{session.*}} template variables.

origins:
  "app.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    session_config:
      cookie_name: sb_session
      cookie_max_age: 86400
      cookie_same_site: Lax

See Session Management for the full reference.

Error Pages

The error_pages array defines custom responses for specific HTTP status codes. Supports inline content, JSON, base64-encoded bodies, and template variables.

origins:
  "app.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    error_pages:
      - status:
          - 404
        content_type: application/json
        body: '{"error": "not found", "path": "{{request.path}}"}'
        template: true
      - status:
          - 500
          - 502
          - 503
        content_type: text/html
        body: "

Service Unavailable

Please try again later.

"

See Custom Error Pages for the full reference.

Transport Options

Several origin-level fields control transport behavior:

origins:
  "api.example.com":
    action:
      type: proxy
      url: https://backend.example.com
    force_ssl: true
    allowed_methods:
      - GET
      - POST
      - PUT
      - DELETE
    cors:
      enable: true
      allow_origins:
        - "https://app.example.com"
      allow_methods:
        - GET
        - POST
      allow_headers:
        - Content-Type
        - Authorization
      max_age: 86400
    compression:
      enable: true
      algorithms:
        - zstd
        - br
        - gzip
      min_size: 1024

Putting It All Together

Here is a complete, realistic origin configuration that combines the most common features:

proxy:
  http_bind_port: 8080

origins:
  "api.example.com":
    # Action: reverse proxy to backend
    action:
      type: proxy
      url: https://backend.example.com
      timeout: 30s

    # Security: JWT auth with rate limiting
    authentication:
      type: jwt
      jwks_url: https://auth.example.com/.well-known/jwks.json
      issuer: https://auth.example.com
      audience: my-api
    policies:
      - type: rate_limiting
        requests_per_second: 120
        burst: 20
        key: ip
      - type: ip_filter
        blacklist:
          - 192.0.2.0/24

    # Request pipeline: add tracing headers
    request_modifiers:
      - headers:
          set:
            X-Request-ID: "{{request.id}}"
            X-User-ID: "{{auth.data.sub}}"

    # Response pipeline: strip internal headers, cache GET responses
    response_modifiers:
      - headers:
          delete:
            - X-Powered-By
            - Server
    response_cache:
      enabled: true
      ttl: 5m
      conditions:
        methods:
          - GET

    # Static template values
    variables:
      api_version: "v2"

    # Error handling
    error_pages:
      - status:
          - 500
          - 502
          - 503
        content_type: application/json
        body: '{"error": "service unavailable"}'
curl -H "Host: api.example.com" -H "Authorization: Bearer your-jwt-token" http://localhost:8080/