# Deploy a Redis or Valkey cache with the redis-cache template

Source: https://docs.quake.ai/resources/deployments/deploy-redis-cache-template
Markdown: https://docs.quake.ai/resources/deployments/deploy-redis-cache-template.md

---

# Deploy a Redis or Valkey cache with the redis-cache template

Stand up a private Valkey or Redis cache on a Quake AI private network using the [validated OpenTofu template](/docs/platform/validation#how-infrastructure-templates-are-checked) `redis-cache`. You set a password and apply the template, confirm the cache binds to the private interface only, connect from an application instance on the same private network, run a key-value and a queue operation, and check persistence behavior.

The template runs Valkey by default (the BSD-licensed Redis fork) and runs Redis OSS with a two-variable change. The cache has no floating IP: it is reachable only from the private network, which is the right shape for a session store, cache, or queue backend that your app tier talks to over private addresses.

<Figure size="md" caption="What you'll build: a private Valkey or Redis cache reachable only from the private network, with append-only persistence on an attached volume, consumed by an application instance on the same subnet">

```d2
direction: right

workstation: Your workstation {
  tofu: OpenTofu CLI
}

cloud: Quake AI {
  private: Private network\n10.20.0.0/24 {
    cache: Cache instance\nport 6379\n(private IP only)
    app: Application instance
    app -> cache: redis:// over private IP
  }
  vol: Block volume\n/data (append-only)
  router: Router\nto PublicStatic
}

workstation.tofu -> cloud: apply
cloud.vol -> cloud.private.cache: persistence
cloud.router -> cloud.private: outbound only
```

</Figure>

<PricingCompanion
  components={[
    { kind: "template", slug: "redis-cache", required: true },
  ]}
/>

## Prerequisites

You need:

- OpenTofu 1.6.0 or later (or Terraform 1.6.0 or later) installed locally.
- Your OpenStack credentials sourced into the shell (`source openrc.sh`). See [the OpenStack CLI guide](/docs/tools/openstack-cli).
- An SSH keypair that already exists in your project. Record its name for the `key_name` variable.
- A way to reach the cache's private subnet after apply, because the template allocates no floating IP: a bastion jump host, a VPN, or an application instance on the same private network. See [How to set up SSH bastion access into a private subnet](/docs/network/how-to/ssh-bastion-access).
- A copy of the `redis-cache` template directory from [the template reference page](/resources/iac-templates/redis-cache).

If private networks are new to you, work through [Build a private network with two virtual machines](/resources/deployments/build-private-network-two-vms) first. It covers the primitives this template wires together.

## Step 1: Set the password and apply the template

The template requires `key_name` and `redis_password`. It ships no default password, so the cache is never reachable without a credential you choose.

Get the template into a dedicated working directory, then load your credentials:

<SourceOpenrc />

Copy the example variables file and open it:

```bash
cp terraform.tfvars.example terraform.tfvars
```

Set the SSH keypair name and a strong password:

```hcl
key_name       = "YOUR_KEY_NAME"
redis_password = "CHOOSE_A_STRONG_PASSWORD"
```

The engine defaults to Valkey. To run Redis OSS instead, add these two lines:

```hcl
redis_image    = "redis:7-alpine"
server_command = "redis-server"
```

Leave `persistence_enabled` at its default of `true` so the cache keeps an append-only file on an attached volume. The remaining variables match the [redis-cache reference page](/resources/iac-templates/redis-cache).

Initialize, preview, and apply:

```bash
tofu init
tofu plan
tofu apply
```

OpenTofu provisions a private network, a subnet on `10.20.0.0/24`, a router to `PublicStatic`, a security group, a block volume (when persistence is on), and the cache instance. Type `yes` to confirm. On first boot, cloud-init mounts the data volume at `/data`, installs Docker, and starts the engine container with `requirepass` set from your password.

When the apply finishes, read the outputs:

```bash
tofu output
```

Record `private_ip` and `connection_string_shape`. The connection string shape is `redis://:REDIS_PASSWORD@PRIVATE_IP:6379/0`; substitute your own password (the secret is not emitted in the output).

## Step 2: Confirm the cache binds to the private interface

The cache must not listen on all interfaces. The template runs the container bound to the instance's private IP, and the security group allows port 6379 only from `private_cidr`.

Open an SSH session to the cache instance from a host that routes to `10.20.0.0/24` (your bastion or a peer instance), using the keypair you set:

```bash
PRIVATE=$(tofu output -raw private_ip)
ssh ubuntu@${PRIVATE}
```

On the instance, confirm the container is running and check what address it listens on:

```bash
sudo docker ps --filter name=redis-cache
sudo ss -tlnp | grep 6379
```

The listening socket shows the private IP and port `6379`, not `0.0.0.0:6379`. A bind to the private address confirms the cache is not exposed on a public interface. Type `exit` to close the session.

## Step 3: Connect from an application instance

Connect from an instance on the same private network, the way your app tier reaches the cache in practice. On that application instance, install a client. The Redis CLI talks to both Valkey and Redis:

```bash
sudo apt-get update && sudo apt-get install -y redis-tools
```

Set the password in the environment so it stays out of the command line and the shell history:

```bash
export REDISCLI_AUTH='CHOOSE_A_STRONG_PASSWORD'
```

Confirm the cache answers, using the private IP from the template output:

```bash
redis-cli -h PRIVATE_IP -p 6379 PING
```

The cache returns `PONG`.

## Step 4: Run a key-value check and a queue operation

Store and read a key to confirm the cache serves reads and writes:

```bash
redis-cli -h PRIVATE_IP -p 6379 SET greeting "hello from quake ai"
redis-cli -h PRIVATE_IP -p 6379 GET greeting
```

`SET` returns `OK` and `GET` returns `"hello from quake ai"`.

A Redis-style list backs a simple job queue. Push two jobs, inspect the queue, then pop the oldest:

```bash
redis-cli -h PRIVATE_IP -p 6379 RPUSH jobs "job-1" "job-2"
redis-cli -h PRIVATE_IP -p 6379 LRANGE jobs 0 -1
redis-cli -h PRIVATE_IP -p 6379 LPOP jobs
```

`RPUSH` returns the list length `2`, `LRANGE` returns both jobs in order, and `LPOP` returns `"job-1"`, the oldest entry. A producer uses `RPUSH` to enqueue and a worker uses `LPOP` (or the blocking `BLPOP`) to dequeue.

## Step 5: Check persistence behavior

With `persistence_enabled = true`, the engine writes an append-only file to `/data`, which is the attached block volume. Data survives a container or instance restart.

To see this, SSH back to the cache instance and restart the container:

```bash
ssh ubuntu@${PRIVATE} "sudo docker restart redis-cache"
```

Wait a few seconds, then read the key again from your application instance:

```bash
redis-cli -h PRIVATE_IP -p 6379 GET greeting
```

The value is still `"hello from quake ai"`, restored from the append-only file on the volume.

If you set `persistence_enabled = false`, the template attaches no volume and the cache runs in memory only. That is the right choice for a pure cache where losing the contents on restart is acceptable, and it skips the volume.

## What you built

- **Applied the `redis-cache` template** with a required password to provision a private network, security group, optional data volume, and a cache instance
- **Confirmed the cache binds to the private IP**, with port 6379 reachable only from `private_cidr` and no floating IP
- **Connected from an application instance** on the same private network with the Redis CLI
- **Ran a key-value check and a list-based queue operation** to confirm reads, writes, and queue semantics
- **Checked append-only persistence** by restarting the container and reading the key back from the volume

## Scope of this deployment

This template runs a single cache instance, not a replicated or clustered cache. There is no automatic failover and no read replica. For a workload that needs high availability, add replication and a failover mechanism yourself, or size a single instance to your working set and accept a restart window. You operate the instance, the engine, and its backups.

## Next steps

- [self-managed Postgres template](/resources/iac-templates/self-managed-postgres): run the relational tier your app pairs with this cache
- [Deploy a Next.js app with the nextjs-app template](/resources/deployments/deploy-nextjs-app-template): wire an app to this cache over the private network with a `REDIS_URL` environment variable
- [How to store application secrets and inject them at runtime](/docs/security/how-to/inject-app-secrets): move the cache password out of plain environment variables
- [Redis / Valkey cache template](/resources/iac-templates/redis-cache): the template reference, parameters, and resource map

## Clean up

When you no longer need the cache, destroy everything the template created, including the instance, the private network, the security group, and the data volume:

```bash
tofu destroy
```

Type `yes` to confirm. Because the append-only file lives on the attached volume, `tofu destroy` removes the cached and persisted data along with the infrastructure. Export anything you want to keep before you destroy.
