Comparing Threat Intelligence Approaches
Diving into Cyber Threat Intelligence (CTI) quickly reveals a hard truth: raw data feeds are a chaotic mess without a central hub. You usually face a fork in the road. You can either sign a high-five-figure contract with a managed SaaS provider or build your own instance. Commercial platforms offer convenience, but they often charge per user or per indicator. As your data grows, those costs spiral. Furthermore, you end up sharing your internal investigation patterns with a third-party vendor.
Self-hosting OpenCTI puts you in the driver’s seat. You own the data, the infrastructure, and the privacy. Because it’s built on the STIX2 standard, it speaks the same language as almost every modern security tool. For engineers, setting this up is a masterclass in modern architecture. You’ll work directly with Elasticsearch for search, RabbitMQ for messaging, and Redis for caching. It is a complete security ecosystem in a box.
The Reality of Self-Hosting OpenCTI
Running your own stack is rewarding, but it requires a clear-eyed look at the trade-offs.
The Benefits
- Total Data Sovereignty: Your internal investigations and sensitive indicators never leave your network.
- Predictable Costs: A $40/month VPS can often handle what a SaaS provider would charge thousands for.
- Unlimited Customization: You can build custom connectors for niche industry feeds or internal proprietary logs.
- Advanced Mapping: The platform’s knowledge graphs allow you to pivot from a single IP to a full campaign involving specific APT groups and malware families.
The Challenges
- Heavy Resource Demand: OpenCTI is a microservices beast. It isn’t something you can run on a $5 Raspberry Pi.
- Operational Overhead: You are the DBA and the SysAdmin. Backups, schema updates, and database tuning fall on your shoulders.
- Complexity: Moving from simple CSV blacklists to the STIX2 graph model involves a steep learning curve.
Hardware Requirements
I’ve seen many setups fail because users tried to skimp on RAM. OpenCTI’s sub-services are memory-hungry. To avoid constant crashes and “Out of Memory” (OOM) errors, stick to these minimums:
- CPU: 4 Cores minimum. 8 Cores if you plan to ingest heavy feeds like AlienVault or OSINT daily.
- RAM: 16GB is the baseline. Elasticsearch alone will want 4GB to 8GB to keep queries snappy.
- Storage: 50GB+ NVMe or SSD. High IOPS are critical for the database performance.
- OS: Ubuntu 22.04 LTS is the most stable choice for Docker-based deployments.
Step-by-Step Implementation Guide
Docker Compose is the best way to orchestrate this stack. It manages the OpenCTI API, the frontend, and the four mandatory dependencies: Redis, Elasticsearch, MinIO, and RabbitMQ.
1. Initialize the Environment
Start by creating a clean workspace. Organization prevents headaches during future updates.
mkdir opencti-docker && cd opencti-docker
2. Secure Your Credentials
OpenCTI relies on several UUIDs and passwords to link its services. Security isn’t optional here. I recommend using a browser-based tool like toolcraft.app to generate your keys. It processes everything locally, so your secrets never cross the wire. You will need a UUID v4 for the Admin ID and unique strings for RabbitMQ and MinIO.
3. Configure the Environment File (.env)
We use an .env file to keep sensitive data out of our logic files. This is a standard DevOps best practice. Create the file with nano .env and populate it:
[email protected]
OPENCTI_ADMIN_PASSWORD=your_strong_password
OPENCTI_ADMIN_TOKEN=your_uuid_v4_here
OPENCTI_BASE_URL=http://localhost:8080
# Database Tuning
ELASTICSEARCH_MEMORY=4G
REDIS_HOST=redis
MINIO_ROOT_USER=opencti
MINIO_ROOT_PASSWORD=your_secure_minio_pass
# RabbitMQ Credentials
RABBITMQ_DEFAULT_USER=opencti
RABBITMQ_DEFAULT_PASS=your_secure_rabbit_pass
4. Define the Docker Compose Stack
The docker-compose.yml file acts as the blueprint. It ensures that the database and message broker start before the API attempts to connect. Note the versioning; using the latest stable image (currently 6.0.x) is recommended.
version: '3'
services:
redis:
image: redis:7.2.4
restart: always
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.2
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms${ELASTICSEARCH_MEMORY} -Xmx${ELASTICSEARCH_MEMORY}"
restart: always
minio:
image: minio/minio
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
command: server /data
restart: always
rabbitmq:
image: rabbitmq:3.12-management
environment:
RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS}
restart: always
opencti:
image: opencti/platform:6.0.10
environment:
- APP__ADMIN__EMAIL=${OPENCTI_ADMIN_EMAIL}
- APP__ADMIN__PASSWORD=${OPENCTI_ADMIN_PASSWORD}
- APP__ADMIN__TOKEN=${OPENCTI_ADMIN_TOKEN}
- REDIS__HOSTNAME=redis
- ELASTICSEARCH__URL=http://elasticsearch:9200
- MINIO__ENDPOINT=minio
- MINIO__PORT=9000
- RABBITMQ__HOSTNAME=rabbitmq
ports:
- "8080:8080"
depends_on:
- redis
- elasticsearch
- minio
- rabbitmq
5. Launch and Monitor
Fire up the stack with a single command. The initial boot can take 3 to 5 minutes as Elasticsearch builds its indices and the platform runs migrations.
docker-compose up -d
Watch the startup process to catch any early errors:
docker-compose logs -f opencti
Once you see the [OPENCTI] Platform ready message, point your browser to http://your-server-ip:8080. Log in using the credentials from your .env file.
Populating the Platform
An empty CTI platform is just a fancy dashboard with no value. To make it useful, you need to deploy “Connectors.” These are lightweight containers that bridge OpenCTI with external data sources. There are over 100 official connectors available.
I suggest starting with the MITRE ATT&CK and Abuse.ch connectors. They provide an immediate baseline of known adversary tactics and active malicious URLs. Keep an eye on your disk usage; a busy instance can easily generate 10GB of index data in its first week.

