Running Redis 8 with Docker Compose gives you a cache, queue or key-value store for local development, CI, or a single-server deployment without installing Redis on the host. In this guide you will run the official redis:8.10.3 image with a pinned tag, a password from an .env file, a mounted redis.conf, AOF and RDB persistence on a named volume, and a healthcheck. You will then back Redis up and restore it, including the restore mistake that silently gives you an empty database.
Everything below was tested on Docker Engine 29 with Redis 8.10.3.
What changed in Redis 8
- Modules are bundled. The official image ships Redis Query Engine (
search), JSON, time series and probabilistic data structures (bf), plus vector sets. The entrypoint loads them automatically, as long as the container command starts withredis-server(see Step 3). - Licensing. Redis 8 is available under AGPLv3 again, alongside RSALv2 and SSPLv1. If that matters for your use, read the license, or look at Valkey, the BSD-licensed fork.
- Config,
redis-cliand the protocol are the same as Redis 6 and 7, so existing clients keep working.
Prerequisites
- Docker Engine with the Compose plugin (
docker compose). On Ubuntu see How to Install and Use Docker Engine on Ubuntu 26.04 LTS. - Port
6379free on the host, or pick another host port below.
docker version --format '{{.Server.Version}}'
docker compose version
Quick start with docker run
For a throwaway instance:
docker run -d --name redis-test -p 127.0.0.1:6379:6379 redis:8.10.3
docker exec -it redis-test redis-cli ping
PONG
This has no password and no persistence settings. Remove it with docker rm -f redis-test. For anything you keep, use Compose.
Step 1: Create the project directory
mkdir -p ~/redis && cd ~/redis
Step 2: Store the password in an .env file
Create .env:
REDIS_PASSWORD=change-me-to-a-long-random-password
Generate a strong one with openssl rand -base64 32, then lock the file down and keep it out of Git:
chmod 600 .env
echo ".env" >> .gitignore
Compose reads .env in two ways in this setup: to fill in ${REDIS_PASSWORD} in compose.yaml, and (through env_file) as an environment variable inside the container for the healthcheck.
Step 3: Write redis.conf
Create redis.conf:
# Network: listen inside the container; the host port mapping controls exposure
bind 0.0.0.0
protected-mode yes
port 6379
# Memory: cap usage and evict least-recently-used keys with a TTL first
maxmemory 512mb
maxmemory-policy volatile-lru
# Persistence: RDB snapshots plus an append-only file
save 3600 1 300 100 60 10000
appendonly yes
appendfsync everysec
dir /data
What these do:
maxmemoryandmaxmemory-policy: without a cap, Redis grows until the kernel’s OOM killer stops it.volatile-lruevicts keys that have a TTL. For a pure cache where every key may go, useallkeys-lru. For a queue or primary store, usenoevictionso writes fail instead of data disappearing.appendonly yeswithappendfsync everysec: every write is logged, so you lose at most about one second of data on a crash.save: periodic RDB snapshots (dump.rdb), which are compact and handy for backups.
Keep the password out of redis.conf. The file is bind-mounted and has to be readable by the redis user inside the container, so it is not the place for a secret.
Step 4: Create the Compose file
Create compose.yaml:
services:
redis:
image: redis:8.10.3
container_name: redis
restart: unless-stopped
env_file: .env
command:
- redis-server
- /usr/local/etc/redis/redis.conf
- --requirepass
- ${REDIS_PASSWORD:?set REDIS_PASSWORD in .env}
ports:
- "127.0.0.1:6379:6379"
volumes:
- redis_data:/data
- ./redis.conf:/usr/local/etc/redis/redis.conf:ro
healthcheck:
test: ["CMD-SHELL", "REDISCLI_AUTH=\"$$REDIS_PASSWORD\" redis-cli ping | grep -q PONG"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
volumes:
redis_data:
Key points:
The command starts with
redis-server. The image’s entrypoint only drops root privileges and loads the bundled modules when it seesredis-serveras the first word. A common pattern,command: sh -c "redis-server ... --requirepass $$REDIS_PASSWORD", works but runs Redis as root and without modules. I tested both: withsh -c,/proc/1/statusshowedUid: 0andMODULE LISTreturned onlyvectorset.${REDIS_PASSWORD:?...}: Compose refuses to start if the variable is empty, instead of starting Redis with no password:error while interpolating services.redis.command.[]: required variable REDIS_PASSWORD is missing a value: set REDIS_PASSWORD in .envREDISCLI_AUTHletsredis-cliauthenticate without putting the password on its command line.$$stops Compose from expanding it, so the container’s environment is used.127.0.0.1:6379:6379: reachable from the host only. Other containers in the same project connect toredis:6379without any port mapping. Never publish Redis to the internet; exposed instances are routinely scanned and attacked.Pinned tag: bump
8.10.3on purpose after reading the release notes, not by pullinglatest.
Step 5: Start Redis
docker compose up -d --wait
Container redis Healthy
Check the version, the settings and the loaded modules:
docker exec -e REDISCLI_AUTH="$(grep ^REDIS_PASSWORD .env | cut -d= -f2-)" redis \
redis-cli INFO server | grep redis_version
redis_version:8.10.3
To save typing, open a shell into redis-cli and authenticate once:
docker exec -it redis redis-cli
127.0.0.1:6379> AUTH change-me-to-a-long-random-password
OK
127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "volatile-lru"
127.0.0.1:6379> MODULE LIST
MODULE LIST should show search, vectorset, bf, timeseries and ReJSON.
Without the password, commands are rejected:
docker exec redis redis-cli ping
NOAUTH Authentication required.
Confirm Redis is not running as root:
docker exec redis grep Uid /proc/1/status
Uid: 999 999 999 999
Step 6: Store and read data
Inside redis-cli (after AUTH):
127.0.0.1:6379> SET greeting "hello from compose"
OK
127.0.0.1:6379> GET greeting
"hello from compose"
127.0.0.1:6379> JSON.SET doc $ '{"a":1}'
OK
127.0.0.1:6379> JSON.GET doc
"{\"a\":1}"
Applications connect with a URL such as:
redis://:[email protected]:6379/0
Step 7: Check persistence
Recreate the container and confirm the keys survived:
docker compose down
docker compose up -d --wait
docker exec -e REDISCLI_AUTH="$(grep ^REDIS_PASSWORD .env | cut -d= -f2-)" redis redis-cli GET greeting
hello from compose
The volume now holds the RDB snapshot and the multi-part AOF:
docker exec redis ls /data /data/appendonlydir
/data:
appendonlydir
dump.rdb
/data/appendonlydir:
appendonly.aof.1.base.rdb
appendonly.aof.1.incr.aof
appendonly.aof.manifest
docker compose down keeps the volume. docker compose down -v deletes it, with all your data.
Step 8: Back up and restore Redis
Option 1: back up the whole volume
This keeps both the AOF and the RDB and restores exactly. Compose prefixes the volume with the project (directory) name, so check it first:
docker volume ls | grep redis_data
For a project directory named redis, the volume is redis_redis_data:
docker compose stop redis
docker run --rm -v redis_redis_data:/data -v "$PWD":/backup alpine \
tar czf /backup/redis-data-$(date +%F).tar.gz -C /data .
docker compose start redis
Restore:
docker compose stop redis
docker run --rm -v redis_redis_data:/data -v "$PWD":/backup alpine \
sh -c 'rm -rf /data/* && tar xzf /backup/redis-data-2026-11-10.tar.gz -C /data'
docker compose start redis
Option 2: copy an RDB snapshot while Redis runs
Trigger a snapshot and copy it out, with no downtime:
export REDISCLI_AUTH="$(grep ^REDIS_PASSWORD .env | cut -d= -f2-)"
docker exec -e REDISCLI_AUTH redis redis-cli BGSAVE
docker exec -e REDISCLI_AUTH redis redis-cli INFO persistence | grep rdb_last_bgsave_status
docker cp redis:/data/dump.rdb ./dump-$(date +%F).rdb
Wait for rdb_last_bgsave_status:ok before copying.
Restoring an RDB file needs one extra step when AOF is on. If you copy dump.rdb into an empty volume and start Redis with appendonly yes, Redis creates a new, empty AOF and loads that instead. You get an empty database, with no error. I tested this: DBSIZE returned 0.
Start Redis once with AOF off so it loads the RDB, then turn AOF on, which writes a new AOF from the loaded data:
docker compose stop redis
docker run --rm -v redis_redis_data:/data -v "$PWD":/backup alpine \
sh -c 'rm -rf /data/* && cp /backup/dump-2026-11-10.rdb /data/dump.rdb'
# Temporary instance: no published ports, AOF off
docker compose run -d --rm --name redis-restore redis \
redis-server /usr/local/etc/redis/redis.conf --appendonly no
docker exec redis-restore redis-cli DBSIZE
docker exec redis-restore redis-cli CONFIG SET appendonly yes
docker stop redis-restore
docker compose up -d --wait
The temporary instance has no password, but docker compose run publishes no ports and protected mode only allows loopback connections, so only docker exec can reach it.
Step 9: Tune the host
Redis logs a warning at startup if memory overcommit is disabled on the Docker host, because background saves (BGSAVE, AOF rewrites) can then fail under memory pressure. On a Linux host, enable it:
echo 'vm.overcommit_memory = 1' | sudo tee /etc/sysctl.d/99-redis.conf
sudo sysctl --system
This is a host kernel setting and cannot be set from inside the container.
Useful commands
docker compose logs -f redis # follow the server log
export REDISCLI_AUTH="$(grep ^REDIS_PASSWORD .env | cut -d= -f2-)"
docker exec -e REDISCLI_AUTH redis redis-cli INFO memory | grep used_memory_human
docker exec -e REDISCLI_AUTH redis redis-cli INFO keyspace # keys per database
docker exec -e REDISCLI_AUTH redis redis-cli --latency # live latency (Ctrl+C to stop)
docker exec -e REDISCLI_AUTH redis redis-cli --bigkeys # find the largest keys
Related content
- How to Run PostgreSQL 18 with Docker and Docker Compose
- How to Run RabbitMQ 4 with Docker and Docker Compose
- How to Install and Configure Redis 6 on Debian 11
- How to Install and Configure Redis 6 on Rocky Linux/CentOS 8
- Getting Started With Docker Compose With Examples
Conclusion
You now have Redis 8 running with Docker Compose: a pinned image, the password kept out of the config file and enforced at startup, a non-root process with the bundled modules loaded, AOF and RDB persistence on a named volume, a healthcheck, and two tested backup and restore methods. For high availability, add replicas with Redis Sentinel, or use Redis Cluster for sharding.