TechEarl

How to Run Redis in Docker (With AOF + RDB Persistence)

Redis is non-persistent by default in the official image — every restart wipes the data. Enable AOF, mount a volume, and set a password before exposing it. The full recipe with practical usage.

Ishan KarunaratneIshan Karunaratne⏱️ 5 min readUpdated
Share thisCopied

The Redis container is one line — but the default image doesn't persist data, doesn't set a password, and binds on all interfaces. That combination is fine for ten minutes of caching experiments and a disaster for anything else. The full safe version of running Redis in Docker is one extra flag for persistence and one for the password.

How do I run Redis in Docker?

Throwaway (no persistence, no password — for quick caching experiments):

bash
docker run -d --name redis -p 6379:6379 redis:7-alpine

Persistent and password-protected (the version you actually want):

bash
docker run -d --name redis \
  -p 6379:6379 \
  -v redis-data:/data \
  redis:7-alpine \
  redis-server --appendonly yes --requirepass change-me

The trailing redis-server --appendonly yes --requirepass change-me overrides the image's default command to enable AOF persistence and require a password.

Try it with your own values

Configure version, port, password, and volume.

Persistence: AOF and RDB

Redis offers two persistence mechanisms, off by default in the official image.

  • RDB (snapshots). Periodic full-database dumps to a file. Fast to load on start, can lose minutes of data between snapshots.
  • AOF (append-only file). Logs every write. Reloads slower, loses at most a second of data with the default appendfsync everysec.

The conservative pick for "I don't want to lose data" is AOF:

bash
docker run -d --name :container_name \
  -p :host_port:6379 \
  -v :volume:/data \
  redis::redis_version \
  redis-server --appendonly yes --requirepass :password

For both AOF and periodic snapshots (the "save and aof" combination):

bash
docker run -d --name :container_name \
  -p :host_port:6379 \
  -v :volume:/data \
  redis::redis_version \
  redis-server --appendonly yes --save 60 1000 --requirepass :password

--save 60 1000 means "snapshot if 1000 keys changed in 60 seconds." You can repeat the flag for multiple thresholds.

For a cache where losing the data on restart is fine, leave both off — Redis is fastest in pure-memory mode.

Why mount /data even without persistence?

The volume mount on /data gives Redis a place to write its AOF and RDB files. Without the volume, those files live in the container's writable layer and disappear with docker rm. With the volume mounted, even if you flip persistence on later, the files are already in a persistent location.

bash
# Stop and remove the container
docker stop :container_name && docker rm :container_name

# Start a new Redis against the same volume — data is intact (if persistence was on)
docker run -d --name :container_name \
  -p :host_port:6379 \
  -v :volume:/data \
  redis::redis_version \
  redis-server --appendonly yes --requirepass :password

Set a password — always

The default redis-server (without --requirepass) accepts unauthenticated connections from anywhere it's reachable. With -p 6379:6379, that's everyone on your LAN. There are recorded cases of malware hitting unprotected Redis instances within minutes of port 6379 being exposed.

Three options, in order of safety:

  1. --requirepass — set a password. Use a strong one if the host is reachable from anywhere except your dev machine.
  2. Don't publish the port. Without -p, Redis is only reachable from other containers on the same Docker network. App-to-Redis traffic still works; nobody on your LAN can connect.
  3. -p 127.0.0.1:6379:6379 — publish only on the loopback interface. Reachable from the host but not the LAN.

For dev work, -p 127.0.0.1:6379:6379 + no password is fine. For anything else, --requirepass.

Practical usage: connecting to Redis

Using redis-cli inside the container:

bash
docker exec -it :container_name redis-cli
# Then in the prompt:
AUTH :password
PING       # → PONG
SET hello world
GET hello  # → "world"

From the host with redis-cli installed:

bash
redis-cli -h 127.0.0.1 -p :host_port -a :password

From an app (Node.js example):

javascript
import Redis from 'ioredis';
const redis = new Redis({
  host: '127.0.0.1',
  port: 6379,
  password: 'change-me',
});

Use Redis as a session store for a Django app, with both containers on the same Docker network:

yaml
services:
  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes --requirepass change-me
    volumes:
      - redis-data:/data
    restart: unless-stopped

  web:
    image: my-django-app
    environment:
      CACHE_URL: redis://:change-me@redis:6379/1
      SESSION_REDIS_URL: redis://:change-me@redis:6379/2
    depends_on:
      - redis

volumes:
  redis-data:

Different Redis database numbers (/1, /2) keep cache and session data separate without separate Redis instances. Redis supports 16 logical databases by default.

Common pitfalls

  • Default image has no persistence. Restart = data loss. Pass --appendonly yes (and ideally mount a volume on /data).
  • No password and port 6379 published to the LAN. Trivial to compromise. Always either set a password or restrict publishing to loopback (-p 127.0.0.1:6379:6379).
  • Mounting /data but not enabling persistence. Volume exists, Redis doesn't write to it. Combine with --appendonly yes.
  • AOF rewrites blowing the disk. AOF can grow without bound between rewrites. The default auto-aof-rewrite-percentage 100 keeps it bounded; if you change this, watch disk usage.
  • Connecting with localhost and getting refused. Use 127.0.0.1. localhost on some platforms tries a Unix socket Redis isn't listening on.

FAQ

Sources

Authoritative references this article was fact-checked against.

TagsDockerRedisCachePersistenceAOFRDBDevOps

Found this useful? Pass it on.

Copied
Ishan Karunaratne

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts