Introduction
Building a personal hacking lab is essential for learning penetration testing skills safely and legally. Docker containerization makes this dramatically easier by eliminating complex VM management. This guide walks you through creating a fully-functional Docker-based lab with vulnerable applications, security tools, and multiple testing environments—all on a single machine.
Why Docker for Your Hacking Lab?
Advantages Over Virtual Machines
| Aspect | Docker | Virtual Machines |
|---|
| Start time | Seconds | Minutes |
| Storage | 50-200 MB per container | 5-30 GB per VM |
| Management | Single file (docker-compose) | Multiple VM files |
| Resource efficiency | Lightweight | Heavy overhead |
| Networking | Easy container networking | Port forwarding complexity |
What You’ll Build
Docker Hacking Lab
├── Vulnerable Web Apps (DVWA, WebGoat)
├── Database Targets (MySQL, PostgreSQL)
├── Network Services (FTP, SSH, SMB)
├── Analysis Tools (Metasploit, Nessus)
└── Monitoring (ELK Stack for logging)
Prerequisites
System Requirements
- RAM: 8GB minimum (16GB+ recommended)
- Storage: 50GB free disk space
- CPU: Dual-core minimum (quad-core recommended)
- OS: Linux (Ubuntu 20.04+), macOS, or Windows 10/11 Pro
Install Docker and Docker Compose
Ubuntu/Debian:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
newgrp docker
Verify installation:
docker --version
docker-compose --version
Building Your First Vulnerable App Container
Create a Simple Vulnerable Web Server
Create a project directory:
mkdir ~/hacking-lab
cd ~/hacking-lab
Create a Dockerfile:
FROM python:3.9-slim
WORKDIR /app
RUN pip install flask
COPY vulnerable_app.py .
EXPOSE 5000
CMD ["python", "vulnerable_app.py"]
Create vulnerable_app.py:
from flask import Flask, request
app = Flask(__name__)
@app.route('/search')
def search():
query = request.args.get('q', '')
# Vulnerable to SQL injection
return f"<h1>Results for: {query}</h1>"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
Build and run:
docker build -t vulnerable-app .
docker run -p 5000:5000 vulnerable-app
Access at http://localhost:5000/search?q=test.
Docker Compose: Multi-Container Lab
Create a Complete Lab Environment
Create docker-compose.yml:
version: '3.8'
services:
# Vulnerable Web Application
dvwa:
image: vulnerables/web-dvwa
ports:
- "80:80"
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=dvwa
networks:
- lab-network
# MySQL Database
mysql:
image: mysql:5.7
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=dvwa
networks:
- lab-network
# WebGoat (OWASP)
webgoat:
image: webgoat/latest
ports:
- "8080:8080"
networks:
- lab-network
# Juice Shop (OWASP)
juiceshop:
image: bkimminich/juice-shop
ports:
- "3000:3000"
networks:
- lab-network
# Metasploitable3 (Linux)
metasploitable:
image: tleemiller/metasploitable3-linux
ports:
- "22:22"
- "23:23"
- "21:21"
- "3306:3306"
networks:
- lab-network
# Kali Linux for attacking
attacker:
image: kalilinux/kali-rolling
stdin_open: true
tty: true
networks:
- lab-network
networks:
lab-network:
driver: bridge
Deploy the Lab
docker-compose up -d
Check running containers:
docker-compose ps
Access Services
- DVWA:
http://localhost
- WebGoat:
http://localhost:8080
- Juice Shop:
http://localhost:3000
- MySQL:
localhost:3306
- Metasploitable SSH:
ssh root@localhost:2222
Adding Custom Vulnerable Applications
Include DVWA (Damn Vulnerable Web Application)
Already in our compose file above. Default credentials:
- Username:
admin
- Password:
password
Add WebGoat for Guided Learning
WebGoat provides structured lessons:
webgoat:
image: webgoat/latest
ports:
- "8080:8080"
environment:
- JAVA_OPTS=-Dspring.profiles.active=docker
networks:
- lab-network
Add Vulnerable Node App
nodegoat:
image: vulnerapp/nodegoat
ports:
- "4000:4000"
networks:
- lab-network
Burp Suite in Docker
Create a Dockerfile for Burp proxy:
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y \
curl \
openjdk-11-jdk
RUN curl -o /burp.jar https://[burp-download-url]
EXPOSE 8081
CMD ["java", "-jar", "/burp.jar"]
metasploit:
image: metasploitframework/metasploit-framework
ports:
- "5432:5432"
networks:
- lab-network
Network Analysis with tcpdump
tcpdump:
image: nicolaka/netshoot
cap_add:
- NET_ADMIN
networks:
- lab-network
Advanced Lab Networking
Custom Network Configuration
Create isolated networks for different scenarios:
docker network create attacking-network
docker network create target-network
Run containers on specific networks:
docker run --network attacking-network -it kalilinux/kali-rolling bash
docker run --network target-network vulnerables/web-dvwa
Internal Lab Communication
Containers on same network can communicate by hostname:
# Inside Kali container
ping dvwa
curl http://dvwa
Persistent Data and Volumes
Create Persistent Storage
services:
dvwa:
image: vulnerables/web-dvwa
volumes:
- dvwa_data:/var/lib/mysql
networks:
- lab-network
volumes:
dvwa_data:
driver: local
This preserves database content between restarts.
Mount Host Directories
services:
attacker:
image: kalilinux/kali-rolling
volumes:
- /home/user/payloads:/payloads
- /home/user/results:/results
networks:
- lab-network
Complete Lab Workflow Example
Attack Scenario: SQL Injection
Step 1: Start lab
docker-compose up -d
Step 2: Access attacking container
docker-compose exec attacker bash
apt-get update && apt-get install -y sqlmap
Step 3: Scan target
sqlmap -u "http://dvwa/vulnerabilities/sqli/?id=1" \
-D dvwa -T users --dump
Step 4: Save results
# Inside container
sqlmap -u "http://dvwa/vulnerabilities/sqli/?id=1" \
--batch --dump-all > /results/sqli_dump.txt
Step 5: Review on host
cat ~/results/sqli_dump.txt
Logging and Monitoring Lab Activity
ELK Stack for Log Aggregation
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.0.0
environment:
- discovery.type=single-node
ports:
- "9200:9200"
networks:
- lab-network
kibana:
image: docker.elastic.co/kibana/kibana:8.0.0
ports:
- "5601:5601"
networks:
- lab-network
Docker Event Logging
Monitor all container activity:
docker events --filter 'type=container'
Container Health Checks
dvwa:
image: vulnerables/web-dvwa
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
Management and Maintenance
Common Docker Commands
View running containers:
docker-compose ps
Access container shell:
docker-compose exec dvwa bash
View logs:
docker-compose logs -f dvwa
Stop lab:
docker-compose stop
Restart lab:
docker-compose restart
Complete cleanup:
docker-compose down -v
Troubleshooting
Port Already in Use
# Find what's using the port
sudo lsof -i :80
# Kill process if needed
sudo kill -9 PID
Container Won’t Start
docker-compose logs dvwa
Check error message and verify resource availability.
Network Connectivity Issues
# Test from attacker container
docker-compose exec attacker ping dvwa
# Verify network exists
docker network ls
docker network inspect lab-network
Out of Disk Space
Clean up old images and containers:
docker system prune -a
Lab Best Practices
Documentation
Create a README for your lab:
# Hacking Lab
## Available Services
- DVWA: http://localhost
- WebGoat: http://localhost:8080
- Juice Shop: http://localhost:3000
## Credentials
- MySQL root:root
- DVWA admin:password
## Common Tasks
Regular Backups
Backup your compose configuration:
git init ~/hacking-lab
git add docker-compose.yml Dockerfile
git commit -m "Initial lab setup"
Version Control
Keep your custom Dockerfiles in version control for consistency across machines.
Resource Limits
Prevent runaway containers from consuming all resources:
dvwa:
image: vulnerables/web-dvwa
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
Conclusion
Docker transforms hacking lab setup from complex, time-consuming infrastructure work into simple, reproducible containerized environments. By mastering docker-compose, you can spin up realistic multi-tier vulnerable applications in minutes, test exploits, and tear down cleanly. This approach scales from simple learning labs to comprehensive enterprise simulation environments. Start with basic DVWA and MySQL, progress to multi-application labs, and continuously expand your testing capabilities as your skills grow.