Complete Guide: Install MISP on Docker in Linux (Production-Ready)
MISP is the open-source threat sharing platform powering hundreds of SOCs, CERTs, and threat intel teams worldwide. Running it via Docker eliminates dependency hell, ensures reproducibility, and scales effortlessly.
This guide uses the official MISP/misp-docker repository, which provides production-ready, multi-stage Docker images for misp-core (MISP app + web) and misp-modules (enrichment/expansion modules). Images are automatically built and tagged on GitHub Packages — no manual compilation required.
Tested on: Ubuntu 22.04/24.04 LTS, Debian 12
Prerequisites
Before starting, ensure your Linux system meets the following requirements:
Docker 27+ and Docker Compose 2.27+
Minimum Resources: 4 vCPU, 8GB RAM, 50GB SSD (16GB+ for production)
Ports Open: 80/443 (HTTP/HTTPS), 3306 (MySQL internal), 6379 (Redis internal)
Firewall: Allow inbound to your MISP FQDN/IP
Domain/SSL: Recommended for production (Let's Encrypt or custom certs)
Install Docker and Docker Compose
Run the following to install Docker on Ubuntu/Debian:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
Log out and back in to apply group changes, then install Docker Compose:
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
Step 1 — Clone the Repository and Prepare Environment
Create a working directory and clone the official MISP Docker repo:
mkdir ~/misp-docker && cd ~/misp-docker
git clone https://github.com/MISP/misp-docker.git .
cp template.env .env
Open .env in your preferred editor and set the following mandatory variables:
# Database credentials (AlphaNum only — avoid special characters in passwords)
MYSQL_USER=misp
MYSQL_PASSWORD=your_strong_password123
MYSQL_ROOT_PASSWORD=your_root_password123
MYSQL_DATABASE=misp
# Redis
REDIS_PASSWORD=redis_pass123
# MISP Base URL — critical for emails and sync
BASE_URL=https://your-misp.domain.com
# For local testing only
# BASE_URL=http://your-ip:8080
# Worker scaling — adjust based on server load
NUM_WORKERS_DEFAULT=5
NUM_WORKERS_PRIO=5
NUM_WORKERS_EMAIL=2
# Internal Docker network address for MISP Modules
MISP_MODULES_FQDN=http://misp-modules
# Enable DB-based settings storage (recommended for production)
ENABLE_DB_SETTINGS=true
Pro Tip: Use
pwgen 32 1to generate secure random passwords. Avoid special characters like!@#$in MySQL passwords as they cause configuration parsing errors.
Step 2 — Review and Configure Docker Compose
The repository ships with a default docker-compose.yml. Below is the production-hardened version you should use:
version: '3.8'
services:
db:
image: mariadb:11
restart: always
volumes:
- mysql_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
healthcheck:
test: ["CMD", "mariadb-admin", "--protocol=tcp", "ping"]
interval: 10s
timeout: 5s
retries: 3
redis:
image: redis:7-alpine
restart: always
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
misp-modules:
image: ghcr.io/misp/misp-docker/misp-modules:latest
restart: always
environment:
- REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379
- WORKER=off
depends_on:
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:6666 || exit 1"]
interval: 30s
timeout: 10s
retries: 3
misp-core:
image: ghcr.io/misp/misp-docker/misp-core:latest
restart: always
ports:
- "8080:80"
# - "443:443" # Uncomment when using HTTPS in production
volumes:
- configs:/var/www/MISP/app/Config
- logs:/var/www/MISP/app/tmp/logs
- files:/var/www/MISP/app/files
- gnupg:/var/www/MISP/.gnupg
- ./ssl:/etc/ssl/certs:ro
- ./ca-certs:/usr/local/share/ca-certificates:ro
environment:
- MYSQL_HOST=db
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- REDIS_PASSWORD=${REDIS_PASSWORD}
- BASE_URL=${BASE_URL}
- MISP_MODULES_FQDN=${MISP_MODULES_FQDN}
- NUM_WORKERS_DEFAULT=${NUM_WORKERS_DEFAULT}
- NUM_WORKERS_PRIO=${NUM_WORKERS_PRIO}
- NUM_WORKERS_EMAIL=${NUM_WORKERS_EMAIL}
- ENABLE_DB_SETTINGS=${ENABLE_DB_SETTINGS}
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
misp-modules:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost || exit 1"]
interval: 30s
timeout: 10s
retries: 3
volumes:
mysql_data:
configs:
logs:
files:
gnupg:
Key Notes on This Configuration
Use
latestor pin a specific version tag likemisp-core:2.4.175-1from GitHub Packages for reproducibilityUse
latest-slimtags if you require smaller image footprints for compliance environmentsAll critical data (configs, logs, files, GPG keys) is persisted via named volumes — never lose data on container restart
Step 3 — Pull Images and Initial Launch
Pull all pre-built images from GitHub Container Registry:
docker compose pull
Start all services in detached mode:
docker compose up -d
Watch the bootstrap process (first run takes 5–15 minutes):
docker compose logs -f misp-core
What Happens on First Run
Database schema migration runs automatically — fully offline, no manual prompts
File permissions are enforced across all volumes
Background job workers are initialised (modern replacement for legacy cron)
Default admin user is created automatically
Verify the Deployment
curl -k http://localhost:8080
docker compose ps
All services should show status healthy.
Default Login Credentials:
URL:
http://your-ip:8080or your configured BASE_URLEmail:
[email protected]Password:
admin
CRITICAL: Change the default admin password immediately after first login.
Step 4 — Production Hardening
SSL Setup
Create the SSL directory:
mkdir ./ssl
For testing, generate a self-signed certificate:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout ssl/key.pem \
-out ssl/cert.pem \
-subj "/CN=your-misp.domain.com"
For production, use Let's Encrypt:
sudo apt install certbot
certbot certonly --standalone -d your-misp.domain.com
Then copy the certificates:
cp /etc/letsencrypt/live/your-misp.domain.com/fullchain.pem ./ssl/cert.pem
cp /etc/letsencrypt/live/your-misp.domain.com/privkey.pem ./ssl/key.pem
After setting SSL certs, uncomment port 443:443 in your docker-compose.yml and restart:
docker compose down && docker compose up -d
Custom Root CA Certificates
If your organisation uses internal CAs, mount them in your compose file:
- "./rootca.crt:/usr/local/share/ca-certificates/rootca.crt"
They are automatically installed each time misp-core starts.
LDAP Authentication (Optional)
Add the following to your .env file:
AUTH=LDAP
LDAP_HOST=ldap://your-ldap.server
LDAP_BASE_DN=dc=example,dc=com
LDAP_SEARCH_FILTER=(mail=%s)
LDAP_SEARCH_ATTRIBUTE=mail
Restart the misp-core container to apply:
docker compose restart misp-core
Step 5 — Updates and Maintenance
Updating MISP
Pull the latest images and recreate containers:
cd ~/misp-docker
docker compose pull
docker compose up -d
docker image prune -f
Schema migrations and permission fixes run automatically on each restart — no manual intervention needed.
Backing Up the Database
Stop the stack before backup to ensure consistency:
docker compose down
tar czf misp-mysql-backup-$(date +%Y%m%d).tar.gz \
/var/lib/docker/volumes/misp-docker_mysql_data/
docker compose up -d
Restoring a Backup
docker compose down
tar xzf misp-mysql-backup-20260225.tar.gz -C /var/lib/docker/volumes/
docker compose up -d
Exporting All Named Volumes
docker compose down
tar czf misp-full-backup-$(date +%Y%m%d).tar.gz \
/var/lib/docker/volumes/misp-docker_mysql_data/ \
/var/lib/docker/volumes/misp-docker_configs/ \
/var/lib/docker/volumes/misp-docker_files/ \
/var/lib/docker/volumes/misp-docker_gnupg/
docker compose up -d
Step 6 — Advanced Configuration
Custom MISP Settings via Script
Create a customisation script at ./files/customize_misp.sh:
#!/bin/bash
/var/www/MISP/app/cake Admin setSetting "Plugin.ZeroMQ_enable" true
/var/www/MISP/app/cake Admin setSetting "MISP.default_event_distribution" 1
/var/www/MISP/app/cake Admin setSetting "MISP.tagging" true
Make it executable:
chmod +x ./files/customize_misp.sh
Set the path in .env:
CUSTOM_PATH=/custom/customize_misp.sh
This script runs on every container start, making it ideal for enforcing baseline configs.
Checking Worker Status
docker compose exec misp-core /var/www/MISP/app/cake worker status
Running MISP Cake Commands
docker compose exec misp-core /var/www/MISP/app/cake Admin runUpdates
docker compose exec misp-core /var/www/MISP/app/cake Admin updateGalaxies
docker compose exec misp-core /var/www/MISP/app/cake Admin updateTaxonomies
docker compose exec misp-core /var/www/MISP/app/cake Admin updateObjectTemplates 0
Accessing the MISP MySQL Shell Directly
docker compose exec db mariadb -u misp -p misp
Step 7 — Troubleshooting Common Issues
IssueCauseFixContainers not startingMissing .env valuesRe-check mandatory .env varsMySQL password errorsSpecial characters in passwordUse AlphaNum-only passwordsSlow startup on cloudNFS/EFS volume latencyReduce volume mounts to essentials onlyWorkers not runningRedis unhealthyCheck Redis password and health statusModules returning errorsMISP_MODULES_FQDN wrongVerify http://misp-modules is correctSSL errorsCerts not foundConfirm paths in volume mountsGPG errorsgnupg volume emptyVolume auto-initialises on first run
Viewing Service Logs
docker compose logs db
docker compose logs redis
docker compose logs misp-modules
docker compose logs misp-core
Restarting a Single Service
docker compose restart misp-core
docker compose restart misp-modules
Key Takeaways
The official
misp-dockerrepo provides pre-built images — you should never need to manually compile MISP from sourceAlways set
BASE_URLcorrectly — it controls email links, sync, and API behaviourAn IP or container not reaching
misp-moduleswill silently break enrichment — confirmMISP_MODULES_FQDN=http://misp-modulesis setSchema migrations and permission enforcement are fully automated on every container restart
Persist your volumes — configs, files, GPG keys, and database data must survive container rebuilds
Use specific image tags in production rather than
latestto prevent unexpected breaking changes during updatesThe first run takes 5–15 minutes — do not kill the container during bootstrap
References
Official MISP Docker Repository: https://github.com/MISP/misp-docker
MISP Project Documentation: https://misp.github.io/MISP/
MISP GitHub Packages (Image Registry): https://github.com/orgs/MISP/packages
MISP Community Forum: https://misp-community.org
🔗 Stay Connected
Sign up FREE for my web app → https://app.cyberhawkthreatintel.com
YouTube: @cyberhawkconsultancy | https://youtube.com/@cyberhawkconsultancy
YouTube: @cyberhawkk | https://youtube.com/@cyberhawkk
TikTok: @cyberhawkthreatintel | https://tiktok.com/@cyberhawkthreatintel
X (Twitter): @cyberhawkintel | https://x.com/cyberhawkintel
Telegram: @cyberhawkthreatintel | https://t.me/cyberhawkthreatintel
Hashtags: #MISP #MISPDocker #ThreatIntelligence #CyberSecurity #SOCTools #DockerCompose #LinuxTutorial #IOCSharing #CTI #InfoSec #OpenSource #MISPInstall #ThreatHunting #SecurityOperations #CyberhawkThreatIntel #CyberhawkConsultancy #CyberhawkK