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

# Redis Multi-Location

> Deploy Redis Multi-Location on Control Plane using the Template Catalog. Covers configuration, volumes, scaling, and geographically distributed master-replica clustering with Sentinel.

## Overview

Redis Multi-Location deploys a single Redis Sentinel cluster spanning multiple Control Plane locations within one GVC. All Redis replicas across all locations belong to the same cluster — replica 0 in the first location starts as the primary, and Sentinel automatically elects a new primary from any location on failure.

<Note>
  This template creates a new GVC. At least 2 locations are required.
</Note>

### What Gets Created

* **GVC** — A new GVC spanning the configured locations.
* **Stateful Redis Workload** — A single cross-location Redis cluster. Replica 0 in the first location starts as the primary; all others replicate from it. Each replica gets its own persistent volume.
* **Stateful Sentinel Workload** — 1 Sentinel replica per location (not configurable). Monitors the cluster and orchestrates automatic failover across locations.
* **Volume Set** — Persistent storage for Redis data (configurable capacity and autoscaling).
* **Secrets** — Opaque secrets for the Redis and Sentinel configurations, mounted into each container.
* **Identity & Policy** — Separate identities and policies for the Redis and Sentinel workloads, each with `reveal` access to their respective secrets.
* **Domain** *(optional)* — One domain per workload when public access is enabled, exposing Redis and Sentinel at the configured addresses.
* **Backup Cron Workload** *(optional)* — A scheduled backup job that writes Redis snapshots to AWS S3 or GCS. Runs in the first configured location only.

## Installation

To install, follow the instructions for your preferred method:

<CardGroup cols={2}>
  <Card title="UI" href="/template-catalog/install-manage/ui" icon="laptop">
    Browse, install, and manage templates visually
  </Card>

  <Card title="CLI" href="/template-catalog/install-manage/cli" icon="terminal">
    Manage templates from your terminal
  </Card>

  <Card title="Terraform" href="/template-catalog/install-manage/terraform" icon={<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><g fill-rule="evenodd"><path d="M77.941 44.5v36.836L46.324 62.918V26.082zm0 0" fill="#5c4ee5"/><path d="M81.41 81.336l31.633-18.418V26.082L81.41 44.5zm0 0" fill="#4040b2"/><path d="M11.242 42.36L42.86 60.776V23.941L11.242 5.523zm0 0M77.941 85.375L46.324 66.957v36.82l31.617 18.418zm0 0" fill="#5c4ee5"/></g></svg>}>
    Declare templates in your Terraform configurations
  </Card>

  <Card
    title="Pulumi"
    href="/template-catalog/install-manage/pulumi"
    icon={<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" id="Pulumi-Icon--Streamline-Svg-Logos" height="24" width="24">
    <desc>
        Pulumi Icon Streamline Icon: https://streamlinehq.com
    </desc>
    <path fill="#f26e7e" d="M4.683025 13.3318c0.869125 -0.5018 0.870575 -2.1264 0.003225 -3.62865s-2.27504 -2.313275 -3.1441725 -1.811475C0.672945 8.3935 0.6715 10.0181 1.53885 11.52035c0.86735 1.502275 2.27505 2.313275 3.144175 1.81145Zm0.0052 3.2167c0.86735 1.502275 0.865925 3.126875 -0.003225 3.628675 -0.86915 0.5018 -2.2768275 -0.309225 -3.144175 -1.81145 -0.8673525 -1.50225 -0.8659075 -3.126875 0.003225 -3.628675 0.8691325 -0.5018 2.276825 0.309225 3.144175 1.81145Zm5.922875 3.4243c0.86735 1.50225 0.8659 3.126775 -0.003225 3.62875 -0.869125 0.501775 -2.27685 -0.309325 -3.1442 -1.81155 -0.867325 -1.50225 -0.865875 -3.12685 0.00325 -3.628675 0.869125 -0.5018 2.276825 0.309225 3.144175 1.811475Zm-0.001925 -6.845275c0.86735 1.50225 0.8659 3.12685 -0.003225 3.628675 -0.869125 0.5018 -2.276825 -0.309225 -3.144175 -1.811475 -0.86735 -1.50225 -0.8659 -3.12685 0.003225 -3.62865 0.869125 -0.501825 2.276825 0.3092 3.144175 1.81145Z" stroke-width="0.25"></path>
    <path fill="#8a3391" d="M22.45775 11.524125c0.86725 -1.502225 0.865925 -3.12685 -0.003225 -3.62865 -0.869125 -0.501825 -2.276825 0.3092 -3.144175 1.811475 -0.86735 1.50225 -0.8659 3.126825 0.003225 3.62865 0.869125 0.501825 2.276825 -0.3092 3.144175 -1.811475Zm0.000175 3.2151c0.869075 0.5018 0.870625 2.1264 0.003225 3.62865 -0.86735 1.50225 -2.27505 2.313275 -3.144175 1.81145 -0.869125 -0.5018 -0.870575 -2.126425 -0.003225 -3.62865 0.86735 -1.50225 2.27505 -2.313275 3.144175 -1.81145ZM16.536225 18.157875c0.86915 0.501825 0.8706 2.126425 0.00325 3.628675 -0.86735 1.502125 -2.275075 2.313225 -3.1442 1.81145 -0.869125 -0.50175 -0.870575 -2.126425 -0.003225 -3.62865 0.867375 -1.502275 2.27505 -2.3133 3.144175 -1.811475Zm-0.003325 -6.843775c0.869125 0.5018 0.870575 2.126425 0.003225 3.628675s-2.27505 2.313275 -3.1442 1.811475c-0.869125 -0.501825 -0.870575 -2.126425 -0.003225 -3.628675 0.86735 -1.502275 2.27505 -2.313275 3.1442 -1.811475Z" stroke-width="0.25"></path>
    <path fill="#f7bf2a" d="M15.138225 2.06721c0 1.003615 -1.40625 1.817215 -3.14095 1.817215 -1.7347 0 -3.14095 -0.8136 -3.14095 -1.817215C8.856325 1.06359 10.262575 0.25 11.997275 0.25c1.7347 0 3.14095 0.81359 3.14095 1.81721ZM9.2166 5.482375c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172s1.40625 -1.817225 3.14095 -1.817225c1.7347 0 3.14095 0.8136 3.14095 1.817225Zm8.71005 1.8172c1.7347 0 3.14095 -0.813575 3.14095 -1.8172s-1.40625 -1.817225 -3.14095 -1.817225c-1.7347 0 -3.14095 0.8136 -3.14095 1.817225s1.40625 1.8172 3.14095 1.8172Zm-2.788425 1.605625c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172 0 -1.0036 1.40625 -1.8172 3.14095 -1.8172 1.7347 0 3.14095 0.8136 3.14095 1.8172Z" stroke-width="0.25"></path>
    </svg>}
  >
    Declare templates in your Pulumi programs
  </Card>
</CardGroup>

## Configuration

The default `values.yaml` for this template:

```yaml theme={null}
gvc:
  name: my-redis-gvc
  locations: # Replica count applies to Redis workload only; Sentinel always runs 1 per location
    - name: aws-eu-central-1
      replicas: 2
    - name: aws-us-west-2
      replicas: 2
    - name: aws-us-east-1
      replicas: 2

redis:
  image: redis:7.4
  resources:
    cpu: 200m
    memory: 256Mi
  serverCommand: redis-server  # Can be overridden based on the version of redis/valkey image
  # extraArgs: "--maxmemory 200mb --maxmemory-policy allkeys-lru"
  # password: your-redis-password
  publicAccess:
    enabled: false
    address: redis.example-cpln.com
  volumeset:
    initialCapacity: 20 # GiB
    autoscaling:
      enabled: false
      maxCapacity: 100 # GiB
      minFreePercentage: 10
      scalingFactor: 1.2

sentinel:
  image: redis:7.4
  resources:
    cpu: 200m
    memory: 256Mi
  # extraArgs: "--sentinel down-after-milliseconds mymaster 5000 --sentinel failover-timeout mymaster 10000"
  # password: your-sentinel-password
  publicAccess:
    enabled: false
    address: redis-sentinel.example-cpln.com

# Applies to both Redis and Sentinel workloads
firewall:
  internalAllowType: same-gvc # options: same-gvc, same-org, workload-list
  # externalInboundAllowCIDR: "0.0.0.0/0"  # Required when publicAccess is enabled. Comma-separated list.
  # externalOutboundAllowCIDR: "0.0.0.0/0"  # Comma-separated list.
  # workloads:
  #   - //gvc/GVC_NAME/workload/WORKLOAD_NAME

backup:
  enabled: false
  image: controlplanecorporation/redis-backup:1.0
  schedule: "0 2 * * *"  # daily at 2am UTC

  resources:
    cpu: 100m
    memory: 128Mi

  provider: aws # Options: aws or gcp

  aws:
    bucket: my-backup-bucket
    region: us-east-1
    cloudAccountName: my-backup-cloudaccount
    policyName: my-backup-policy
    prefix: "redis/backups"

  gcp:
    bucket: my-backup-bucket
    cloudAccountName: my-backup-cloudaccount
    prefix: "redis/backups"
```

### Locations

* `gvc.name` — Name of the GVC to create. **Must be unique within your organization** if deploying multiple instances.
* `gvc.locations` — List of Control Plane locations to deploy into. At least 2 locations are required.
* `locations[].name` — Location identifier (e.g. `aws-us-east-1`).
* `locations[].replicas` — Number of Redis replicas to run in that location. Sentinel always runs exactly 1 replica per location regardless of this setting.

### Authentication

Authentication is disabled by default. Redis and Sentinel can be configured with independent passwords.

* `redis.password` — Password applied as both `requirepass` and `masterauth` in the Redis configuration.
* `sentinel.password` — Optional separate password for Sentinel-to-Sentinel communication (`requirepass` on the Sentinel process).

### Redis

* `redis.image` — Redis (or Valkey) image to use.
* `redis.resources.cpu` / `redis.resources.memory` — CPU and memory allocated per Redis replica.
* `redis.serverCommand` — Override the server command (e.g. `valkey-server` for Valkey images).
* `redis.extraArgs` — Additional server arguments appended to the startup command.

### Sentinel

Sentinel monitors the Redis primary across all locations and promotes a replica on failure. One Sentinel replica is deployed per location — this is fixed and not configurable. Quorum is calculated automatically based on the number of locations.

* `sentinel.image` — Redis (or Valkey) image to use for Sentinel.
* `sentinel.resources.cpu` / `sentinel.resources.memory` — CPU and memory allocated per Sentinel replica.
* `sentinel.extraArgs` — Additional Sentinel arguments (e.g. custom `down-after-milliseconds` or `failover-timeout`).

### Storage

* `redis.volumeset.initialCapacity` — Initial volume size in GiB for Redis data (default 20).
* `redis.volumeset.autoscaling.enabled` — Automatically expand the volume as it fills. When enabled:
  * `maxCapacity` — Maximum volume size in GiB.
  * `minFreePercentage` — Trigger a scale-up when free space drops below this percentage.
  * `scalingFactor` — Multiply current capacity by this factor when scaling up.

### Public Access

Redis and Sentinel can be exposed over the internet via TCP using Control Plane's domain resource with per-replica port routing.

<Note>
  When `publicAccess` is enabled, a Dedicated Load Balancer is automatically enabled on the GVC. This is required for TCP port routing and is a paid Control Plane feature.
</Note>

* `redis.publicAccess.enabled` — Expose Redis publicly (default: `false`).
* `redis.publicAccess.address` — A domain you control to expose Redis (e.g. `redis.your-domain.com`).
* `sentinel.publicAccess.enabled` — Expose Sentinel publicly (default: `false`).
* `sentinel.publicAccess.address` — A domain you control to expose Sentinel (e.g. `redis-sentinel.your-domain.com`).

DNS records must be added before deploying. If ownership has not been proven, the first deploy will fail and the error message will list the exact TXT and CNAME records required. Add those records in your DNS provider, then upgrade the release to complete the deployment. **Disable DNS proxying** (e.g. Cloudflare's orange cloud) — TCP traffic must pass through directly.

When enabled, a Control Plane domain resource is created for each address. Port mapping is one port per replica:

| Workload | Ports                                                      |
| -------- | ---------------------------------------------------------- |
| Redis    | `6380`, `6381`, ... (one per replica across all locations) |
| Sentinel | `26380`, `26381`, ... (one per location)                   |

`firewall.externalInboundAllowCIDR` must be set when public access is enabled. Without it, inbound external traffic will be blocked.

**Connecting externally:**

```bash theme={null}
# Redis replica 0
redis-cli -h redis.your-domain.com -p 6380 ping

# Redis replica 1
redis-cli -h redis.your-domain.com -p 6381 ping

# Sentinel replica 0 (location 0)
redis-cli -h redis-sentinel.your-domain.com -p 26380 ping
```

### Firewall

A single firewall configuration applies to both the Redis and Sentinel workloads.

* `firewall.internalAllowType` — Controls which workloads can connect internally:

| Value           | Description                                                     |
| --------------- | --------------------------------------------------------------- |
| `same-gvc`      | Allow access from all workloads in the same GVC (recommended)   |
| `same-org`      | Allow access from all workloads in the same organization        |
| `workload-list` | Allow access only from specific workloads listed in `workloads` |

* `firewall.workloads` — List of specific workload links, used when `internalAllowType` is `workload-list`.
* `firewall.externalInboundAllowCIDR` — Comma-separated list of CIDRs allowed to reach the workloads externally. **Required when public access is enabled.** Use `0.0.0.0/0` to allow all, or restrict to specific IP ranges.
* `firewall.externalOutboundAllowCIDR` — Comma-separated list of CIDRs the workloads are allowed to connect to externally.

### Connecting to Redis

All replicas across all locations belong to a single cluster and are accessible within the GVC. Replica 0 in the first configured location starts as the primary.

**Option 1 — Load-balanced endpoint (any replica):**

```text theme={null}
RELEASE_NAME-redis.GVC_NAME.cpln.local:6379
```

**Option 2 — Direct to a specific replica:**

```text theme={null}
replica-0.RELEASE_NAME-redis.LOCATION.GVC_NAME.cpln.local:6379
replica-1.RELEASE_NAME-redis.LOCATION.GVC_NAME.cpln.local:6379
```

**Option 3 — Via Sentinel to always write to the current primary:**

```bash theme={null}
MASTER_INFO=$(redis-cli -h RELEASE_NAME-sentinel.GVC_NAME.cpln.local -p 26379 SENTINEL get-master-addr-by-name mymaster)
MASTER_HOST=$(echo $MASTER_INFO | cut -d' ' -f1)
MASTER_PORT=$(echo $MASTER_INFO | cut -d' ' -f2)
redis-cli -h $MASTER_HOST -p $MASTER_PORT SET my-key "Hello world"
```

For Sentinel-aware clients, connect through:

```text theme={null}
RELEASE_NAME-sentinel.GVC_NAME.cpln.local:26379
```

The Sentinel master name is `mymaster`.

### Ports

| Workload          | Port                  | Protocol | Description                               |
| ----------------- | --------------------- | -------- | ----------------------------------------- |
| Redis             | `6379`                | TCP      | Redis data port (internal)                |
| Sentinel          | `26379`               | TCP      | Sentinel discovery port (internal)        |
| Redis (public)    | `6380`, `6381`, ...   | TCP      | One port per replica across all locations |
| Sentinel (public) | `26380`, `26381`, ... | TCP      | One port per location                     |

## Backup

Backup is disabled by default. When enabled, a cron workload runs in the first configured location only and uploads a single compressed `.rdb.gz` snapshot to AWS S3 or GCS. The backup image is compatible with all Redis versions.

* `backup.enabled` — Enable scheduled backups.
* `backup.schedule` — Cron expression for backup frequency (default: daily at 2am UTC).
* `backup.provider` — `aws` or `gcp`.
* `backup.resources.cpu` / `backup.resources.memory` — Resources for the backup cron container.

### AWS S3

Before enabling backup with `provider: aws`, complete the following in your AWS account:

1. Create an S3 bucket. Set `backup.aws.bucket` to its name and `backup.aws.region` to its region.
2. If you do not have a Cloud Account set up, refer to the docs to [Create a Cloud Account](/guides/create-cloud-account). Set `backup.aws.cloudAccountName` to its name.
3. Create an IAM policy with the following JSON, replacing `YOUR_BUCKET_NAME`:

```json theme={null}
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject",
                "s3:ListBucket",
                "s3:GetObjectVersion",
                "s3:DeleteObjectVersion"
            ],
            "Resource": [
                "arn:aws:s3:::YOUR_BUCKET_NAME",
                "arn:aws:s3:::YOUR_BUCKET_NAME/*"
            ]
        }
    ]
}
```

4. Set `backup.aws.policyName` to the name of the policy created in step 3.
5. Set `backup.aws.prefix` to the folder path where backups will be stored.

### GCS

Before enabling backup with `provider: gcp`, complete the following in your GCP account:

1. Create a GCS bucket. Set `backup.gcp.bucket` to its name.
2. If you do not have a Cloud Account set up, refer to the docs to [Create a Cloud Account](/guides/create-cloud-account). Set `backup.gcp.cloudAccountName` to its name.
3. Add the **Storage Admin** role to the GCP service account associated with the Cloud Account.
4. Set `backup.gcp.prefix` to the folder path where backups will be stored.

## Restoring a Backup

The backup produces a single file (`redis-<timestamp>.rdb.gz`). Download and decompress it, then copy it to `/data/dump.rdb` on the replica you want to restore and restart that replica.

For GCS, replace `aws s3 cp s3://...` with `gsutil cp gs://...`.

```sh theme={null}
aws s3 cp s3://BUCKET_NAME/PREFIX/BACKUP_FILE.rdb.gz - \
  | gunzip > /tmp/dump.rdb
```

## External References

<CardGroup cols={2}>
  <Card title="Redis Documentation" icon="book" href="https://redis.io/docs/">
    Official Redis documentation
  </Card>

  <Card title="Redis Sentinel Documentation" icon="book" href="https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/">
    Redis Sentinel setup and client configuration
  </Card>

  <Card title="Backup Image Source" icon="github" href="https://github.com/controlplane-com/backup-images/tree/main/redis-backup">
    Source code for the Redis backup container image
  </Card>

  <Card title="Redis Multi-Location Template" icon="github" href="https://github.com/controlplane-com/templates/tree/main/redis-multi-location">
    View the source files, default values, and chart definition
  </Card>
</CardGroup>
