Redis is the most widely used in-memory data store in the world for caching, queues and sessions, and with Docker you have it running in a minute. In this guide you bring up Redis from a single docker-compose.yml file, learn how to enable persistence on a volume so you do not lose data on restart, how to protect it with a password (mandatory in Docker) and how to wire it up as a cache for other applications. At the end we compare Redis with Valkey, the free fork that has reshaped the map. The same explanation is available in Spanish.

Key takeaways

  • Redis is an in-memory key-value database: it keeps data in RAM, so it answers in microseconds and is used mostly as a cache, a job queue and a session store.
  • With Docker a single service in docker-compose.yml is enough; state is stored in the /data volume through RDB snapshots and the AOF log, so it survives a container restart.
  • The official image ships with protected mode disabled to ease inter-container networking, so you must set a password with --requirepass and never publish port 6379 to the Internet.
  • Pin a specific image version (for example redis:8.2-alpine) instead of :latest, so you decide when you move to a new major version.
  • Since version 8.0 Redis is no longer purely open source; if that licensing worries you, Valkey[1] is a drop-in replacement under the BSD license, maintained by the Linux Foundation.

What is Redis used for?

Redis (REmote DIctionary Server) is an in-memory data-structure store created by Salvatore Sanfilippo in 2009. Unlike PostgreSQL, which stores everything on disk with durability in mind, Redis keeps data in RAM and optionally persists it to disk, so its reads and writes are measured in microseconds. That speed explains its three most common uses:

  • Caching. You store the result of an expensive query (a page, a user object, an API response) with an expiry date and serve it from memory until it expires. This is why WordPress, Nextcloud and Paperless-ngx all recommend Redis.
  • Queues and background jobs. Libraries like Celery, Sidekiq, BullMQ and RQ use Redis lists and streams to enqueue tasks (send emails, generate thumbnails) and process them outside the web request.
  • Sessions and shared state. Being external to the application, several replicas of a service can share sessions, rate-limit counters or distributed locks.

Redis goes well beyond the classic key-value pair: it offers lists, sets, hashes, sorted sets, streams and publish-subscribe, all with atomic commands.

The Redis docker-compose.yml with persistence

Create a folder for the project and save this docker-compose.yml inside it. Instead of writing the password in the file, we read it from an environment variable, a good practice explained in the environment variables and secrets in Docker guide:

services:
  redis:
    image: redis:8.2-alpine
    restart: unless-stopped
    command: >
      redis-server
      --requirepass ${REDIS_PASSWORD}
      --appendonly yes
      --appendfsync everysec
      --save 60 1000
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 30s
      timeout: 5s
      retries: 5
    networks:
      - backend

networks:
  backend:

volumes:
  redis_data:

Next to the Compose file, create a .env file with the password (Docker Compose reads it automatically). Generate a long, random string, not a dictionary word:

REDIS_PASSWORD=change_this_very_long_random_key

Notice the command options. With --appendonly yes you enable the AOF log, which records every write; with --appendfsync everysec that log is flushed to disk once per second, so in the worst case you lose one second of data. And --save 60 1000 also keeps RDB snapshots: one every 60 seconds if there have been at least 1000 changes. Everything is stored in the redis_data volume, mounted at /data. Note there is no ports section: Redis is reachable only inside the backend network, which is exactly what you want.

Start the stack and check that the container is healthy:

docker compose up -d
docker compose ps
docker compose logs -f redis

When docker compose ps shows the healthy status, Redis is ready. The healthcheck runs redis-cli ping with the password and expects a PONG.

How do you protect Redis with a password?

This is the point most people overlook. The official Redis image starts with protected mode disabled so that other containers can connect without friction, which means a Redis with port 6379 published and no password is open to anyone who reaches that address. There have been mass cryptomining campaigns that exploit exactly that oversight.

The rule is twofold: always set a password with --requirepass (as in the Compose above) and do not publish the port unless you need to. If you truly need to access it from the host, bind the publication to the local interface so it never listens on the Internet:

    ports:
      - "127.0.0.1:6379:6379"

To enter the interactive Redis console and try commands, run redis-cli inside the container and authenticate:

docker compose exec redis redis-cli
127.0.0.1:6379> AUTH change_this_very_long_random_key
OK
127.0.0.1:6379> SET greeting "hello"
OK
127.0.0.1:6379> GET greeting
"hello"

If you are going to expose Redis outside the server, the right move is not to open the port but to encrypt the connection with TLS or route it through a private network; publishing 6379 in the open is not an alternative.

Redis as a cache for other applications

Redis rarely lives alone; it is usually the cache for another service. The connection is made through the service name inside a shared Docker network. Imagine your application is in the same docker-compose.yml: you pass it the host redis, port 6379 and the password, and that is it.

A real example is Nextcloud, which uses Redis for transactional file locking. In its Compose file, the application container receives these variables:

    environment:
      REDIS_HOST: redis
      REDIS_HOST_PASSWORD: change_this_very_long_random_key

The pattern repeats almost everywhere: WordPress with the Redis Object Cache plugin, Paperless-ngx as a task broker or Authentik for its sessions. What matters is that the host is the service name, not localhost, and that both containers share a network. Because Redis does not publish its port, only the services on that network can talk to it, which greatly reduces the attack surface.

Redis versus Valkey: which should you choose?

This is worth pausing on, because Redis licensing changed. For fifteen years Redis was open-source software under the BSD license. In 2024 the company relicensed it to source-available models (RSALv2 and SSPLv1), which are not recognised open-source licenses. The community responded by forking the code: Valkey was born, starting from the last free version, Redis 7.2.4, under the Linux Foundation and with the BSD license.

Since Redis 8.0 (May 2025) the company added the AGPLv3 option again, so today Redis ships under a triple license (RSALv2, SSPLv1 or AGPLv3) and the latest stable version is 8.8.0. Valkey, for its part, is a drop-in replacement: it speaks the same protocol, understands the same commands and reads the same data files. Switching is as simple as swapping the image:

    image: valkey/valkey:8-alpine

Which should you choose? If you want a clear-cut free license, or if your distribution already ships Valkey by default (Debian, Ubuntu, Fedora and Arch do), Valkey is the safe bet. If you need the features Redis 8 folded back into the core (JSON, search, time series, vector sets), Redis has them built in, whereas in Valkey they are separate modules. For 99% of caching, queue and session use cases, the two are interchangeable.

Frequently asked questions

Does Redis lose data if I restart the container?

No, if you enable persistence and mount the volume, as in the Compose in this guide. With --appendonly yes Redis records every write in the AOF file under /data, and on boot it rebuilds the state from it. Without a volume or without persistence, Redis behaves as a pure cache and would indeed lose everything on restart, which is sometimes exactly what you want.

Do I really need a password on an internal network?

Yes. Even if you do not publish the port, the password is a cheap second barrier: if another container on the network is compromised, or if you accidentally end up exposing 6379, --requirepass prevents trivial access. It is one line in the Compose file and there is no good reason to skip it in a serious deployment.

What is the difference between the alpine and standard images?

The -alpine variant is based on Alpine Linux and is much smaller (a few megabytes versus the Debian image), ideal for a lightweight cache. The standard, Debian-based image is somewhat larger but includes more system utilities. For Redis, which barely needs the operating system, the Alpine version is the usual choice.

Conclusion

With a single service in docker-compose.yml you have a fast, persistent, password-protected Redis, ready to serve as a cache, queue or session store for the rest of your containers. Remember the two golden rules: never leave it without a password and never publish port 6379 in the open. The logical next step is to wire it up to a real application, such as Nextcloud, and calmly decide whether you stay with Redis or make the jump to Valkey.

Sources

  1. Valkey
  2. Official redis image on Docker Hub
  3. Official Redis documentation: persistence

Route: Self-hosted databases and storage with Docker