# Protect Redis or Valkey

> Backups to your own bucket, restores to any second, Marks, weekly Proof, Rewind, Pulse with one-click fixes, security checks, Tuning, updates and upgrades, logs, users and recommendations for Redis 7.0 and newer and Valkey 7.2 and newer, on your own server or in Docker.

Source: https://rowsafe.sh/docs/guides/redis

Rowsafe protects Redis and Valkey the way it protects your other databases: backups go to **your** bucket, encrypted on your server with a passphrase only you hold; every change is saved as it happens, so you can restore to **any second**; **Marks** save the exact moment before a risky change; a weekly **Proof** restores a copy and checks it; **Rewind** brings deleted keys back or puts the whole server back; **Pulse** watches the server and fixes what it can. Some features aren't there for Redis yet: see [Not yet](#not-yet) and [Limits](#limits).

Valkey is a fork of Redis that speaks the same language and keeps the same files, so everything on this page is the same for both. Where the page says Redis, it means Valkey too.

## What you get

|                                                                             |                                                                                                                                                                                                                              |
| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Backups                                                                     | A full snapshot of the server, encrypted on your server, in your bucket (or [Rowsafe Storage](https://rowsafe.sh/docs/guides/rowsafe-storage)).                                                                                                |
| Restore to any second                                                       | Every change is saved, stamped with the moment it reached Rowsafe's agent, and uploaded about every minute.                                                                                                                  |
| [Marks](https://rowsafe.sh/docs/concepts/restore-points)                                      | Name a moment before a risky change; a restore to it stops exactly there.                                                                                                                                                    |
| [Proof](https://rowsafe.sh/docs/concepts/restore-drills)                                      | Every week, your newest backup is restored into a temporary server and checked.                                                                                                                                              |
| [Rewind](https://rowsafe.sh/docs/guides/restore)                                              | Restore a copy at any second, compare it with production, bring keys back, or rewind the whole server in place, with **Undo** for 7 days.                                                                                    |
| [Pulse](https://rowsafe.sh/docs/guides/monitoring)                                            | Memory, evictions, hit rate, clients, persistence, replication, the slow log and latency, with fixes you apply in one click.                                                                                                 |
| Restart                                                                     | **Restart** in the dashboard, after you confirm.                                                                                                                                                                             |
| [Security check](https://rowsafe.sh/docs/guides/security#redis-and-valkey)                    | A server without a password, protected mode off, a port open to the internet, users allowed `FLUSHALL` or `CONFIG`, versions with known flaws, with one-click fixes (a new password made on your server, shown only to you). |
| [Tuning](https://rowsafe.sh/docs/guides/tuning#redis-and-valkey)                              | The settings that matter in plain words, **Tune for this server** (memory limit, eviction policy for a cache, a store or a queue), changes kept in Redis's config file, undo in one click.                                   |
| [Updates and upgrades](https://rowsafe.sh/docs/guides/updates#redis-and-valkey)               | Bug and security releases with one click (including the October 2025 Lua fixes), and new versions (Redis 7.4 to 8.2, Valkey 8.1 to 9.0) rehearsed on a restored copy first, with undo for 7 days.                            |
| [Logs](https://rowsafe.sh/docs/guides/logs#mysql-mariadb-mongodb-clickhouse-redis-and-valkey) | Redis's own log, redacted on your server, searchable and forwardable.                                                                                                                                                        |
| [Recommendations](https://rowsafe.sh/docs/guides/recommendations#redis-and-valkey)            | Where the memory goes by key-name pattern, keys that never expire, commands that make other clients wait, settings that lose data on a restart. Only patterns like `session:*` leave your server, never key names or values. |
| [Databases & users](https://rowsafe.sh/docs/guides/databases-and-users#redis-and-valkey)      | Add ACL users (read only, read and write, or admin, on the keys you choose), new passwords only you see, and the numbered databases with their keys.                                                                         |
| [Files](https://rowsafe.sh/docs/guides/files) and [second copy](https://rowsafe.sh/docs/guides/second-copy)     | Back up the folders that go with your app, and keep your backups in a second bucket too.                                                                                                                                     |
| [Find the moment](https://rowsafe.sh/docs/guides/find-the-moment)                             | Type a key or a pattern (`user:*`) and see when it was written or deleted, with the moment to rewind to.                                                                                                                     |
| [Safe copies](https://rowsafe.sh/docs/guides/safe-copies)                                     | A masked copy, or one with every key's type and time to live but no data, for development and AI agents.                                                                                                                     |
| [Clones](https://rowsafe.sh/docs/guides/fork)                                                 | The database as it was at any moment, in a new server on the same or another host.                                                                                                                                           |
| [Standby servers](https://rowsafe.sh/docs/guides/standby)                                     | A replica Rowsafe sets up on another server, with promotion and a planned [move to a new server](https://rowsafe.sh/docs/guides/move).                                                                                                         |
| [Move in](https://rowsafe.sh/docs/guides/move-in)                                             | Bring a database in from ElastiCache, MemoryDB, Upstash, Redis Cloud, Azure, DigitalOcean, Aiven or any Redis.                                                                                                               |

## Before you start

- **Redis 7.0 or newer**, or **Valkey 7.2 or newer**. That is the Redis or Valkey that comes with:
  - Debian 12 (Redis 7.0) and Debian 13 (Redis 8.0, Valkey 8.1);
  - Ubuntu 24.04 (Redis 7.0, Valkey 7.2);
  - Redis's own packages ([packages.redis.io](https://packages.redis.io));
  - the official Docker images: `redis` 7.2 to 8.10 and `valkey/valkey` 7.2 to 9.2.
- Ubuntu 22.04's own Redis is 6.0, which is too old. Install Redis from Redis's own packages instead.
- A **standalone** server, with or without replicas of its own. Redis Cluster and servers managed by Sentinel aren't supported yet.
- Redis listens on a TCP port (`6379` by default) without requiring TLS. Rowsafe connects to it from the server itself.
- You have a bucket and an encryption passphrase, as for PostgreSQL. See [Adopt an existing database](https://rowsafe.sh/docs/guides/adopt) for the one-command install.

## Turn on backups

Run the install command on the server and approve the server in your browser when it prints the link:

```bash
curl -fsSL https://rowsafe.sh | sudo sh
```

The installer finds `redis-server` or `valkey-server`. Nothing restarts:

**Rowsafe's own Redis user.** The installer creates an ACL user for Rowsafe, `rowsafe`, with a random password. The password stays on the server, saved for the agent only. The installer also keeps the user across restarts, in Redis's ACL file or its config file, whichever your server uses. What the user may do is [below](#what-rowsafe-may-do).

**Read access to Redis's data folder**, for the agent only. Rowsafe needs it only when it can't follow the server (see [When Rowsafe can't follow the server](#when-rowsafe-cant-follow-the-server)).

**What Rowsafe may do** on the server: restart Redis, only when someone clicks it and confirms. Say no and restart it yourself when it suits you.

**The plan.** You see what Rowsafe will do and say yes. Nothing in Redis's settings changes. Rowsafe checks that a backup reaches your bucket and opens with your key, and takes the first full backup.

On a server without PostgreSQL, the agent runs as its own system user, `rowsafe`.

## What Rowsafe does

|                                         | How                                                                                                                                                                                                                                                                                                                                            |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Backup                                  | A full snapshot of the server (an RDB file), which Redis sends Rowsafe's agent the same way it sends one to a new replica (what `redis-cli --rdb` does). The agent never needs Redis's files for this, so it works across containers too. Redis forks to make it, as it does for any snapshot or new replica. Every backup is a full snapshot. |
| Encryption                              | The agent encrypts the snapshot on your server, before it goes to your bucket (or Rowsafe Storage). Your keys and values never leave the server unencrypted.                                                                                                                                                                                   |
| Every change                            | The agent stays attached to Redis as a replica that never serves anything. It stamps every change with the moment it arrived and uploads the changes about every minute, encrypted.                                                                                                                                                            |
| Restore to any second                   | The newest snapshot before that moment, then the changes up to it, to about a second.                                                                                                                                                                                                                                                          |
| [Marks](https://rowsafe.sh/docs/concepts/restore-points)  | The server's position in its stream of changes at that moment. A restore to a Mark replays exactly up to it.                                                                                                                                                                                                                                   |
| [Proof](https://rowsafe.sh/docs/concepts/restore-drills)  | Weekly: restore the newest backup into a temporary server of the same engine and version, check that it loads and that every logical database (`db0`, `db1`...) has as many keys as when the backup was taken, then replay the changes since and compare with production. The temporary server is deleted afterwards.                          |
| [Rewind](https://rowsafe.sh/docs/guides/restore)          | Restore a copy as it was at any second or a Mark, as a temporary server on the same host, reachable only through a private Unix socket (no network). Compare it with production and bring keys back ([below](#rewind)).                                                                                                                        |
| Rewind the whole server                 | Puts the data back as it was at any second or a Mark, in place, through Redis itself: no restart, never a moment without data. **Undo** for 7 days ([below](#rewind-the-whole-server)).                                                                                                                                                        |
| [Pulse](https://rowsafe.sh/docs/guides/monitoring)        | Memory, evictions, clients, persistence, replication, slow log and latency, with one-click fixes ([below](#pulse)).                                                                                                                                                                                                                            |
| Restart                                 | **Restart** in the dashboard (or `rowsafe restart`), after you confirm ([below](#restart)).                                                                                                                                                                                                                                                    |
| [Files](https://rowsafe.sh/docs/guides/files)             | Back up the folders that go with the database (uploads), restored to the same moment.                                                                                                                                                                                                                                                          |
| [Second copy](https://rowsafe.sh/docs/guides/second-copy) | Weekly full snapshots and the stream of changes also go to a second bucket at another provider, encrypted with that bucket's own passphrase, so it can restore to any second too. Proof alternates between the two.                                                                                                                            |

Before every temporary server (Proof, a Rewind copy), the agent checks there is enough free disk and memory on the server, and refuses with a plain message if there isn't. Temporary servers are capped in memory, so they can't take memory from production.

In Redis's own list of replicas (`INFO replication`), Rowsafe's link shows as `ip=rowsafe-agent`. Rowsafe leaves it out of its own replica counts, but other tools that count replicas will see it.

### When Rowsafe can't follow the server

Some servers refuse Rowsafe's link: the replication commands (`SYNC`, `PSYNC`) are renamed or not allowed for Rowsafe's user, or the server uses `min-replicas-to-write` (Rowsafe's link would count as a replica and weaken that guarantee, so Rowsafe doesn't attach). Then:

- backups are snapshots on the schedule only: Rowsafe asks Redis to save one (`BGSAVE`) and reads it from Redis's own file;
- restores go back to those snapshots, not to any second;
- Marks aren't available (a Mark is a position in the stream of changes Rowsafe can't follow);
- the dashboard says so plainly, and why.

For this the agent needs read access to Redis's data folder: the installer gives it, and in Docker you mount Redis's data volume into the agent, read only.

## Rewind

All of this is in the dashboard, for owners and admins. See [Restore a database](https://rowsafe.sh/docs/guides/restore) for how the buttons work.

- **Restore a copy** at any second or a Mark. It runs as a temporary server on the same host, reachable only through a private Unix socket.
- **Compare** it with production, one logical database at a time: keys only in the copy (deleted since), keys whose value differs, and keys added since. Large databases are sampled, and the result says how many keys were compared.
- **Bring back keys** for a key pattern (like `user:*`) in a logical database. Keys come back with their remaining time to live. Keys that exist in production are never overwritten, unless you choose to.

### Rewind the whole server

**Rewind the whole database** puts every logical database back as it was at the moment you pick, through Redis itself, one logical database at a time: the restored keys are loaded into an empty logical database, then swapped with the live one in an instant (`SWAPDB`). Redis never restarts, and there is never a moment without data.

It needs one empty logical database on the server, and enough free memory for one more copy of your largest logical database. The data from before is kept as a snapshot in your bucket for 7 days: **Undo rewind** puts it back.

## Find the moment

**Find the moment** shows when keys were written or deleted. Type an exact key name (`user:42`) or a pattern (`session:*`, Redis's own patterns), pick a time range, and Rowsafe reads the changes it saved in your bucket, on your server. Each change comes with **Rewind to just before this**.

- Changes are grouped by logical database, pattern and second; a `MULTI`/`EXEC` is one change. `FLUSHDB` and `FLUSHALL` show as emptied databases.
- Only what you typed reaches Rowsafe: results count the keys each change touched under your pattern, never the key names a pattern matched. Values are never read.
- Redis restores to the second, so "just before" a change is the second before it.
- Keys that expired show as deleted (Redis records an expiry as a delete).
- It reads the changes Rowsafe follows: a server [Rowsafe can't follow](#when-rowsafe-cant-follow-the-server) has none to search.

## Safe copies

A [safe copy](https://rowsafe.sh/docs/guides/safe-copies) is a copy of the newest point in your bucket, opened for developers or AI agents on a port of the server, over TLS, for the addresses you allow:

- **Masked**: values are replaced by your rules, per key pattern and field (a hash's fields, a string's value), by what the names suggest (email, phone, name, token...), and wherever a value looks like an email, a phone number, a token or a JSON document. Times to live are kept. Review the rules under **Guard > Masking**.
- **Structure only**: every key with its type and time to live, and no data: strings are empty, hashes keep their field names with empty values, lists, sets, sorted sets and streams keep one empty element.

Redis can't limit logins by address, so Rowsafe's agent listens on the copy's port itself, lets in only the addresses you allowed, speaks TLS, and passes each connection to the copy. On the copy, the only login is the copy's, with the password made in your browser (Rowsafe never sees it), and it can't run administration commands (`CONFIG`, `MODULE`, `DEBUG`, `SAVE`, `REPLICAOF`, `MIGRATE`...). Clients connect with `rediss://` (the certificate is self-signed unless you set your own). Keys of module types (RedisJSON, search indexes) are removed from a copy: their values can't be masked.

## Clones

A [clone](https://rowsafe.sh/docs/guides/fork) is the database as it was at any second (or a Mark), in its own server. The moment is restored privately on the target host (Unix socket only), masked first if you ask, then copied key by key into the target, with times to live.

The target is a server Rowsafe may fill: run the Rowsafe installer on that host with `--redis-clones`. Rowsafe then creates a new Redis server there when you pick the host (its own service, `rowsafe-redis@PORT`, ports 6390 to 6399), or takes an empty server handed to it (`sudo -u rowsafe rowsafe-agent redis login --port PORT --target clones`). The bucket settings and passphrase reach the target host sealed to its agent's key, and are only used for the restore.

Users aren't part of the data: a clone has none of the source's. A server Rowsafe created starts with its default user without a password, which Redis's protected mode lets in from that host only, until you add users.

## Standby servers

A [standby](https://rowsafe.sh/docs/guides/standby) is a real Redis replica that Rowsafe sets up on another server and watches:

1. Run the installer with `--redis-standby` on both servers. On the primary, it lets Rowsafe's user create and remove users (the standby's replication login) and list them; on Redis that amounts to administrator rights, used only when someone adds, promotes or removes a standby. On the standby's server, it lets Rowsafe create a Redis server for it (or hand it an empty one).
2. **Standby > Add a standby** in the dashboard, pick the server and confirm its key fingerprint.

The primary gets a replication login made for that standby, whose password reaches the standby's agent sealed to its key, with the primary's users (names, rules and password hashes) so your apps can sign in to the standby once it is promoted. The standby then copies the data straight from the primary, the way any Redis replica starts (one snapshot), and follows every change, read-only. Pulse shows its lag; Rowsafe's own link never counts as a replica.

- **Promote** makes the standby the primary (`REPLICAOF NO ONE`).
- **Move to a new server** is a planned switchover: the old primary is made to refuse writes for good (fenced: kept in its config file, client connections ended, and its agent keeps it so), the standby gets every last change, then it is promoted. The old server can follow the new one afterwards (**Rebuild as standby**) or let you switch back.
- After a switch, Rowsafe follows the new primary: its first snapshot is a **new base** for restores to any second. Moments before the switch restore from the old server's history, in the same bucket; the minute or so between the switch and that first snapshot can't be restored to a second.
- The primary must listen on an address the standby reaches, and its default user needs a password (protected mode refuses other servers otherwise). Users created on the primary later aren't copied: add them on the standby too.

## Move in

[Move in](https://rowsafe.sh/docs/guides/move-in) brings a database from a managed provider (ElastiCache, MemoryDB, Upstash, Redis Cloud, Azure Cache for Redis, DigitalOcean or Aiven for Valkey) or any Redis into the server Rowsafe protects, which must be empty. Paste the connection string (`rediss://default:password@host:6379`); it is encrypted in your browser to a key the agent made for this move, and only your server can read it.

The check answers in plain words: whether Rowsafe reaches the source, versions (this server must run the same version or newer), modules the source uses that this server lacks, whether the data fits `maxmemory`, the eviction policy, the number of logical databases, and whether live sync is possible.

- **One-time copy**: every key is read from the source and written here with its time to live, a batch at a time (memory stays low, and a copy that stops continues where it was). Managed providers don't let anyone make their database read-only, so stop your apps' writes for the copy; the check says about how long it takes. Key counts are compared at the end.
- **Live sync**: where the source lets replicas connect (a self-hosted Redis, over a plain connection; managed providers don't allow it), this server follows the source until you switch over, so your apps keep writing during the copy. The switchover waits until every change arrived and compares key counts.

Afterwards Rowsafe can make a login for your apps (with `--redis-standby` on this server) and shows its connection string once.

## Pulse

Pulse reads Redis's own statistics every minute (the detailed status every 5 minutes): memory against `maxmemory`, evictions, the hit rate, commands per second, clients (blocked and rejected), fragmentation, persistence (whether snapshots and the append-only file are working), replication (replicas and their lag), the slow log and the latency monitor's events. The slow log reaches Rowsafe as command names only, never keys or values.

Fixes come with **Apply fix** and a confirmation:

| Finding                                                                          | Fix                                                                                                                                                                                                                                    |
| -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Redis is near `maxmemory` and set to refuse writes once full (`noeviction`)      | **Set an eviction policy**, so Redis removes old keys instead of refusing writes.                                                                                                                                                      |
| A lot of memory is fragmented                                                    | **Give memory back** (`MEMORY PURGE`), or **turn on active defragmentation**, which compacts memory in the background at a small CPU cost. Both need Redis built with jemalloc (most Linux builds are); Rowsafe offers them only then. |
| A client looks stuck (blocked for a long time, or holding a large output buffer) | **Disconnect** it. Rowsafe checks it's still the same connection first, and never disconnects replicas or its own link.                                                                                                                |
| Rowsafe's link (or a replica) often needs a whole new snapshot                   | **Raise the replication backlog**, so a short break continues where it stopped.                                                                                                                                                        |

Fixes apply on the running server at once. Rowsafe also keeps them in Redis's config file when Redis can write it; otherwise they last until the next restart, and the result says which.

Security problems (a server without a password, protected mode off, a port open to the internet) are in the [security check](https://rowsafe.sh/docs/guides/security#redis-and-valkey), with their fixes.

## Restart

**Restart** in the dashboard restarts Redis after you confirm, through root's helper, and only for the services root allowed at install (`redis-server`, `valkey-server`...). See [Permissions](https://rowsafe.sh/docs/guides/permissions). In Docker, it works through the optional container control service ([below](#docker)). Rowsafe doesn't restart a server that keeps nothing on its own disk (snapshots and the append-only file both off), since it would come back empty: Pulse offers **Turn on snapshots** first.

## What Rowsafe may do

**Rowsafe's Redis user** (`rowsafe`) gets only what it needs, each used only when someone asks or for the backups you turned on:

- read and inspect the server: backups, Proof, compare and Pulse;
- the replication handshake: the snapshot for backups, and following every change;
- `DUMP` and `RESTORE`: bring keys back from a copy;
- `SWAPDB`, `FLUSHDB` and `DEL`: rewind the whole server in place (only into and out of an empty logical database, and `DEL` only for its own marker key);
- `CONFIG GET`, `CONFIG SET` and `CONFIG REWRITE`, `MEMORY PURGE` and `CLIENT KILL`: the fixes and Tuning;
- `ACL LIST`, `ACL GETUSER`, `ACL USERS`, `ACL SETUSER`, `ACL DELUSER` and `ACL SAVE`: Databases & users and the security fixes (never on its own user, the default user's password only through the security fix, never the users replicas sign in with). An agent installed before these existed lists users only, until you run the installer again; the dashboard says so;
- `BGSAVE`: scheduled snapshots, when Rowsafe can't follow the server.

With `--redis-standby` (standby servers, the apps' login after a move-in) it may also create, list and remove users and run `REPLICAOF`. On a server handed to Rowsafe for a standby or a clone, it has every right: that server is Rowsafe's to fill.

It never sees anything outside Redis.

**Root decides** what Rowsafe may do on the server itself ([permissions](https://rowsafe.sh/docs/guides/permissions), `sudo rowsafe-allow`):

| Permission                                      | Lets Rowsafe                                                                                                                                                                           |
| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `restart`                                       | restart Redis (**Restart**)                                                                                                                                                            |
| `--redis-standby`, `--redis-clones` (installer) | create a new Redis server for a standby or a clone, on ports 6390 to 6399, as its own service (`rowsafe-redis@PORT`, running as `redis`), and remove it when the standby or clone goes |
| `updates`                                       | install Redis's minor updates and upgrade it to a new series (the word `database`)                                                                                                     |
| `tuning`                                        | keep setting changes in Redis's config file (root's helper writes only the settings Tuning offers, keeping a copy)                                                                     |

Rewinding the whole server in place needs no root permission: it swaps data inside Redis.

## Docker

Use the Redis agent image next to the official `redis` or `valkey/valkey` image. There is one image per version, with that version's `redis-server` (or `valkey-server`) inside, which Proof and Rewind copies run: `ghcr.io/rowsafe/agent:redis<version>`, like `redis8.2`, and `ghcr.io/rowsafe/agent:valkey<version>`, like `valkey8.1`. Use the one that matches your server.

```yaml
services:
  redis:
    image: redis:8.2
    # Users, Rowsafe's included, live in an ACL file in the data volume, so they survive restarts.
    # The full example below sets this up.
    volumes:
      - redisdata:/data

  rowsafe-agent:
    image: ghcr.io/rowsafe/agent:redis8.2
    hostname: db-1
    environment:
      ROWSAFE_REDIS_HOST: redis
      ROWSAFE_REDIS_DATA_DIR: /srv/redis-data   # only used when Rowsafe can't follow the server
    env_file: rowsafe-agent.env
    volumes:
      - rowsafe-state:/var/lib/rowsafe
      - redisdata:/srv/redis-data:ro            # read only
```

Start Redis with an ACL file in its data volume, as the full example does, so Rowsafe's user is still there after Redis restarts. The full example is [`deploy/docker/compose.redis.example.yml`](https://github.com/rowsafe/rowsafe/blob/main/deploy/docker/compose.redis.example.yml). Then, once:

```bash
docker compose exec rowsafe-agent rowsafe-agent redis login --port 6379 --admin-user default
rowsafe adopt cache --host db-1 --engine redis --port 6379
rowsafe apply cache
```

`redis login` asks for the administrator's password (type it, one line), creates Rowsafe's user with it, and forgets it: it is used once and never saved. For Valkey, use `--engine valkey`.

### Restart and update in Docker

Without help, restart the Redis container yourself; Rowsafe notices. To get **Restart** in the dashboard, add the container control service, set to your Redis service (`ROWSAFE_CONTROL_SERVICE: redis`). It holds the Docker socket, so the agent never gets it. See [Let Rowsafe restart the container](https://rowsafe.sh/docs/guides/docker#let-rowsafe-restart-the-container) and its [threat model](https://rowsafe.sh/docs/guides/docker#threat-model).

The agent never updates itself in Docker. To update it, download the newest image and recreate only the agent's container. Redis keeps running:

```bash
docker compose pull rowsafe-agent && docker compose up -d rowsafe-agent
```

Name the service: a plain `docker compose pull` also downloads a newer Redis image if there is one, and `docker compose up -d` then restarts Redis to use it. With the container control service, **Update now** in the dashboard does it for you: see [Update the agent from the dashboard](https://rowsafe.sh/docs/guides/docker#update-the-agent-from-the-dashboard).

On a server, the agent updates itself: see [Updating the agent](https://rowsafe.sh/docs/guides/agent-updates).

## Restore without Rowsafe

Your backups don't need Rowsafe to be restored. With your bucket settings and passphrase in the environment (as in `agent.env`), the agent lists a database's snapshots and decrypts one into a `dump.rdb` that any server of the same version loads at startup:

```bash
rowsafe-agent redis download-backup --stanza cache
rowsafe-agent redis download-backup --stanza cache --label 20261003-235013F --to ./dump.rdb
```

Put the file in an empty server's data folder (its `dir`, with `appendonly no`) and start it. This brings back a snapshot; restoring to a second in between needs Rowsafe.

## Not yet

These Rowsafe features aren't available for Redis and Valkey yet. The dashboard says so where you would look for them.

- Connection pooling.
- Migration previews (Redis has no schema to migrate).

## Limits

- **Not supported yet**: Redis Cluster, servers managed by Sentinel, and servers reachable only over TLS or only through a Unix socket.
- **Precision**: a restore to a second uses the moment each change reached the agent, so it is precise to about a second. A restore to a Mark is exact.
- **When the agent is away** (stopped, or the server unreachable) for longer than Redis's replication backlog holds (`repl-backlog-size`, 1 MB by default), Redis sends a whole new snapshot when the agent comes back. That snapshot becomes a new backup by itself, but the time in between can't be restored to a second. When this happens often, Pulse proposes a larger backlog, with a button.
- **Expired keys**: keys whose expiry time has passed by the time of a restore are gone, as Redis drops them itself.
- **Every backup is a full snapshot**, and Redis forks to make it, as it does for its own snapshots and new replicas.
- **Servers Rowsafe can't follow** (replication refused, or `min-replicas-to-write` in use) get scheduled snapshots only, and restore to those snapshots, not to any second. See [above](#when-rowsafe-cant-follow-the-server).
- **Compare** samples large databases; the result says how many keys were compared.
- **Rewinding the whole server** needs an empty logical database and enough free memory for one more copy of the largest logical database.
- **Temporary servers** (Proof, Rewind copies) need free disk and memory on the server; the agent checks first and refuses if there isn't enough.
- **Fixes** last only until the next restart when Redis can't write its config file; the result says so.
- **Standby servers and clones** need the agent installed on the server itself (not as a Docker sidecar); a Redis server in Docker can still hold one, with the agent on the host ([example](https://github.com/rowsafe/rowsafe/blob/main/deploy/docker/compose.redis-standby.example.yml)). A standby starts with a full copy from the primary (one snapshot, as for any replica), not from the backup.
- **After a switch to a standby**, restores to any second start again from the new primary's first snapshot.
- **Move in** copies one standalone database (not a Redis Cluster). Live sync only works from a source that lets replicas connect, over a plain connection; from managed providers it is a one-time copy while writes are stopped.
- **Safe copies and clones** remove keys of module types (RedisJSON, search): they can't be masked or always copied. A clone and a safe copy have none of the source's users.
- **Find the moment** groups writes by second and pattern; keys that expired show as deleted.
- **In Docker**, restart the container yourself unless you add the container control service; for updates, pull the newest agent image of the same version and recreate its container. Redis's own updates and upgrades are a change to your compose file (Pulse shows the step), setting changes last until the container restarts, and logs need `--logfile` in a volume the agent can read.
- **Restart, updates and upgrades** need snapshots or the append-only file on: their restart would empty a server that keeps nothing on disk (Pulse offers **Turn on snapshots**). Updates and upgrades install from your server's package sources on Debian and Ubuntu.
- **Protected mode** can't be turned on from Rowsafe while clients connect over the network (they would be refused) or in Docker.
- **Read and write users** made in Databases & users can't run `KEYS` or `SORT` (Redis counts them as dangerous); give a user the admin preset if an old app needs them.
- **Recommendations** sample up to 10,000 keys per numbered database every 30 minutes, slowly; a key-name pattern is sent only when it covers many sampled keys.
- **Version checks** go by the version number: a fix your distribution added without changing it (Debian, Ubuntu) isn't seen.
