VulnerableApp — Production Deployment Guide
Overview
This guide covers how to run VulnerableApp securely on an EC2 instance using the provided docker-compose.prod.yml and startup scripts. The setup isolates backend services from the internet and randomises credentials on every start.
Prerequisites
- EC2 instance (Amazon Linux 2 or Ubuntu)
- Docker and Docker Compose installed
Install Docker (Amazon Linux 2)
sudo yum update -y
sudo yum install -y docker
sudo systemctl enable docker
sudo systemctl start docker
sudo usermod -aG docker ec2-user
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
File Structure
VulnerableApp/
├── docker-compose.prod.yml # Production compose — facade + base only
├── templates/ # Nginx config templates (mounted read-only)
│ └── default.conf.template
└── scripts/
└── productionize/
├── startup_script.sh # Linux/Mac startup script
└── startup_script.bat # Windows startup script
What the Startup Script Does
Each time the startup script runs it:
- Generates a fresh random username and password for both database users
- Writes them to a
.envfile (never committed to source control) - Starts Docker Compose using those credentials
Credentials are different on every run. The H2 database is in-memory so there is no data to migrate between restarts.
Running on Linux / Mac
cd scripts/productionize
chmod +x startup_script.sh
./startup_script.sh
Running on Windows
cd scripts\productionize
startup_script.bat
Checking Credentials
The generated credentials are written to .env in the scripts/productionize/ directory:
cat scripts/productionize/.env
This file is regenerated on every run. Never commit it:
echo ".env" >> .gitignore
What Runs in Production
| Container | Purpose |
|---|---|
VulnerableApp-base | Spring Boot application (internal only, not exposed) |
VulnerableApp-facade | Nginx reverse proxy (the only publicly exposed container) |
The JSP and PHP containers are excluded from production. All backend traffic stays on an internal Docker network with no internet access.
Network Architecture
Internet
│
▼
[ EC2 :80 ]
│
[ VulnerableApp-facade ] (edge + internal networks)
│
[ VulnerableApp-base ] (internal network only — no internet access)
The base container cannot make outbound internet requests. Only the facade is reachable from outside.
Security Controls
| Control | Detail |
|---|---|
| Random credentials | New username and password generated on every start |
| Internal network | Base container has no internet access |
| Read-only volume | Nginx templates mounted as read-only |
| H2 console disabled | public profile disables the H2 web console |
| Active profile | Runs public only — unsafe profile is excluded |
EC2 Security Group Rules
Lock down inbound access as tightly as possible:
| Port | Source | Purpose |
|---|---|---|
| 80 | Your IP only (e.g. 1.2.3.4/32) | App access |
| 22 | Your IP only | SSH |
Avoid opening port 80 to 0.0.0.0/0 unless absolutely necessary.
Stopping the App
docker compose -f docker-compose.prod.yml down