SOC Lab Deployment Documentation: TheHive 5.2 + Cortex + MISP + Dependencies
This documentation describes the complete deployment of a Security Operations Center (SOC) lab environment using Docker Compose. The stack…
SOC Lab Deployment Documentation: TheHive 5.2 + Cortex + MISP + Dependencies
This documentation describes the complete deployment of a Security Operations Center (SOC) lab environment using Docker Compose. The stack includes:

Step-by-Step Deployment Process
Step 1: Create a project directory and necessary subdirectories/files:
mkdir -p ~/soc-lab/{cortex/logs,server-configs,logs,files,ssl}
cd ~/soc-lab
Place your docker-compose.yml in ~/soc-lab/.
~/soc-lab/
├── docker-compose.yml # Main compose file
├── thehive.conf # TheHive configuration (MISP integration)
├── cortex/
│ ├── logs/ # Cortex log directory
│ └── application.conf # Cortex configuration
├── server-configs/ # MISP configuration files
├── logs/ # MISP logs
├── files/ # MISP file storage
└── ssl/ # SSL certificates
Step 2: Add User to Docker Group (Optional but Recommended)
sudo usermod -aG docker $USER
newgrp docker
Step 3: Create TheHive Configuration File
TheHive requires an application.conf file. Create ~/soc-lab/thehive.conf
nano ~/soc-lab/thehive.conf
Paste this content:
# ============================================
# TheHive 5.2 Configuration File
# ============================================
# MISP Module Enable
play.modules.enabled += org.thp.thehive.connector.misp.MispModule
# MISP Server Configuration
misp {
interval: 1 hour
servers: [
{
name = "MISP"
url = "https://misp.local" # MISP container name (Docker DNS)
auth {
type = key
key = "Yl1M7biMolOcb1qk7HCgNih3OjpUyUJqesDXtazB"
}
tags = ["tag1", "tag2", "tag3"]
caseTemplate = "misp"
includedTheHiveOrganisations = ["Morgan Maxwell"]
# SSL/TLS Settings (for self-signed certs)
wsConfig.ssl.loose.acceptAnyCertificate = true
wsConfig.ssl.loose.allowWeakCiphers = true
}
]
}
Step 4: Create Cortex Configuration
Create ~/soc-lab/cortex/application.conf
nano ~/soc-lab/cortex/application.conf
Paste this content:
# ============================================
# Cortex Configuration File
# ============================================
# Application Secret (generate a strong one for production)
play.http.secret.key="changeme-please-generate-a-32-char-secret-key-here"
# Search Configuration (Elasticsearch)
search {
index = cortex
uri = "http://elasticsearch:9200"
}
# Analyzer Paths
analyzer {
path = ["/opt/cortex/analyzers"]
}
# Job Directories
job {
directory = "/tmp/cortex-jobs"
dockerDirectory = "/tmp/cortex-jobs"
}
# Authentication
auth {
method = [
{
name = local
provider = local
}
]
}
# Organization Settings
organization {
name = "SOC-Lab"
}
Step 5: Create the Docker Compose File
nano ~/soc-lab/docker-compose.yml
Paste this COMPLETE configuration:
# ============================================
# SOC Lab Stack - Docker Compose
# TheHive 5.2 + Cortex + MISP + Dependencies
# ============================================
services:
# ------------------------------------------
# 1. CASSANDRA (TheHive Database)
# ------------------------------------------
cassandra:
image: cassandra:4
container_name: soc-cassandra
restart: unless-stopped
ports:
- "9042:9042"
environment:
- CASSANDRA_CLUSTER_NAME=TheHive
- CASSANDRA_NUM_TOKENS=256
- CASSANDRA_START_RPC=true
volumes:
- cassandradata:/var/lib/cassandra
networks:
- SOC_NET
healthcheck:
test: ["CMD", "cqlsh", "-e", "describe keyspaces"]
interval: 30s
timeout: 10s
retries: 5
# ------------------------------------------
# 2. ELASTICSEARCH (Search & Indexing)
# ------------------------------------------
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.9
container_name: soc-elasticsearch
restart: unless-stopped
mem_limit: 512m
ports:
- "9200:9200"
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- cluster.name=hive
- http.host=0.0.0.0
- "ES_JAVA_OPTS=-Xms256m -Xmx256m"
- bootstrap.memory_lock=true
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- elasticsearchdata:/usr/share/elasticsearch/data
networks:
- SOC_NET
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9200/_cluster/health"]
interval: 30s
timeout: 10s
retries: 5
# ------------------------------------------
# 3. MINIO (S3-Compatible Object Storage)
# ------------------------------------------
minio:
image: quay.io/minio/minio:latest
container_name: soc-minio
restart: unless-stopped
command: ["server", "/data", "--console-address", ":9002"]
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=minioadmin
ports:
- "9002:9002"
volumes:
- miniodata:/data
networks:
- SOC_NET
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9002/minio/health/live"]
interval: 30s
timeout: 10s
retries: 3
# ------------------------------------------
# 4. CORTEX (Observable Analysis Engine)
# ------------------------------------------
cortex.local:
image: thehiveproject/cortex:latest
container_name: soc-cortex
restart: unless-stopped
environment:
- job_directory=/tmp/cortex-jobs
- docker_job_directory=/tmp/cortex-jobs
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /tmp/cortex-jobs:/tmp/cortex-jobs
- ./cortex/logs:/var/log/cortex
- ./cortex/application.conf:/cortex/application.conf:ro
depends_on:
elasticsearch:
condition: service_healthy
ports:
- "9001:9001"
networks:
- SOC_NET
# ------------------------------------------
# 5. THEHIVE (Incident Response Platform)
# ------------------------------------------
thehive:
image: strangebee/thehive:5.2
container_name: soc-thehive
restart: unless-stopped
depends_on:
cassandra:
condition: service_healthy
elasticsearch:
condition: service_healthy
minio:
condition: service_healthy
cortex.local:
condition: service_started
mem_limit: 1500m
ports:
- "9000:9000"
environment:
- JVM_OPTS="-Xms1024M -Xmx1024M"
command:
- --secret
- "lab123456789"
- "--cql-hostnames"
- "cassandra"
- "--index-backend"
- "elasticsearch"
- "--es-hostnames"
- "elasticsearch"
- "--s3-endpoint"
- "http://minio:9002"
- "--s3-access-key"
- "minioadmin"
- "--s3-secret-key"
- "minioadmin"
- "--s3-use-path-access-style"
volumes:
- ./thehive.conf:/etc/thehive/application.conf:ro # FIXED: Bind mount for config
- thehivedata:/etc/thehive/data # Data volume
networks:
- SOC_NET
# ------------------------------------------
# 6. MISP MYSQL (Database for MISP)
# ------------------------------------------
misp_mysql:
image: mysql/mysql-server:5.7
container_name: soc-misp-mysql
restart: unless-stopped
volumes:
- mispsqldata:/var/lib/mysql
environment:
- MYSQL_DATABASE=mispdb
- MYSQL_USER=mispuser
- MYSQL_PASSWORD=misppass
- MYSQL_ROOT_PASSWORD=mispass
networks:
- SOC_NET
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 30s
timeout: 10s
retries: 5
# ------------------------------------------
# 7. REDIS (Cache for MISP)
# ------------------------------------------
redis:
image: redis:latest
container_name: soc-redis
restart: unless-stopped
networks:
- SOC_NET
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
# ------------------------------------------
# 8. MISP (Threat Intelligence Platform)
# ------------------------------------------
misp.local:
image: coolacid/misp-docker:core-latest
container_name: soc-misp
restart: unless-stopped
depends_on:
misp_mysql:
condition: service_healthy
redis:
condition: service_healthy
ports:
- "80:80"
- "443:443"
volumes:
- "./server-configs/:/var/www/MISP/app/Config/"
- "./logs/:/var/www/MISP/app/tmp/logs/"
- "./files/:/var/www/MISP/app/files"
- "./ssl/:/etc/nginx/certs"
environment:
- MYSQL_HOST=misp_mysql
- MYSQL_DATABASE=mispdb
- MYSQL_USER=mispuser
- MYSQL_PASSWORD=misppass
- MYSQL_ROOT_PASSWORD=mispass
- MISP_ADMIN_EMAIL=mispadmin@lab.local
- MISP_ADMIN_PASSPHRASE=mispadminpass
- MISP_BASEURL=https://192.168.0.107 # ← REPLACE WITH YOUR IP
- TIMEZONE=Asia/Dhaka
- INIT=true
- CRON_USER_ID=1
- REDIS_FQDN=redis
- HOSTNAME=https://192.168.0.107 # ← REPLACE WITH YOUR IP
networks:
- SOC_NET
# ------------------------------------------
# 9. MISP MODULES (Enrichment Services)
# ------------------------------------------
misp-modules:
image: coolacid/misp-docker:modules-latest
container_name: soc-misp-modules
restart: unless-stopped
environment:
- "REDIS_BACKEND=redis"
depends_on:
- redis
- misp_mysql
networks:
- SOC_NET
# ============================================
# VOLUMES
# ============================================
volumes:
miniodata:
cassandradata:
elasticsearchdata:
thehivedata:
mispsqldata:
# ============================================
# NETWORKS
# ============================================
networks:
SOC_NET:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
Step 6: Fix MISP Configuration Issues
Your MISP container has placeholder <IP> values. Replace these with your actual server IP or domain:
# Get your server IP
ip addr show | grep "inet " | head -1
# Example: If your IP is 192.168.1.100, use:
# MISP_BASEURL=https://192.168.1.100
# HOSTNAME=https://192.168.1.100
environment:
- MISP_BASEURL=https://192.168.1.100 # ← Replace with your IP
- HOSTNAME=https://192.168.1.100 # ← Replace with your IP
Step 7: Deploy the Stack
cd ~/soc-lab
# Pull images first
docker-compose pull
# Start services (detached mode)
docker-compose up -d
# Check service status
docker-compose ps
Step 8: Access & Initial Setup
| Service | URL | Purpose |
| ----------------- | ---------------------------- | ------------------- |
| **TheHive** | `http://YOUR_SERVER_IP:9000` | Incident Response |
| **Cortex** | `http://YOUR_SERVER_IP:9001` | Observable Analysis |
| **MISP** | `https://YOUR_SERVER_IP` | Threat Intelligence |
| **MinIO Console** | `http://YOUR_SERVER_IP:9002` | File Storage |
| **Elasticsearch** | `http://YOUR_SERVER_IP:9200` | Search Index |
Step 9: Enable Firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow necessary ports
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # MISP HTTP
sudo ufw allow 443/tcp # MISP HTTPS
sudo ufw allow 9000/tcp # TheHive
sudo ufw allow 9001/tcp # Cortex
sudo ufw allow 9002/tcp # MinIO Console
sudo ufw enable
Step 10: All Services — User & Password Table
# Generate strong passwords
openssl rand -base64 32
| # | Service | URL | Username / Email | Password | Notes |
| - | ----------- | --------------------------- | --------------------- | --------------------- | ----------------------------------------------- |
| 1 | **TheHive** | `http://192.168.0.107:9000` | `admin@thehive.local` | `secret` | Change on first login |
| 2 | **Cortex** | `http://192.168.0.107:9001` | Create on first setup | Create on first setup | Click "Update Database", then create superadmin |
| 3 | **MISP** | `https://192.168.0.107` | `mispadmin@lab.local` | `mispadmin |
Quick Commands Reference
# Start all services
docker-compose up -d
# Stop all services
docker-compose down
# Stop and remove volumes (WARNING: deletes data)
docker-compose down -v
# View logs
docker-compose logs -f [service_name]
# Restart specific service
docker-compose restart thehive
# Scale check (resource monitoring)
docker stats
Appendix: Network Diagram
┌─────────────────────────────────────────┐
│ Docker Network: SOC_NET │
│ (Subnet: 172.20.0.0/16) │
│ │
│ ┌──────────┐ ┌──────────────┐ │
│ │ TheHive │◄──►│ Cassandra │ │
│ │ :9000 │ │ :9042 │ │
│ └────┬─────┘ └──────────────┘ │
│ │ │
│ │ ┌──────────────┐ │
│ │ │Elasticsearch │ │
│ │ │ :9200 │ │
│ │ └──────────────┘ │
│ │ │
│ │ ┌──────────────┐ │
│ │ │ MinIO │ │
│ │ │ :9002 │ │
│ │ └──────────────┘ │
│ │ │
│ └────────►┌──────────────┐ │
│ │ Cortex │ │
│ │ :9001 │ │
│ └──────────────┘ │
│ │
│ ┌──────────┐ ┌──────────────┐ │
│ │ MISP │◄──►│ MISP MySQL │ │
│ │ :80/443 │ │ :3306 │ │
│ └────┬─────┘ └──────────────┘ │
│ │ │
│ └────────►┌──────────────┐ │
│ │ Redis │ │
│ │ :6379 │ │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────┘ 메타데이터
- post_id
- c7f494d780ca
- slug
- soc-lab-deployment-documentation-thehive-5-2-cortex-misp-dependencies-c7f494d780ca
- url
- https://medium.com/@mahimsec/soc-lab-deployment-documentation-thehive-5-2-cortex-misp-dependencies-c7f494d780ca
- canonical_url
- https://medium.com/@mahimsec/soc-lab-deployment-documentation-thehive-5-2-cortex-misp-dependencies-c7f494d780ca
- author_url
- https://medium.com/@mahimsec
- status
- ok
- fetched_at
- 2026-06-20 20:29:01