Skip to content

Redis ​

UseImageStatus
Redisredis:8.8.2-trixiedefault

Pinned, as every compose file and Dockerfile writes them:

text
redis:8.8.2-trixie@sha256:37227fff5638322f4ebea25d6d0dc3ee50848604e82b81426f11507b3ec7d2cc

The tag and digest come from the approved images table; when they disagree, the table wins.

Local development ​

docker run
sh
docker run -d --name redis-dev \
  -p 127.0.0.1:6379:6379 \
  -v redis-dev-data:/data \
  --health-cmd 'redis-cli ping | grep -q PONG' \
  --health-interval 5s --health-timeout 5s --health-retries 10 \
  redis:8.8.2-trixie@sha256:37227fff5638322f4ebea25d6d0dc3ee50848604e82b81426f11507b3ec7d2cc \
  redis-server --appendonly yes
check docker run
sh
docker exec redis-dev redis-cli set hello world
docker exec redis-dev redis-cli get hello

Connect with redis://127.0.0.1:6379/0; there is no password locally. Remove it, data included, with docker rm -f redis-dev && docker volume rm redis-dev-data.

On a server ​

Prepare the host once, next to the compose file. Redis reads its password from its config file, so the config is a folder mounted read-only (see config mounts) and owned by the redis user.

prepare the host
sh
mkdir -p redis
cat > redis/redis.conf <<CONF
appendonly yes
requirepass $(openssl rand -hex 24)
CONF
sudo chown -R 999:999 redis
sudo chmod 0400 redis/redis.conf
compose.yml
yaml
services:
  redis:
    image: redis:8.8.2-trixie@sha256:37227fff5638322f4ebea25d6d0dc3ee50848604e82b81426f11507b3ec7d2cc
    command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
    volumes:
      - ./redis:/usr/local/etc/redis:ro
      - redis-data:/data
    ports:
      - "127.0.0.1:6379:6379"
    read_only: true
    cap_drop: [ALL]
    cap_add: [CHOWN, SETGID, SETPCAP, SETUID]
    security_opt:
      - no-new-privileges:true
    healthcheck:
      test: ["CMD", "setpriv", "--reuid=redis", "--regid=redis", "--clear-groups", "sh", "-c", "REDISCLI_AUTH=\"$$(sed -n 's/^requirepass //p' /usr/local/etc/redis/redis.conf)\" redis-cli ping | grep -q PONG"]
      interval: 10s
      timeout: 5s
      retries: 5
    stop_grace_period: 30s
    restart: unless-stopped
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

volumes:
  redis-data: {}
check compose
sh
docker compose exec -u redis redis sh -c 'REDISCLI_AUTH="$(sed -n "s/^requirepass //p" /usr/local/etc/redis/redis.conf)" redis-cli set hello world'

The service connects with the same password, from its own .env, as redis://:<password>@redis:6379/0.

Why each line is there:

  • appendonly yes. Every write is logged to disk, so a restart loses at most a second of writes instead of everything since the last snapshot.
  • The password in a config folder, not on the command line. A --requirepass argument is visible to anyone who can run ps or docker inspect.
  • REDISCLI_AUTH in the health check, for the same reason: redis-cli -a puts the password on the command line. The check runs as the redis user (setpriv), because only that user can read the config.
  • The capabilities. The entrypoint starts as root, fixes the data folder's owner and drops to the redis user (999) with setpriv; these four are what that needs.
  • read_only. Redis writes only to /data.
  • Port on 127.0.0.1. Never publish Redis on 0.0.0.0: an exposed Redis is taken over within hours.

Upgrading ​

Replace every redis:latest with the pinned tag. Moving from 7.x to 8 is an image change and a restart; take a snapshot first (redis-cli BGSAVE, then copy dump.rdb).