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)withnatMapandscaleReads - 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 streamslock: Distributed locking via Redlockpubsub: Real-time GraphQL subscriptions usinggraphql-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__MODEtosingle,sentinel, orclusterand provide appropriate host and authentication details via environment variables. - Client Initialization: The platform creates four dedicated Redis connections (
base,xrange,lock,pubsub) throughinitializeRedisClients()inopencti-graphql/src/database/redis.ts. - Caching: Use
getClientBase()with helpers likesetKeyWithListandredisTxto store sessions, edit contexts, and work progress with TTL support. - Pub/Sub: Real-time updates flow through
graphql-redis-subscriptionsusingnotify()to publish andpubSubAsyncIterator()to subscribe in GraphQL resolvers. - Stream Management: Configure
REDIS__TRIMMINGto limit UI history stream size inopencti-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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →