How to Configure Redis for Caching and Pub/Sub in OpenCTI

Configure Redis for OpenCTI by setting environment variables like REDIS__MODE, REDIS__HOSTNAME, and REDIS__PORT, then initialize the clients via initializeRedisClients() in opencti-graphql/src/database/redis.ts to enable caching and real-time pub/sub functionality.

OpenCTI relies on Redis as a high-performance in-memory data store to handle session caching, distributed locking, and real-time GraphQL subscriptions. To configure Redis for caching and pub/sub in OpenCTI, you need to understand the client factory architecture in opencti-graphql/src/database/redis.ts and the environment variables that control connection behavior across single, sentinel, and cluster deployment modes.

Redis Configuration Environment Variables

OpenCTI reads Redis connection parameters from environment variables defined in the deployment configuration. These variables control topology, authentication, TLS, and namespace prefixing.

Variable Default Purpose
REDIS__MODE single Deployment topology: single, sentinel, or cluster
REDIS__HOSTNAME localhost Host for single mode
REDIS__HOSTNAMES — JSON array of host:port for cluster or sentinel
REDIS__PORT 6379 Port for single mode
REDIS__USERNAME / REDIS__PASSWORD — Authentication credentials
REDIS__SENTINEL_MASTER_NAME — Master name required for sentinel mode
REDIS__USE_SSL false Enable TLS encryption
REDIS__CA [] Paths to CA certificates for TLS
REDIS__NAMESPACE — Key prefix added to every key (REDIS_PREFIX)
REDIS__TRIMMING 2000000 Max entries in Redis Stream for UI history

The complete reference lives in docs/docs/deployment/configuration.md.

Redis Client Architecture in OpenCTI

The Redis integration centers on a factory function createRedisClient in opencti-graphql/src/database/redis.ts. This factory adapts to your chosen deployment mode and handles TLS, authentication, and namespace prefixing automatically.

// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis.ts
const redisOptions = async (provider: string, autoReconnect = false): Promise<RedisOptions> => ({
  connectionName: connectionName(provider),
  keyPrefix: REDIS_PREFIX,
  ...userPasswordAuth,
  tls: USE_SSL ? { ...configureCA(REDIS_CA), servername: conf.get('redis:hostname') } : undefined,
  retryStrategy: (times) => autoReconnect ? Math.min(times * 50, 2000) : null,
  lazyConnect: true,
  enableOfflineQueue: true,
});

Depending on REDIS__MODE, the factory instantiates:

  • Cluster: new Redis.Cluster(clusterNodes, clusterOpts) with natMap and scaleReads
  • Sentinel: new Redis(sentinelOpts) with master name and sentinel authentication
  • Single: new Redis({ ...singleOptions, db, port, host }) with direct host/port selection

Initializing Redis Clients for Caching and Pub/Sub

During platform startup, redisInit() calls initializeRedisClients() to create four distinct Redis connections:

// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis.ts
export const initializeRedisClients = async () => {
  const base = await createRedisClient('base', true);
  const xrange = await createRedisClient('xrange', true);
  const lock = await createRedisClient('lock', true);
  const publisher = await createRedisClient('publisher', true);
  const subscriber = await createRedisClient('subscriber', true);
  redisClients = {
    base,
    xrange,
    lock,
    pubsub: new RedisPubSub({
      publisher,
      subscriber,
      connectionListener: (err) => {
        logApp.info('[REDIS] Redis pubsub client closed', { error: err });
      },
    }),
  };
};

Each client serves a specific purpose:

  • base: General caching operations (sessions, edit contexts, work progress)
  • xrange: Range queries for UI activity streams
  • lock: Distributed locking via Redlock
  • pubsub: Real-time GraphQL subscriptions using graphql-redis-subscriptions

Implementing Caching with Redis

OpenCTI provides helper functions in opencti-graphql/src/database/redis.ts for common caching patterns. The caching layer uses TTL-based keys and sorted sets for list management.

Transaction Helper

export const redisTx = async (client: Cluster | Redis, chain: (tx: ChainableCommander) => void) => {
  const tx = client.multi();
  await chain(tx);
  return tx.exec();
};

List-Based Caching

The setKeyWithList function stores values with automatic list indexing:

// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis.ts
const setKeyWithList = async (keyId, listIds, keyData, expirationTime) => {
  const keyPromise = getClientBase().set(keyId, JSON.stringify(keyData), 'EX', expirationTime);
  const listsPromise = listIds.map((listId) => setInList(listId, keyId, expirationTime));
  await Promise.all([keyPromise, ...listsPromise]);
  return keyData;
};

Common Cache Types

Cache Helper Functions Use Case
Session (platform_sessions) setSession, getSession, extendSession JWT token storage
Edit Context (edit:{instanceId}:{userId}) setEditContext, fetchEditContext, delEditContext Collaborative UI editing
Work Progress (work:{connectorId}) redisInitializeWork, redisUpdateWorkFigures, redisGetWork Connector import tracking
Telemetry (telemetry_events) redisSetTelemetryAdd, redisGetTelemetry Platform metrics

All cache operations use getClientBase() or getClientLock() for distributed locking.

Configuring Pub/Sub for Real-Time Updates

OpenCTI uses Redis pub/sub to power GraphQL subscriptions for live UI updates. The implementation wraps graphql-redis-subscriptions around dedicated publisher and subscriber clients.

Publishing Events

The notify function in opencti-graphql/src/database/redis.ts publishes changes to subscribers:

// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis.ts
export const notify = async (topic: string, instance: any, user: AuthUser) => {
  if (isNotEmptyField(instance)) {
    const data = Array.isArray(instance)
      ? instance.map((i) => R.dissoc(INPUT_OBJECTS, i))
      : R.dissoc(INPUT_OBJECTS, instance);
    await refreshLocalCacheForEntity(topic, data as unknown as BasicStoreCommon);
    await getClientPubSub().publish(topic, { instance: data, user });
  }
  return instance;
};

The payload includes the instance data (with heavy input objects removed) and the user who performed the action. The function first refreshes the local cache, then publishes to ensure subscribers receive consistent data.

Subscribing in GraphQL Resolvers

Use pubSubAsyncIterator to create subscription resolvers:

// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis.ts
export const pubSubAsyncIterator = (topic: string | string[]) => {
  return getClientPubSub().asyncIterator(topic);
};

export const pubSubSubscription = async <T>(topic: string, onMessage: (message: T) => void) => {
  const subscription = await getClientPubSub().subscribe(topic, onMessage, { pattern: true });
  const unsubscribe = () => getClientPubSub().unsubscribe(subscription);
  return { topic, unsubscribe };
};

Example GraphQL resolver implementation:

const resolvers = {
  Subscription: {
    liveUpdates: {
      subscribe: (_, __, { user }) => {
        const topic = `live:${user.id}`;
        return pubSubAsyncIterator(topic);
      },
    },
  },
};

OpenCTI uses topic patterns like live:${userId} and connector-${id}-logs to route events to specific clients.

Redis Stream Trimming Configuration

OpenCTI stores UI activity history in a Redis Stream managed by opencti-graphql/src/database/redis-stream.ts. To prevent unbounded memory growth, the platform automatically trims streams based on the REDIS__TRIMMING configuration.

// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis-stream.ts
const streamTrimming = conf.get('redis:trimming') || 0;

The default value of 2000000 entries (approximately 8GB) balances history retention with memory usage. Adjust REDIS__TRIMMING based on your infrastructure capacity and audit requirements.

Complete Configuration Example

Docker Compose Setup


# docker-compose.yml

services:
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - redis_data:/data
volumes:
  redis_data:

Environment Configuration


# .env

REDIS__MODE=single
REDIS__HOSTNAME=redis
REDIS__PORT=6379
REDIS__USE_SSL=false
REDIS__NAMESPACE=opencti
REDIS__TRIMMING=2000000

Sentinel Configuration

For high availability, use Redis Sentinel:

REDIS__MODE=sentinel
REDIS__HOSTNAMES=["sentinel1:26379","sentinel2:26379","sentinel3:26379"]
REDIS__SENTINEL_MASTER_NAME=mymaster
REDIS__PASSWORD=your_redis_password

Summary

  • Configuration: Set REDIS__MODE to single, sentinel, or cluster and provide appropriate host and authentication details via environment variables.
  • Client Initialization: The platform creates four dedicated Redis connections (base, xrange, lock, pubsub) through initializeRedisClients() in opencti-graphql/src/database/redis.ts.
  • Caching: Use getClientBase() with helpers like setKeyWithList and redisTx to store sessions, edit contexts, and work progress with TTL support.
  • Pub/Sub: Real-time updates flow through graphql-redis-subscriptions using notify() to publish and pubSubAsyncIterator() to subscribe in GraphQL resolvers.
  • Stream Management: Configure REDIS__TRIMMING to limit UI history stream size in opencti-graphql/src/database/redis-stream.ts.

Frequently Asked Questions

What is the difference between the base Redis client and the pub/sub client in OpenCTI?

The base client (getClientBase()) handles standard caching operations like GET, SET, and ZADD for sessions, edit contexts, and work progress. The pub/sub client (getClientPubSub()) is a specialized connection created by graphql-redis-subscriptions that handles PUBLISH and SUBSCRIBE commands for real-time GraphQL updates. OpenCTI initializes separate physical connections for each role to prevent command interference and enable independent scaling.

How do I enable TLS for Redis connections in OpenCTI?

Set REDIS__USE_SSL=true and provide CA certificate paths via REDIS__CA as a JSON array of file paths. The createRedisClient factory in opencti-graphql/src/database/redis.ts automatically injects TLS options into the Redis connection configuration when USE_SSL is enabled, including the servername parameter for SNI validation.

What happens if Redis becomes unavailable during OpenCTI runtime?

OpenCTI uses ioredis with enableOfflineQueue: true and lazyConnect: true, allowing the application to start even if Redis is temporarily unavailable. The retryStrategy in redisOptions attempts reconnection with exponential backoff up to 2000ms for clients initialized with autoReconnect = true. However, real-time pub/sub functionality will stall until connectivity resumes, and caching operations will queue or fail depending on the specific client configuration.

How do I configure Redis Sentinel for high availability in OpenCTI?

Set REDIS__MODE=sentinel and provide the sentinel host array via REDIS__HOSTNAMES as a JSON string like ["sentinel1:26379","sentinel2:26379"]. You must also specify REDIS__SENTINEL_MASTER_NAME to identify the Redis master instance. The createRedisClient factory automatically constructs sentinel-specific connection options and handles failover detection through the ioredis sentinel implementation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →