---
title: Configuration
description: Programmatic and YAML configuration for Bastion with hot-reload support.
---

Bastion can be configured programmatically via option functions, declaratively via YAML/JSON configuration files, or through a combination of both. Configuration changes can be applied at runtime without restarting the gateway.

## Programmatic configuration

Bastion uses the functional options pattern. Options are passed to `bastion.NewExtension`:

```go
bastion.NewExtension(
    bastion.WithBasePath("/api"),
    bastion.WithRoute(bastion.RouteConfig{
        Path:    "/users/*",
        Targets: []bastion.TargetConfig{
            {URL: "http://user-service:8080", Weight: 1},
        },
        StripPrefix: true,
        Protocol:    bastion.ProtocolHTTP,
        Enabled:     true,
    }),
    bastion.WithCircuitBreaker(bastion.CircuitBreakerConfig{
        Enabled:          true,
        FailureThreshold: 5,
        ResetTimeout:     30 * time.Second,
    }),
    bastion.WithRateLimiting(bastion.RateLimitConfig{
        Enabled:        true,
        RequestsPerSec: 1000,
        Burst:          100,
    }),
    bastion.WithHealthCheck(bastion.HealthCheckConfig{
        Enabled:  true,
        Interval: 10 * time.Second,
        Path:     "/health",
    }),
    bastion.WithDiscovery(bastion.DiscoveryConfig{
        Enabled:    true,
        WatchMode:  true,
        AutoPrefix: true,
    }),
    bastion.WithDashboard(bastion.DashboardConfig{
        Enabled:  true,
        BasePath: "/bastion",
        Realtime: true,
    }),
)
```

### Available option functions

| Option | Description |
|--------|-------------|
| `WithBasePath(path)` | Sets the base URL prefix for all gateway routes (default: `"/api"`) |
| `WithRoute(cfg)` | Adds a static route. Can be called multiple times. |
| `WithCircuitBreaker(cfg)` | Configures global circuit breaker settings |
| `WithRateLimiting(cfg)` | Configures global rate limiting |
| `WithHealthCheck(cfg)` | Configures active health checking |
| `WithDiscovery(cfg)` | Configures FARP service discovery integration |
| `WithDashboard(cfg)` | Enables the admin dashboard and REST API |
| `WithTLS(cfg)` | Configures default upstream TLS settings |
| `WithCORS(cfg)` | Configures CORS headers |
| `WithIPFilter(cfg)` | Configures IP allow/deny lists |
| `WithAuth(cfg)` | Configures global authentication |
| `WithCache(cfg)` | Configures global response caching |
| `WithRetry(cfg)` | Configures global retry policy |
| `WithTimeout(d)` | Sets the global upstream request timeout |
| `WithLogger(l)` | Sets the structured logger (`*slog.Logger`) |

## YAML configuration

Bastion reads configuration from Forge YAML config files under the `bastion` key:

```yaml
bastion:
  enabled: true
  basePath: "/api"
  routes:
    - path: "/users/*"
      targets:
        - url: "http://user-service:8080"
          weight: 1
      stripPrefix: true
      protocol: http
      enabled: true
    - path: "/orders/*"
      targets:
        - url: "http://order-service:8080"
          weight: 1
      stripPrefix: true
      protocol: http
      enabled: true
  circuitBreaker:
    enabled: true
    failureThreshold: 5
    resetTimeout: 30s
  rateLimiting:
    enabled: true
    requestsPerSec: 1000
    burst: 100
  healthCheck:
    enabled: true
    interval: 10s
    path: "/health"
    timeout: 5s
  discovery:
    enabled: true
    watchMode: true
    autoPrefix: true
  dashboard:
    enabled: true
    basePath: "/bastion"
    realtime: true
```

YAML configuration is merged with programmatic defaults. Programmatic options that are explicitly set take precedence over YAML values.

## Configuration keys reference

### Top-level

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `enabled` | `bool` | `true` | Enable or disable the entire gateway |
| `basePath` | `string` | `"/api"` | Base URL prefix for all proxied routes |

### Routes (`routes[]`)

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `path` | `string` | -- | URL pattern to match (required) |
| `targets` | `[]object` | -- | Upstream targets (required, at least one) |
| `targets[].url` | `string` | -- | Target base URL |
| `targets[].weight` | `int` | `1` | Relative traffic weight |
| `stripPrefix` | `bool` | `false` | Remove matched prefix before forwarding |
| `protocol` | `string` | `"http"` | Proxy protocol: `http`, `websocket`, `sse`, `grpc` |
| `enabled` | `bool` | `true` | Whether the route is active |
| `loadBalancer` | `string` | `""` | Override: `round-robin`, `weighted-round-robin`, `random`, `least-connections`, `consistent-hash` |
| `timeout` | `duration` | `30s` | Override: upstream request timeout |

### Circuit breaker (`circuitBreaker`)

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `enabled` | `bool` | `false` | Enable circuit breakers |
| `failureThreshold` | `int` | `5` | Consecutive failures before opening the circuit |
| `resetTimeout` | `duration` | `30s` | Time to wait before transitioning from open to half-open |

### Rate limiting (`rateLimiting`)

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `enabled` | `bool` | `false` | Enable rate limiting |
| `requestsPerSec` | `float64` | `1000` | Token refill rate (requests per second) |
| `burst` | `int` | `100` | Maximum burst size (token bucket capacity) |

### Health check (`healthCheck`)

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `enabled` | `bool` | `false` | Enable active health probes |
| `interval` | `duration` | `10s` | Time between health check requests |
| `path` | `string` | `"/health"` | HTTP path to probe on each target |
| `timeout` | `duration` | `5s` | Health check request timeout |

### Discovery (`discovery`)

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `enabled` | `bool` | `false` | Enable FARP service discovery |
| `watchMode` | `bool` | `false` | Watch for service registrations/deregistrations in real time |
| `autoPrefix` | `bool` | `false` | Auto-create route prefixes from service names |

### Dashboard (`dashboard`)

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `enabled` | `bool` | `false` | Enable the admin dashboard and REST API |
| `basePath` | `string` | `"/bastion"` | Base path for dashboard and API routes |
| `realtime` | `bool` | `false` | Enable WebSocket real-time event stream |

### Authentication (`auth`)

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `type` | `string` | `""` | Auth type: `api-key`, `bearer`, `forward-auth` |
| `secret` | `string` | `""` | Secret or token for validation |
| `header` | `string` | `""` | Header name for API key auth |
| `forwardURL` | `string` | `""` | URL for forward-auth delegation |

### TLS (`tls`)

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `caCertFile` | `string` | `""` | CA certificate for upstream verification |
| `certFile` | `string` | `""` | Client certificate for mTLS |
| `keyFile` | `string` | `""` | Client key for mTLS |
| `insecureSkipVerify` | `bool` | `false` | Skip certificate verification (development only) |

### Retry (`retry`)

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `maxRetries` | `int` | `0` | Maximum retry attempts (0 = disabled) |
| `strategy` | `string` | `"exponential"` | Backoff strategy: `exponential`, `linear`, `fixed` |
| `baseDelay` | `duration` | `100ms` | Initial delay between retries |
| `maxDelay` | `duration` | `5s` | Maximum delay cap |
| `jitter` | `bool` | `false` | Add randomized jitter to delays |

### Cache (`cache`)

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `enabled` | `bool` | `false` | Enable response caching |
| `ttl` | `duration` | `5m` | Default cache entry time-to-live |

## Hot-reload behavior

Bastion supports hot-reloading of configuration changes without restarting the gateway process. There are two mechanisms:

### File watcher

When the Forge configuration file changes on disk, Bastion detects the change and reloads:

- **Route additions and removals** -- New routes are added to the route table; removed routes stop accepting traffic
- **Target changes** -- New targets are added to the load balancer pool; removed targets are drained
- **Rate limit changes** -- Token bucket parameters are updated immediately
- **Circuit breaker changes** -- Thresholds are updated; existing circuit states are preserved
- **Health check changes** -- Interval and path changes take effect on the next probe cycle

### Admin API

The admin REST API provides runtime configuration changes:

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/bastion/api/routes` | Create a new route |
| `PUT` | `/bastion/api/routes/:id` | Update an existing route |
| `DELETE` | `/bastion/api/routes/:id` | Remove a route |
| `POST` | `/bastion/api/routes/:id/enable` | Enable a route |
| `POST` | `/bastion/api/routes/:id/disable` | Disable a route |

Changes made through the admin API take effect immediately and are reflected in the running configuration.

### What does not hot-reload

Some settings require a restart to take effect:

- `basePath` (the gateway base URL prefix)
- `dashboard.basePath` (the admin dashboard prefix)
- TLS certificate file paths (though certificate contents are reloaded automatically when the files change)

## Per-route config overrides

Many global settings can be overridden at the route level. Route-level settings take precedence over global settings.

```yaml
bastion:
  rateLimiting:
    enabled: true
    requestsPerSec: 1000
    burst: 100
  routes:
    - path: "/uploads/*"
      targets:
        - url: "http://upload-service:8080"
      rateLimit:
        enabled: true
        requestsPerSec: 10     # stricter limit for uploads
        burst: 5
    - path: "/api/*"
      targets:
        - url: "http://api-service:8080"
      # inherits the global rate limit (1000 req/s)
```

Overridable settings: `rateLimit`, `loadBalancer`, `auth`, `cache`, `timeout`, `retryPolicy`.
