Installation¶
This page covers prerequisites, dependency installation, and database setup for a CTFHive instance. For a fast local demo see Quickstart first.
Prerequisites¶
| Requirement | Minimum version | Notes |
|---|---|---|
| Python | 3.13+ | Required; enforced in pyproject.toml via requires-python = ">=3.13" |
uv |
any recent | The only supported package manager for this repo |
| Docker + Docker Compose | 24+ / v2+ | Optional — required only for the Docker Compose stack or dynamic lab features |
| Redis | 7+ | Optional — app degrades gracefully without it (see Redis) |
| PostgreSQL | 16+ | Optional in dev (SQLite is the default), recommended in production |
Clone the repository¶
Install Python dependencies¶
Installs all [project.dependencies] from pyproject.toml. This includes Flask, SQLAlchemy, Redis client, Gunicorn, Pydantic, the Docker SDK, WireGuard bindings, and all other runtime dependencies.
Adds the dev extras (pytest, pytest-flask, pytest-cov) and the docs extras (mkdocs, mkdocs-material, pymdown-extensions).
Equivalent Makefile target:
Virtual environment location
uv creates .venv/ in the repo root. The Makefile references binaries as .venv/bin/python, .venv/bin/flask, etc. You do not need to activate the venv manually when using uv run or make targets.
Database setup¶
Default: SQLite (development)¶
No database installation needed. On first startup create_app() calls db.create_all() automatically, creating instance/ctfapp.db (or the path in DATABASE_URL).
Bootstrap the schema and seed the default admin account explicitly with:
This is equivalent to running db.create_all() inside an app context. It is safe to run multiple times (idempotent).
Apply Flask-Migrate migrations¶
If you are upgrading an existing database or working with Alembic migrations:
This runs flask db upgrade — the standard Flask-Migrate command.
Migration history
The migrations/ directory must exist (created by flask db init) before running db-upgrade. For fresh installs where migrations/ is absent, use cli.py db bootstrap (which calls db.create_all()) instead.
Production: PostgreSQL¶
Set DATABASE_URL in your .env:
The psycopg2-binary driver is included in the default dependencies. For production, prefer a non-binary psycopg2 build linked against your system's libpq.
Redis (optional)¶
Redis is used for:
- Rate limiting (sliding-window counters shared across gunicorn workers)
- Challenge flag caching
The app runs without Redis. When Redis is unreachable at startup, init_redis() in ctfapp/extensions.py catches the connection error, logs a warning, and the app continues with:
- Cache falls back to an in-process
SimpleCache(per-worker, not shared) - Rate limiting falls back to
memory://(per-worker counters — see the Configuration rate limiting section)
To start Redis locally:
Or with Docker:
Then set in .env:
Multi-worker production without Redis
Running gunicorn with -w 4 (or more) without RATELIMIT_STORAGE_URI pointing at Redis means each worker maintains its own counter. A client can send workers × limit requests before being rate-limited. Always set RATELIMIT_STORAGE_URI=redis://... in production.
Running the app¶
Development server¶
Runs flask run --debug --port 5000 with hot reload. Suitable for local development only.
Production with gunicorn¶
Runs .venv/bin/gunicorn -w 4 -b 0.0.0.0:5000 "ctfapp:create_app()" --access-logfile -.
For a proper production deployment behind nginx see Deploy with Docker Compose and Server setup guide.
Makefile targets reference¶
| Target | Command executed | Purpose |
|---|---|---|
make install |
uv sync |
Install production dependencies |
make install-dev |
uv sync --all-extras |
Install dev + docs dependencies |
make dev |
flask run --debug --port 5000 |
Hot-reload dev server |
make dev-prod |
gunicorn -w 4 ... |
Production-mode server (no reload) |
make db-upgrade |
flask db upgrade |
Apply Alembic migrations |
make db-reset |
flask ctfhive reset-db --confirm |
Destructive DB reset (requires CONFIRM=yes) |
make docker-up |
docker compose up -d |
Start full Docker stack |
make docker-down |
docker compose down |
Stop Docker stack |
make docker-build |
docker compose build ctf-app |
Rebuild app container |
make docker-logs |
docker compose logs -f ctf-app |
Tail app container logs |
make docker-shell |
docker compose exec ctf-app bash |
Shell into app container |
make test |
pytest tests/ -v --tb=short |
Full test suite |
make test-cov |
pytest ... --cov=ctfapp |
Tests with HTML coverage report |
make lint |
ruff check ctfapp/ tests/ |
Linting (ruff required) |
make format |
ruff format ctfapp/ tests/ |
Auto-format code |
make typecheck |
mypy ctfapp/ --ignore-missing-imports |
Type checking (mypy required) |
make docs-serve |
uv run mkdocs serve |
Live-preview docs at http://127.0.0.1:8000 |
make docs-build |
uv run mkdocs build --strict |
Build static docs site |
make health |
flask ctfhive health |
Check DB, Redis, Docker health |
make clean |
removes __pycache__, .pytest_cache, coverage |
Clean build artifacts |
Ops CLI¶
The repo ships a Typer-based operations CLI at cli.py (also aliased as ctfctrl.py). Run it with:
Key command groups:
| Group | Example command | Purpose |
|---|---|---|
env |
cli.py env validate role-b |
Validate config for a deployment role |
db |
cli.py db bootstrap |
Create all tables, seed admin |
admin |
cli.py admin bootstrap --username ... --email ... --password ... |
Create/update admin account |
challenge |
cli.py challenge import <yaml> |
Import a challenge from YAML |
challenge |
cli.py challenge validate <yaml> |
Validate manifest without DB write |
challenge |
cli.py challenge build <slug> |
Build local Docker image for a challenge |
registry |
cli.py registry check |
List images and registry config |
instance |
cli.py instance spawn <slug> |
Spawn a lab instance from CLI |
vpn |
cli.py vpn status |
WireGuard VPN overview |
worker |
cli.py worker list |
List lab worker inventory |
health |
cli.py health all |
Full platform health check |
Most commands accept --app-env <development|production|testing> and --json flags.
Next steps¶
- Configuration — full environment variable reference
- Quickstart — end-to-end local demo
- Challenge format — write your own challenge YAML