Features β’ Quick Start β’ Documentation β’ Screenshots β’ Contributing
Whaley is a production-ready Docker instance manager designed specifically for Capture The Flag (CTF) competitions. Deploy it on a dedicated server to provide each participant with their own isolated challenge environmentβcomplete with automatic port allocation, resource limits, and seamless CTFd integration.
| Problem | Whaley's Solution |
|---|---|
| Shared challenge instances cause interference | π Isolated containers per user/team |
| Manual port management is error-prone | π― Automatic port allocation with collision prevention |
| No visibility into player resource usage | π Real-time monitoring dashboard |
| Difficult to detect flag sharing | π Suspicious submission detection |
| Complex setup for dynamic flags | π Simple CTFd integration with auto flag injection |
|
|
- Docker Engine 24.0+ with Docker Compose v2
- 4+ CPU cores, 8GB+ RAM (see capacity planning)
- Linux server (Ubuntu 22.04+ or Debian 12+ recommended)
# Clone the repository
git clone https://github.com/jonscafe/whaley.git
cd whaley
# Configure environment
cp .env.example .env
nano .env # Edit with your settings
# Start Whaley
docker compose up -d| Interface | URL | Description |
|---|---|---|
| User Dashboard | http://your-server:8000/ |
Challenge spawning interface |
| Admin Panel | http://your-server:8000/admin |
Monitoring & management |
| API Docs | http://your-server:8000/docs |
Swagger API documentation |
# Authentication
AUTH_MODE=ctfd # "ctfd" or "none"
CTFD_URL=https://your-ctfd.com # Your CTFd instance URL
CTFD_API_KEY=ctfd_xxx... # CTFd admin API key
# Network
PUBLIC_HOST=auto # VPS IP ("auto" for detection)
PORT_RANGE_START=20000
PORT_RANGE_END=50000
# Admin
ADMIN_KEY=your-secure-key # Admin dashboard access key
# Dynamic Flags
DYNAMIC_FLAGS_ENABLED=true
FLAG_PREFIX=FLAG # e.g., FLAG{...}
# Team Mode
TEAM_MODE=auto # "auto", "enabled", or "disabled"# PostgreSQL for high availability
DATABASE_URL=postgresql+asyncpg://user:pass@db:5432/whaley
# Redis for distributed locking (required for multiple workers)
REDIS_URL=redis://redis:6379/0
# Network Isolation (recommended)
NETWORK_ISOLATION_ENABLED=true
NETWORK_ICC_DISABLED=true
# Resource Limits (enforced on all containers)
CONTAINER_MAX_MEMORY=512m # Max memory per container
CONTAINER_MAX_CPU=1.0 # Max CPU cores per container
CONTAINER_PIDS_LIMIT=256 # Max PIDs per container (fork bomb protection)π‘ Tip: Most settings (including Authentication & CTFd integration) can be configured instantly via the Admin Panel β βοΈ Settings tab.
π Full configuration guide: See DOCUMENTATION.md
Create challenges in the challenges/ directory:
challenges/
βββ my-web-challenge/
βββ challenge.yaml # Challenge metadata
βββ docker-compose.yaml # Container definition
βββ Dockerfile
βββ flag.txt # Flag file (auto-injected)
βββ src/
βββ app.py
id: my-web-challenge
name: "SQL Injection Lab"
category: web
description: "Can you bypass the login?"
ports:
- 80
timeout: 3600 # 1 hourservices:
web:
build: .
ports:
- "${PORT_80}:80"
environment:
- FLAG=${FLAG}
mem_limit: 256m
cpus: 0.5
β οΈ Resource enforcement: Even if a challenge setsmem_limit: 2g, Whaley will cap it to the globalCONTAINER_MAX_MEMORY(default512m). You can set per-challenge overrides via the admin panel.
π More examples: See DOCUMENTATION.md
Whaley supports CTFd Team Mode where instances and flags are shared per-team:
| Feature | User Mode | Team Mode |
|---|---|---|
| Instance Ownership | Per user | Per team |
| Dynamic Flags | Unique per user | Shared per team |
| Instance Control | Only spawner | Any team member |
| Suspicious Detection | User vs User | Team vs Team |
Enable with TEAM_MODE=auto to automatically detect from CTFd settings.
Concurrent Instances = Teams Γ Active Challenges Γ 0.5
RAM Required = Concurrent Instances Γ 256MB (average)
Ports Required = Concurrent Instances Γ Ports per Challenge
| Event Size | CPU | RAM | Storage | Example |
|---|---|---|---|---|
| Small (β€50 teams) | 4 cores | 8 GB | 40 GB SSD | Local CTFs |
| Medium (50-150 teams) | 8 cores | 32 GB | 100 GB SSD | University CTFs |
| Large (150-300 teams) | 16 cores | 64 GB | 200 GB SSD | National CTFs |
Scenario: 150 teams, 5 active challenges, 2 ports each
- Peak instances: 150 Γ 5 Γ 0.5 = 375 instances
- RAM needed: 375 Γ 256MB = ~96 GB (recommend 64 GB with swap)
- Ports needed: 375 Γ 2 = 750 ports
User Dashboard |
Admin Dashboard |
Event Logs |
Challenge Manager |
Dynamic Flags |
CTFd Challenge Sync |
All key Whaley settings can be changed at runtime via the Admin Panel β βοΈ Settings tab:
| Category | Settings |
|---|---|
| Instance | Timeout, max instances per user/team |
| Resources | Container max memory, CPU cores, PID limit |
| Network | Port range, isolation, public host |
| Features | Dynamic flags, flag prefix |
| Authentication | Auth mode (CTFd/None), CTFd URL, Admin Key |
| Forensics | Auto capture, retention period |
Changes persist to the database and survive container restartsβno need to edit docker-compose.yaml or .env files.
Control which challenges are visible and spawnable from the Challenge Manager tab:
- π’ Active β Visible on the user dashboard, can be spawned
- π΄ Inactive β Hidden from users, spawn requests rejected (HTTP 403)
Use this during competitions to stage challenges for later rounds, or to quickly disable a broken challenge without deleting it.
Whaley enforces maximum resource limits on every container, regardless of what the challenge's docker-compose.yaml specifies:
CONTAINER_MAX_MEMORY=512m # Caps mem_limit in compose files
CONTAINER_MAX_CPU=1.0 # Caps cpus in compose files
CONTAINER_PIDS_LIMIT=256 # Injects pids_limit (fork bomb protection)
Per-challenge overrides can be set via the admin API if certain challenges need more resources.
For comprehensive documentation, see DOCUMENTATION.md:
- π§ Installation & Configuration
- π¦ Challenge Structure & Examples
- π API Reference
- π‘οΈ Security Considerations
- π Instance Forensics
- π Resource Monitoring
- π Capacity Planning
- βοΈ Admin Settings & Challenge Management
Contributions are welcome! Here's how you can help:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- π Bug fixes and improvements
- π Documentation enhancements
- π¨ UI/UX improvements
- π§ͺ Test coverage
- π Internationalization
This project is licensed under the MIT License β see the LICENSE file for details.
keii Creator & Maintainer |
Built with β€οΈ for the CTF community
If you find Whaley useful, please consider giving it a β





