All materials
docker-compose.yml
ymldocker-compose.yml
# Baobab Bay Lodge — P1 Lab Environment
# Expected services:
# dvwa → http://localhost:8080 (DVWA web application)
# grafana → http://localhost:3000 (Grafana dashboard)
# loki → http://localhost:3100 (Loki log ingestion, internal)
# alloy → internal only (Log collector, forwards to Loki)
# Expected exposed ports: 8080 (DVWA HTTP), 3306 (MySQL — intentionally exposed for recon/hardening exercise), 3000 (Grafana), 3100 (Loki)
version: "3.8"
networks:
lab:
driver: bridge
volumes:
loki-data:
grafana-data:
services:
dvwa:
image: vulnerables/web-dvwa:1.9
container_name: dvwa
ports:
- "8080:80"
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: dvwa_root_pass
MYSQL_DATABASE: dvwa
MYSQL_USER: dvwa
MYSQL_PASSWORD: p@ssw0rd
DVWA_SECURITY: low
networks:
- lab
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"]
interval: 15s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped
loki:
image: grafana/loki:2.9.4
container_name: loki
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
volumes:
- loki-data:/loki
networks:
- lab
restart: unless-stopped
alloy:
image: grafana/alloy:v1.3.1
container_name: alloy
volumes:
- ./alloy-config.river:/etc/alloy/config.river
- /var/run/docker.sock:/var/run/docker.sock:ro
command:
- run
- /etc/alloy/config.river
depends_on:
- loki
networks:
- lab
restart: unless-stopped
grafana:
image: grafana/grafana:10.3.3
container_name: grafana
ports:
- "3000:3000"
environment:
GF_SECURITY_ADMIN_USER: admin
GF_SECURITY_ADMIN_PASSWORD: admin
GF_AUTH_ANONYMOUS_ENABLED: "true"
GF_AUTH_ANONYMOUS_ORG_ROLE: Admin
volumes:
- grafana-data:/var/lib/grafana
- ./grafana-provisioning:/etc/grafana/provisioning
depends_on:
- loki
networks:
- lab
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 15s
timeout: 5s
retries: 5
start_period: 20s
restart: unless-stopped