> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/TecharoHq/Anubis/llms.txt
> Use this file to discover all available pages before exploring further.

# Storage Configuration

> Storage backend configuration for state persistence

## Overview

Anubis uses pluggable storage backends to persist client state, challenge tokens, and bot detection metadata. The storage configuration determines which backend to use and its parameters.

## Store

Storage backend configuration struct.

### Type Definition

```go theme={null}
type Store struct {
    Backend    string          `json:"backend"`
    Parameters json.RawMessage `json:"parameters"`
}
```

### Fields

<ParamField path="Backend" type="string" required>
  Storage backend type. Must be a registered store backend.

  Built-in backends:

  * `"memory"` - In-memory storage (default, not persistent)
  * `"bbolt"` - BoltDB embedded database
  * `"valkey"` - Valkey/Redis compatible server
  * `"s3api"` - S3-compatible object storage
</ParamField>

<ParamField path="Parameters" type="json.RawMessage">
  Backend-specific configuration as raw JSON. The structure depends on the selected backend.
</ParamField>

### Validation Rules

* `Backend` must be non-empty
* `Backend` must be a registered store implementation
* `Parameters` must be valid according to the backend's validation rules

### Errors

```go theme={null}
var (
    ErrNoStoreBackend      = errors.New("config.Store: no backend defined")
    ErrUnknownStoreBackend = errors.New("config.Store: unknown backend")
)
```

## Backend-Specific Parameters

### Memory Backend

The memory backend requires no parameters. State is stored in-process and lost on restart.

```yaml theme={null}
store:
  backend: memory
```

### BoltDB Backend

Embedded database stored in a local file.

```yaml theme={null}
store:
  backend: bbolt
  parameters:
    path: "./var/anubis.db"
    mode: 0600
```

**Parameters:**

* `path` (string, required): Filesystem path to the database file
* `mode` (int, optional): File permissions in octal (default: 0600)

### Valkey/Redis Backend

Connect to a Valkey or Redis server.

```yaml theme={null}
store:
  backend: valkey
  parameters:
    address: "localhost:6379"
    password: "secret"
    db: 0
    poolSize: 10
```

**Parameters:**

* `address` (string, required): Server address (host:port)
* `password` (string, optional): Authentication password
* `db` (int, optional): Database number (default: 0)
* `poolSize` (int, optional): Connection pool size
* `tls` (bool, optional): Enable TLS

### S3 Backend

Use S3-compatible object storage (AWS S3, MinIO, etc.).

```yaml theme={null}
store:
  backend: s3api
  parameters:
    bucket: "anubis-state"
    region: "us-east-1"
    endpoint: "https://s3.amazonaws.com"
    accessKeyId: "AKIAIOSFODNN7EXAMPLE"
    secretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
```

**Parameters:**

* `bucket` (string, required): S3 bucket name
* `region` (string, required): AWS region
* `endpoint` (string, optional): Custom S3 endpoint (for S3-compatible services)
* `accessKeyId` (string, required): AWS access key ID
* `secretAccessKey` (string, required): AWS secret access key
* `sessionToken` (string, optional): AWS session token

## Default Configuration

When no store is specified, Anubis defaults to in-memory storage:

```go theme={null}
Store: &Store{
    Backend: "memory",
}
```

## StatusCodes

HTTP status codes returned for different actions.

### Type Definition

```go theme={null}
type StatusCodes struct {
    Challenge int `json:"CHALLENGE"`
    Deny      int `json:"DENY"`
}
```

### Fields

<ParamField path="Challenge" type="int" default="200">
  HTTP status code to return when presenting a challenge. Valid range: 100-599.

  Common values:

  * `200` - OK (default, challenge rendered in response body)
  * `403` - Forbidden
  * `429` - Too Many Requests
</ParamField>

<ParamField path="Deny" type="int" default="200">
  HTTP status code to return when denying a request. Valid range: 100-599.

  Common values:

  * `200` - OK (default, denial message in response body)
  * `403` - Forbidden
  * `429` - Too Many Requests
  * `503` - Service Unavailable
</ParamField>

### Validation Rules

* Both `Challenge` and `Deny` must be set
* Both must be in range 100-599

### Errors

```go theme={null}
var (
    ErrStatusCodeNotValid = errors.New("config.StatusCode: status code not valid, must be between 100 and 599")
)
```

### Example

```yaml theme={null}
status_codes:
  CHALLENGE: 429
  DENY: 403
```

## DnsTTL

DNS cache TTL settings for reverse DNS lookups.

### Type Definition

```go theme={null}
type DnsTTL struct {
    Forward int `json:"forward"`
    Reverse int `json:"reverse"`
}
```

### Fields

<ParamField path="Forward" type="int" default="300">
  TTL in seconds for forward DNS lookups (hostname to IP). Must be >= 0.
</ParamField>

<ParamField path="Reverse" type="int" default="300">
  TTL in seconds for reverse DNS lookups (IP to hostname). Must be >= 0.
</ParamField>

### Example

```yaml theme={null}
dns_ttl:
  forward: 600
  reverse: 600
```

## Logging

Logging configuration for Anubis.

### Type Definition

```go theme={null}
type Logging struct {
    Sink       string             `json:"sink"`
    Level      *slog.Level        `json:"level"`
    Parameters *LoggingFileConfig `json:"parameters"`
}
```

### Fields

<ParamField path="Sink" type="string" default="stdio">
  Logging output sink. Valid values: `"stdio"`, `"file"`.
</ParamField>

<ParamField path="Level" type="*slog.Level">
  Log level. If set, overrides the level from command-line flags.

  Valid levels:

  * `slog.LevelDebug` (-4)
  * `slog.LevelInfo` (0)
  * `slog.LevelWarn` (4)
  * `slog.LevelError` (8)
</ParamField>

<ParamField path="Parameters" type="*LoggingFileConfig">
  File logging configuration. Required when `Sink` is `"file"`.
</ParamField>

### Validation Rules

* If `Sink` is `"file"`, `Parameters` must be set
* `Parameters` must pass its own validation

### Errors

```go theme={null}
var (
    ErrMissingLoggingFileConfig = errors.New("config.Logging: missing value parameters in logging block")
    ErrInvalidLoggingSink       = errors.New("config.Logging: invalid sink")
)
```

## LoggingFileConfig

File-based logging configuration with log rotation.

### Type Definition

```go theme={null}
type LoggingFileConfig struct {
    Filename     string `json:"file"`
    MaxBackups   int    `json:"maxBackups"`
    MaxBytes     int64  `json:"maxBytes"`
    MaxAge       int    `json:"maxAge"`
    Compress     bool   `json:"compress"`
    UseLocalTime bool   `json:"useLocalTime"`
}
```

### Fields

<ParamField path="Filename" type="string" required>
  Path to the log file.
</ParamField>

<ParamField path="MaxBackups" type="int" default="3">
  Maximum number of old log files to retain. Must be >= 0.
</ParamField>

<ParamField path="MaxBytes" type="int64" default="104857600">
  Maximum size in bytes before rotating the log file (default: 100 MiB).
</ParamField>

<ParamField path="MaxAge" type="int" default="7">
  Maximum number of days to retain old log files. Must be >= 0.
</ParamField>

<ParamField path="Compress" type="bool" default="true">
  Compress rotated log files using gzip.
</ParamField>

<ParamField path="UseLocalTime" type="bool" default="false">
  Use local time for log file timestamps instead of UTC.
</ParamField>

### Validation Rules

* `Filename` must be set
* `MaxBackups` must be >= 0
* `MaxAge` must be >= 0

### Errors

```go theme={null}
var (
    ErrInvalidLoggingFileConfig = errors.New("config.LoggingFileConfig: invalid parameters")
    ErrOutOfRange               = errors.New("config: error out of range")
)
```

### Example

```yaml theme={null}
logging:
  sink: file
  parameters:
    file: "./var/anubis.log"
    maxBackups: 5
    maxBytes: 209715200  # 200 MiB
    maxAge: 14
    compress: true
    useLocalTime: false
```

## OpenGraph

OpenGraph metadata configuration for social media previews.

### Type Definition

```go theme={null}
type OpenGraph struct {
    Override     map[string]string `json:"override,omitempty" yaml:"override,omitempty"`
    TimeToLive   time.Duration     `json:"ttl" yaml:"ttl"`
    Enabled      bool              `json:"enabled" yaml:"enabled"`
    ConsiderHost bool              `json:"considerHost" yaml:"enabled"`
}
```

### Fields

<ParamField path="Enabled" type="bool" default="false">
  Enable OpenGraph tag caching and customization.
</ParamField>

<ParamField path="ConsiderHost" type="bool" default="false">
  Include the request hostname when caching OpenGraph tags.
</ParamField>

<ParamField path="TimeToLive" type="time.Duration">
  Duration to cache OpenGraph tags (e.g., `"5m"`, `"1h"`, `"24h"`).
</ParamField>

<ParamField path="Override" type="map[string]string">
  Custom OpenGraph tags to inject. Keys are tag names (e.g., `"og:title"`).

  Required tags when using overrides:

  * `"og:title"` - Page title
</ParamField>

### Example

```yaml theme={null}
openGraph:
  enabled: true
  considerHost: true
  ttl: "1h"
  override:
    og:title: "My Protected Site"
    og:description: "Protected by Anubis"
    og:image: "https://example.com/og-image.png"
```

## Complete Configuration Example

```yaml theme={null}
store:
  backend: valkey
  parameters:
    address: "localhost:6379"
    db: 0
    poolSize: 20

status_codes:
  CHALLENGE: 429
  DENY: 403

dns_ttl:
  forward: 300
  reverse: 300

logging:
  sink: file
  parameters:
    file: "./var/anubis.log"
    maxBackups: 3
    maxBytes: 104857600
    maxAge: 7
    compress: true
    useLocalTime: false

openGraph:
  enabled: true
  ttl: "30m"
  override:
    og:title: "Protected Site"

bots:
  # Bot rules here...
```
