A Platform Built for CTF Organizers
rCTF is a platform designed for hosting cybersecurity capture-the-flag competitions. The project addresses a common pain point for CTF organizers: deploying and maintaining a competition infrastructure without becoming dependent on a rigid set of services. The platform runs as a single bundle, and its major integrations use replaceable providers with a common configuration format. An event can use only what it needs and change providers later without rewriting the platform.
Single Bundle, No Vendor Lock-in
The core design philosophy of rCTF is simplicity without lock-in. Organizers often face the choice between building a CTF platform from scratch—which requires significant engineering time—or adopting a commercial solution that may be difficult to customize or migrate away from. rCTF avoids both traps by providing a self-contained bundle that can be extended or swapped piece by piece. Each integration point follows a common configuration format, meaning new providers can be added or existing ones replaced without touching the core codebase. This approach gives competition teams the freedom to start small and grow into more complex service combinations as needed.
Getting rCTF Running
To begin using rCTF, organizers need Bun version 1.0 or newer. The first step is installing dependencies with bun i. After dependencies are in place, development containers are started using docker compose -f compose.dev.yml up -d. This brings up the required database and caching services.
Next, a development configuration file must be created at rctf.d/00-development.yaml. This file defines the competition name, descriptive metadata, logo image, homepage content, competition window, and database connection details. The configuration uses a YAML structure that includes sections for the CTF name, a meta description, an image URL, home page content written in Markdown, and the origin URL for the frontend. Database settings cover both PostgreSQL and Redis, with host, port, and password fields. A migrate: before flag controls whether database migrations run automatically on startup.
With the configuration in place, the development server is started using bun dev. For frontend work, the command bun dev:mock seeds the database with a reproducible set of mock teams, challenges, and solves. This allows developers to test the interface and workflow without manually creating test data.
Provider Configuration Explained
rCTF’s integrations follow a replaceable-provider pattern. The configuration file includes commented-out sections for email services, CTFtime integration, instancers, captcha providers, blood bot settings, messaging destinations, admin bots, avatar moderation, upload providers, and site tracking. Each section follows the same structure: a provider name, optional options block, and configuration keys specific to that service. Because the format is common across all providers, switching from one captcha service to another, or from Discord to Telegram for announcements, requires only updating the relevant block rather than rewriting integration code.
The database section, for example, lists PostgreSQL connection details with host, port, username, password, and database name. The Redis section follows the same pattern for caching and session storage. The configuration also includes placeholders for email providers, complete with SMTP URL construction, and for ctftime.org integration with client ID and secret fields. Instancer settings cover Docker-based deployment with authentication tokens and API endpoints. Each of these blocks is optional—organizers include only the services their competition requires.
Development Workflow in Practice
The typical development cycle begins with the bun dev command, which starts the server hot-reload cycle. When making changes to the frontend or challenge metadata, developers run bun dev:mock to refresh the database with consistent sample data. This command populates the system with mock teams, defines sample challenges across various categories, and records sample solves. The reproducible nature of this data means the same state can be restored across different development machines, speeding up onboarding for new team members.
Organizers can also adjust the competition window through the configuration file. The startTime and endTime fields define the active competition period, expressed as Unix timestamps. In the development setup, these values are set to a broad range (0 to 99999999999999) to allow unrestricted testing, while production deployments would use specific start and end times corresponding to the actual competition schedule.
What This Means for Teams
For CTF organizations, rCTF translates to less time spent on infrastructure glue and more time focused on competition design. The single-bundle approach means there is no need to coordinate versions across separate repositories or services. The common configuration format means that as new third-party services become available, they can be integrated by adding a new provider block rather than modifying core code. If a service is deprecated or a better alternative emerges, the switch is a configuration change, not a code rewrite.
The provider model also means that organizers are not locked into a specific cloud provider, messaging system, or authentication service from the outset. A competition starting with simple file-based challenges can add an instancer for Docker-based challenge deployment, swap in a different captcha provider, or enable leaderboard tracking on ctftime.org—all through configuration adjustments. This modular approach is particularly valuable for organizations running multiple competitions or iterating on their platform setup between events.
New organizers benefit from the mocked development data, which provides immediate visual feedback without the overhead of seeding real team records. The documentation and live demo lower the barrier to entry, while the replaceable provider model ensures the platform can grow alongside the competition’s needs.