Overview
Every mature security operation needs a way to manage incidents — not just detect them. Detection tools like Wazuh, Suricata, and Falco generate alerts, but alerts alone are not a workflow. You need a place to open cases, assign analysts, track observables, run enrichment queries, and document the investigation from first alert to final resolution.
TheHive is the open-source answer. Originally built by CERT-BDF and now maintained by StrangeBee, it is a scalable Security Incident Response Platform (SIRP) used by SOC teams, CSIRTs, and MSSPs worldwide. TheHive 5 brings multi-tenancy, a redesigned API, and native S3 storage support — making it a solid fit even for single-analyst homelabs.
In this project you will:
- Deploy TheHive 5 with its full production backend stack (Cassandra + Elasticsearch + MinIO) using Docker Compose
- Configure organizations, users, and custom alert templates
- Connect Cortex for automated observable enrichment
- Wire Wazuh alerts into TheHive cases via the custom integration script
- Validate the full pipeline from SIEM alert to open case
This stack pairs naturally with Wazuh XDR/SIEM and Shuffle SOAR if you already have those running.
Architecture
TheHive 5 splits its concerns across four services:
| Service | Role | Storage |
|---|---|---|
| TheHive | Web UI, REST API, case engine | Cassandra (data), Elasticsearch (index), MinIO (files) |
| Cassandra 4 | Primary data store for cases, alerts, users | Local volume |
| Elasticsearch 7 | Full-text index for fast search | Local volume |
| MinIO | S3-compatible blob store for attachments | Local volume |
Optional fifth service: Cortex runs as a sibling container and exposes an API TheHive calls to run analyzers against observables (IP addresses, domains, file hashes).
┌─────────────────────────────┐
│ Analyst Browser │
└──────────────┬──────────────┘
│ :9000
┌──────────────▼──────────────┐
│ TheHive 5 │
│ Case · Alert · Observable │
└──────┬───────┬──────┬───────┘
│ │ │
┌────────────▼┐ ┌───▼───┐ ┌▼────────┐
│ Cassandra │ │ ES │ │ MinIO │
│ (data) │ │(index)│ │ (files) │
└─────────────┘ └───────┘ └─────────┘
Wazuh Manager ──► custom-w2thive.py ──► TheHive REST API
Cortex ──► Analyzers/Responders ◄─ TheHive (on-demand)
All services communicate on an isolated Docker network. Only TheHive's port 9000 is exposed to the host.
Prerequisites
- Docker 24+ and Docker Compose v2
- 8 GB RAM minimum (Cassandra and Elasticsearch are memory-hungry)
- 20 GB free disk for volumes
- A running Wazuh stack (optional, for the integration section)
Step 1 — Directory Structure
Create a working directory to hold your Compose file and configuration:
mkdir -p ~/thehive/{cassandra-data,elasticsearch-data,minio-data,cortex-data}
cd ~/thehiveStep 2 — Docker Compose Stack
Create docker-compose.yml:
version: "3.8"
services:
cassandra:
image: cassandra:4.1
container_name: thehive-cassandra
restart: unless-stopped
environment:
CASSANDRA_CLUSTER_NAME: thehive-cluster
CASSANDRA_DC: dc1
CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
MAX_HEAP_SIZE: "1G"
HEAP_NEWSIZE: "256M"
volumes:
- ./cassandra-data:/var/lib/cassandra
networks:
- thehive-net
healthcheck:
test: ["CMD", "cqlsh", "-e", "describe keyspaces"]
interval: 30s
timeout: 10s
retries: 10
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.9
container_name: thehive-elasticsearch
restart: unless-stopped
environment:
discovery.type: single-node
xpack.security.enabled: "false"
ES_JAVA_OPTS: "-Xms512m -Xmx512m"
volumes:
- ./elasticsearch-data:/usr/share/elasticsearch/data
networks:
- thehive-net
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:9200/_cluster/health || exit 1"]
interval: 20s
timeout: 10s
retries: 10
minio:
image: minio/minio:latest
container_name: thehive-minio
restart: unless-stopped
command: server /data --console-address ":9090"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: "${MINIO_PASSWORD}"
volumes:
- ./minio-data:/data
networks:
- thehive-net
thehive:
image: strangebee/thehive:5.2
container_name: thehive
restart: unless-stopped
depends_on:
cassandra:
condition: service_healthy
elasticsearch:
condition: service_healthy
minio:
condition: service_started
ports:
- "9000:9000"
environment:
TH_SECRET: "${TH_SECRET}"
command:
- --cql-hostnames
- cassandra
- --index-backend
- elasticsearch
- --es-hostnames
- elasticsearch
- --s3-endpoint
- http://minio:9000
- --s3-access-key
- minioadmin
- --s3-secret-key
- "${MINIO_PASSWORD}"
- --s3-bucket
- thehive
- --s3-use-path-access-style
networks:
- thehive-net
cortex:
image: thehiveproject/cortex:3.1.7
container_name: thehive-cortex
restart: unless-stopped
ports:
- "9001:9001"
volumes:
- ./cortex-data:/var/run/cortex
- /var/run/docker.sock:/var/run/docker.sock
environment:
JOB_DIRECTORY: /tmp/cortex-jobs
networks:
- thehive-net
networks:
thehive-net:
driver: bridgeCreate the .env file (never commit this):
# Generate secrets
TH_SECRET=$(openssl rand -hex 32)
MINIO_PASSWORD=$(openssl rand -base64 20 | tr -dc 'a-zA-Z0-9' | head -c 20)
cat > .env <<EOF
TH_SECRET=${TH_SECRET}
MINIO_PASSWORD=${MINIO_PASSWORD}
EOF
echo "Secrets written to .env"
cat .envStep 3 — Start the Stack
Bring up the services. Cassandra takes 30–60 seconds to become ready the first time:
docker compose up -d
# Watch the startup sequence
docker compose logs -f thehiveWait for this line before proceeding:
[info] o.t.Application - Application started
TheHive should now be reachable at http://localhost:9000.
Step 4 — First Login and Initial Configuration
Open http://localhost:9000 in your browser.
Default credentials: admin@thehive.local / secret
Change the admin password immediately: click your avatar (top-right) → Edit profile → Change password.
Create an Organisation
In TheHive multi-tenancy model, all work happens inside an organisation:
- Navigate to Admin → Organisations → Create organisation
- Name:
SOC-Lab, Description:Security operations lab - Click Create
Create an Analyst User
- Admin → Users → Create user
- Fill in name, email (e.g.
analyst@soc.lab), and set role to Analyst - Assign them to
SOC-Lab - Set a password and save
Generate an API Key
You will need this for the Wazuh integration:
- Log out and log back in as the new analyst (or stay as admin for the integration key)
- Click avatar → Edit profile → API Key → Create
- Copy and store the key — it is shown only once
# Store it in your .env for later use
echo "THEHIVE_API_KEY=your_copied_key_here" >> .envStep 5 — Custom Case Templates
Case templates save time by pre-populating tasks, custom fields, and tags for common incident types.
- Go to Admin → Case Templates → Create template
- Name:
Phishing Alert - Add tasks:
Triage,Collect Headers,Block Sender,User Notification,Post-Incident Review - Tags:
phishing,email - Severity:
Medium - Save
Create similar templates for Malware Execution, Brute Force, and Data Exfiltration — these map directly to Wazuh rule categories you will pipe in later.
Step 6 — Connect Cortex
Cortex is TheHive's analysis and response engine. It runs hundreds of analyzers (VirusTotal, Shodan, AbuseIPDB, etc.) against observables attached to cases.
Initialize Cortex
Navigate to http://localhost:9001 and follow the setup wizard:
- Create an admin account
- Create an organization matching your TheHive org name (
SOC-Lab) - Create an API key for TheHive to use
Enable Free Analyzers
- Go to Organization → Analyzers → Refresh
- Enable the free analyzers that don't need API keys:
AbuseIPDB_1_0— IP reputationRobtex_Forward_FQDN_Lookup_1_0— DNS historyDNSScan_1_0— DNS recordsMaxMind_GeoIP_3_0— GeolocationURLScan_io_Scan_0_1— URL analysis (needs free API key)
For VirusTotal and others, sign up for free API keys and configure them under the analyzer's configuration tab.
Link Cortex to TheHive
Back in TheHive:
- Admin → Cortex → Add Cortex server
- URL:
http://cortex:9001 - API Key: paste the key you generated in Cortex
- Click Test connection — it should return green
Now, when you view an observable in a case, a Run analyzers button will appear.
Step 7 — Wazuh Integration
This section forwards Wazuh alerts (level 10+) to TheHive as alerts, which an analyst can promote to cases.
Install the Integration Script on Wazuh Manager
# On the Wazuh manager container or host
pip3 install thehive4py requests
# Download the community integration script
curl -o /var/ossec/integrations/custom-w2thive \
https://raw.githubusercontent.com/thehive-project/Wazuh/master/custom-w2thive.py
chmod +x /var/ossec/integrations/custom-w2thiveCreate the companion configuration file /var/ossec/integrations/custom-w2thive.conf:
[thehive]
# TheHive endpoint and API key
url = http://thehive:9000
apikey = YOUR_THEHIVE_API_KEY
# Minimum Wazuh alert level to forward (0 = all, 10 = high)
lvl_threshold = 10
# Tags to apply to every TheHive alert created
tags = wazuh,auto-generated
# Map Wazuh severity to TheHive severity (1=Low, 2=Medium, 3=High, 4=Critical)
# Default mapping: Wazuh lvl 1-7 → Low, 8-11 → Medium, 12-14 → High, 15+ → CriticalWire into ossec.conf
Add the following block inside <ossec_config> in /var/ossec/etc/ossec.conf:
<integration>
<name>custom-w2thive</name>
<hook_url>http://thehive:9000</hook_url>
<api_key>YOUR_THEHIVE_API_KEY</api_key>
<level>10</level>
<alert_format>json</alert_format>
</integration>Restart the Wazuh manager:
docker restart wazuh-manager
# or systemctl restart wazuh-manager on bare-metalVerify Alert Flow
Trigger a test alert (SSH brute force simulation works well):
# From any host — run a few failed SSH attempts to trigger rule 5712/5763
for i in {1..10}; do
ssh -o BatchMode=yes -o ConnectTimeout=1 baduser@your-wazuh-agent 2>/dev/null
doneWithin 30–60 seconds, check TheHive: Alerts → you should see a new Wazuh Alert entry. Click it, review the observable data (source IP, agent name, rule description), and click Create case to promote it.
Step 8 — Validate the Full Pipeline
Run through this checklist to confirm the stack is working end-to-end:
# 1. Confirm all containers are running
docker compose ps
# 2. Check TheHive API health
curl -s http://localhost:9000/api/v1/status | python3 -m json.tool
# 3. List open alerts via API
curl -s -H "Authorization: Bearer YOUR_API_KEY" \
http://localhost:9000/api/v1/alert?max=5 | python3 -m json.tool
# 4. Create a test alert via API
curl -s -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Test Alert from API",
"description": "Verifying TheHive API integration",
"type": "external",
"source": "test",
"sourceRef": "test-001",
"severity": 2,
"tags": ["test"]
}' \
http://localhost:9000/api/v1/alert | python3 -m json.toolYou should see the test alert appear in the TheHive UI under Alerts.
Deployment Considerations
Reverse Proxy
Put Traefik or Caddy in front of TheHive if you want HTTPS and a proper domain:
# Add to the thehive service in docker-compose.yml
labels:
- "traefik.enable=true"
- "traefik.http.routers.thehive.rule=Host(`thehive.yourdomain.local`)"
- "traefik.http.routers.thehive.entrypoints=websecure"
- "traefik.http.routers.thehive.tls=true"
- "traefik.http.services.thehive.loadbalancer.server.port=9000"Backups
Back up the three persistent volumes on a schedule:
#!/bin/bash
BACKUP_DIR=/backups/thehive/$(date +%Y-%m-%d)
mkdir -p "$BACKUP_DIR"
# Stop stack for consistent snapshot
docker compose stop thehive
# Archive volumes
tar -czf "$BACKUP_DIR/cassandra.tar.gz" ./cassandra-data
tar -czf "$BACKUP_DIR/elasticsearch.tar.gz" ./elasticsearch-data
tar -czf "$BACKUP_DIR/minio.tar.gz" ./minio-data
docker compose start thehive
echo "Backup complete: $BACKUP_DIR"Resource Tuning
On systems with less than 16 GB RAM, reduce Elasticsearch and Cassandra heap sizes:
# Elasticsearch: reduce from 512m to 256m each
ES_JAVA_OPTS: "-Xms256m -Xmx256m"
# Cassandra: reduce from 1G to 512m
MAX_HEAP_SIZE: "512M"
HEAP_NEWSIZE: "128M"Extensions and Next Steps
Shuffle SOAR integration: Connect Shuffle to TheHive so that when a case is created, an automated playbook fires — isolating a host, sending a Slack notification, or enriching all observables in bulk. TheHive exposes webhooks under Admin → Webhooks that Shuffle can receive.
MISP threat intelligence: TheHive can sync IoCs from a MISP instance. Under Admin → MISP, point it at your MISP URL and API key. Any MISP event matching your filter will appear as a TheHive alert automatically.
Custom dashboards: TheHive 5 has a built-in dashboard builder. Create views tracking MTTD (mean time to detect) and MTTR (mean time to respond) by plotting alert-to-case promotion time against case close time.
Responders in Cortex: Beyond analysis, Cortex responders can take action — blocking an IP in your firewall, disabling an Active Directory account, or updating a threat intel blocklist. The Firewall-Blocker and AD-Disable responders are community-maintained and available in the Cortex Analyzers repository.
Email ingestion: TheHive's mail2thive connector reads a dedicated mailbox and converts each email into an alert. Useful for ingesting abuse reports, phishing forwards from users, or external partner notifications.
With the full stack running — TheHive for case management, Cortex for enrichment, Wazuh for detection, and Shuffle for automation — you have a genuine SOC workflow in a homelab footprint.