> ## 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 Backends

Anubis requires persistent storage for tracking challenges, cookies, and DNS cache. Choose a storage backend based on your deployment architecture.

## Available Backends

| Backend  | Persistence | Multi-Instance | Use Case                   |
| -------- | ----------- | -------------- | -------------------------- |
| `memory` | No          | No             | Development/testing        |
| `bbolt`  | Yes         | No             | Single-instance production |
| `valkey` | Yes         | Yes            | Multi-instance deployments |
| `s3api`  | Yes         | Yes            | Cloud/serverless           |

## Memory Backend

In-memory hashmap storage. Data is lost on restart.

### Configuration

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

This is the default if no store is configured.

### When to Use

✅ **Use for**:

* Local development
* Testing
* Single-instance with low traffic
* Ephemeral environments

🚫 **Don't use for**:

* Production with high traffic
* Multi-instance deployments
* When you need persistence across restarts

### Limitations

* No size limits (memory grows unbounded)
* Data lost on process restart
* Cannot share state between instances

## BoltDB Backend

Embedded key-value database using [bbolt](https://github.com/etcd-io/bbolt). Data persists to disk.

### Configuration

```yaml theme={null}
store:
  backend: bbolt
  parameters:
    path: /data/anubis.bdb
```

| Parameter | Type   | Required | Description                      |
| --------- | ------ | -------- | -------------------------------- |
| `path`    | string | Yes      | Filesystem path to database file |

### When to Use

✅ **Use for**:

* Single-instance production deployments
* High-traffic single-instance setups
* When persistent storage is required
* VPS/dedicated server deployments

🚫 **Don't use for**:

* Multi-instance deployments (Kubernetes, etc.)
* Environments without persistent filesystem
* Multiple Anubis instances sharing a backend

### File System Requirements

Anubis requires:

1. **Write access** to the directory containing the database file
2. **Exclusive lock** on the database file (one process only)

```bash theme={null}
# Create directory
mkdir -p /var/lib/anubis

# Set permissions
chown anubis:anubis /var/lib/anubis
chmod 750 /var/lib/anubis
```

Configuration:

```yaml theme={null}
store:
  backend: bbolt
  parameters:
    path: /var/lib/anubis/anubis.bdb
```

### Cleanup

BoltDB runs hourly cleanup to remove expired entries. No manual maintenance required.

### Docker Example

```yaml theme={null}
services:
  anubis:
    image: ghcr.io/techarohq/anubis:latest
    volumes:
      - anubis-data:/data
      - ./policy.yaml:/etc/anubis/policy.yaml:ro
    environment:
      - POLICY_FNAME=/etc/anubis/policy.yaml

volumes:
  anubis-data:
```

Policy file:

```yaml theme={null}
store:
  backend: bbolt
  parameters:
    path: /data/anubis.bdb
```

## Valkey/Redis Backend

Remote key-value store using [Valkey](https://valkey.io/) or Redis compatible servers.

### Configuration

#### Standalone

```yaml theme={null}
store:
  backend: valkey
  parameters:
    url: redis://valkey.example.com:6379/0
```

#### Cluster

```yaml theme={null}
store:
  backend: valkey
  parameters:
    url: redis://valkey.example.com:6379/0
    cluster: true
```

#### Sentinel (High Availability)

```yaml theme={null}
store:
  backend: valkey
  parameters:
    sentinel:
      masterName: mymaster
      addr:
        - sentinel1.example.com:26379
        - sentinel2.example.com:26379
        - sentinel3.example.com:26379
      username: anubis
      password: ${VALKEY_PASSWORD}
      clientName: anubis-prod
```

### Parameters

| Parameter  | Type   | Required | Description                        |
| ---------- | ------ | -------- | ---------------------------------- |
| `url`      | string | Yes\*    | Redis connection URL               |
| `cluster`  | bool   | No       | Enable cluster mode                |
| `sentinel` | object | No       | Sentinel configuration (see below) |

\*Either `url` or `sentinel` must be provided.

#### Sentinel Parameters

| Parameter    | Type           | Required | Description               |
| ------------ | -------------- | -------- | ------------------------- |
| `masterName` | string         | Yes      | Sentinel master name      |
| `addr`       | string or list | Yes      | Sentinel server addresses |
| `username`   | string         | No       | Auth username             |
| `password`   | string         | No       | Auth password             |
| `clientName` | string         | No       | Client identifier         |

### When to Use

✅ **Use for**:

* Multi-instance deployments
* Kubernetes/Docker Swarm
* High-availability requirements
* Shared state across instances

🚫 **Don't use for**:

* Single-instance deployments (use bbolt instead)
* If you don't already have Redis/Valkey
* Low-traffic sites (overhead not justified)

### URL Format

```
redis://[username:password@]host[:port][/database]
```

Examples:

```yaml theme={null}
# Basic
url: redis://localhost:6379/0

# With auth
url: redis://user:pass@valkey.internal:6379/0

# TLS (rediss://)
url: rediss://valkey.internal:6380/0
```

### Kubernetes Example

```yaml theme={null}
apiVersion: v1
kind: ConfigMap
metadata:
  name: anubis-policy
data:
  policy.yaml: |
    store:
      backend: valkey
      parameters:
        url: redis://valkey-service:6379/0
    bots:
      - name: browsers
        user_agent_regex: Mozilla
        action: CHALLENGE
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: anubis
spec:
  replicas: 3  # Multiple instances share Valkey
  template:
    spec:
      containers:
      - name: anubis
        image: ghcr.io/techarohq/anubis:latest
        env:
        - name: POLICY_FNAME
          value: /etc/anubis/policy.yaml
        volumeMounts:
        - name: policy
          mountPath: /etc/anubis
      volumes:
      - name: policy
        configMap:
          name: anubis-policy
```

## S3 API Backend

Object storage backend using S3-compatible APIs.

### Configuration

```yaml theme={null}
store:
  backend: s3api
  parameters:
    bucketName: anubis-production
    pathStyle: false
```

### Environment Variables

S3 credentials are read from environment:

```bash theme={null}
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...
AWS_REGION=us-east-1
AWS_ENDPOINT_URL_S3=https://s3.amazonaws.com  # Optional
```

### Parameters

| Parameter    | Type   | Required | Description                          |
| ------------ | ------ | -------- | ------------------------------------ |
| `bucketName` | string | Yes      | S3 bucket name                       |
| `pathStyle`  | bool   | No       | Use path-style URLs (default: false) |

### When to Use

✅ **Use for**:

* Serverless deployments (AWS Lambda, Cloud Run)
* Multi-instance without managing Redis
* Cloud-native deployments
* When object storage is already available

🚫 **Don't use for**:

* High-frequency traffic (S3 API calls are expensive)
* Latency-sensitive applications
* If you can use Redis/Valkey instead

### Supported Providers

* AWS S3
* Cloudflare R2
* Minio
* Tigris
* Backblaze B2
* DigitalOcean Spaces
* Any S3-compatible service

### Lifecycle Policy

Configure bucket lifecycle to auto-delete old objects:

```json theme={null}
{
  "Rules": [
    {
      "Status": "Enabled",
      "Expiration": {
        "Days": 7
      }
    }
  ]
}
```

Anubis stores expiry metadata but doesn't auto-cleanup. Lifecycle policies prevent unbounded growth.

### Example: Cloudflare R2

```bash theme={null}
# Environment
AWS_ACCESS_KEY_ID=<r2-access-key>
AWS_SECRET_ACCESS_KEY=<r2-secret>
AWS_ENDPOINT_URL_S3=https://<account-id>.r2.cloudflarestorage.com
```

```yaml theme={null}
store:
  backend: s3api
  parameters:
    bucketName: anubis-data
    pathStyle: false
```

## Storage Interface

All backends implement the same interface:

```go theme={null}
type Interface interface {
    Get(ctx context.Context, key string) ([]byte, error)
    Set(ctx context.Context, key string, value []byte, expiry time.Duration) error
    Delete(ctx context.Context, key string) error
    IsPersistent() bool
}
```

## Choosing a Backend

### Decision Tree

```
Are you running multiple Anubis instances?
├─ Yes → Use valkey or s3api
│  ├─ Already have Redis/Valkey? → Use valkey
│  └─ Using serverless/cloud? → Use s3api
└─ No → Single instance
   ├─ Production? → Use bbolt
   └─ Development? → Use memory
```

### Comparison

| Feature              | memory  | bbolt | valkey  | s3api       |
| -------------------- | ------- | ----- | ------- | ----------- |
| Persistence          | ❌       | ✅     | ✅       | ✅           |
| Multi-instance       | ❌       | ❌     | ✅       | ✅           |
| Setup complexity     | None    | Low   | Medium  | Medium      |
| Performance          | Fastest | Fast  | Fast    | Slower      |
| Operational overhead | None    | Low   | Medium  | Low         |
| Cost                 | Free    | Free  | \$-\$\$ | \$\$-\$\$\$ |

## Key Generation Warning

When using persistent storage (`bbolt`, `valkey`, `s3api`), always configure a signing key to prevent challenge invalidation on restart:

```bash theme={null}
# Generate Ed25519 key
openssl rand -hex 32 > /etc/anubis/ed25519.key

# Use it
anubis --ed25519-private-key-hex-file /etc/anubis/ed25519.key
```

See [Security](/admin/security) for details.

## Validation Errors

### BoltDB

```yaml theme={null}
store:
  backend: bbolt
  parameters: {}  # Error: ErrMissingPath
```

**Fix**: Provide path:

```yaml theme={null}
store:
  backend: bbolt
  parameters:
    path: /data/anubis.bdb
```

### Valkey

```yaml theme={null}
store:
  backend: valkey
  parameters: {}  # Error: ErrNoURL
```

**Fix**: Provide URL:

```yaml theme={null}
store:
  backend: valkey
  parameters:
    url: redis://localhost:6379/0
```

### S3 API

```yaml theme={null}
store:
  backend: s3api
  parameters: {}  # Error: ErrNoBucketName
```

**Fix**: Provide bucket:

```yaml theme={null}
store:
  backend: s3api
  parameters:
    bucketName: anubis-data
```

## Next Steps

* [Policy Configuration](/admin/policy-configuration) - Configure storage in policy files
* [Security](/admin/security) - Key generation for persistent storage
* [Monitoring](/admin/monitoring) - Monitor storage backend health
