How to host a CTF competition
This is the end-to-end playbook for hosting a CTF competition on Flagpost — from the first format decision to the post-event retro. Each step links to the deep-dive page for that area; read this once to see the whole shape, then work through the pieces.
1. Decide the format
Section titled “1. Decide the format”The choices that shape everything downstream:
- Team or individual? A per-competition setting — decide before registration opens, it isn’t switchable mid-event. Teams need a size cap policy; see Teams & participants.
- Open or invite-only? Public with self-serve join, public with an invite code, or fully private. An email-domain allowlist suits university events.
- Divisions? Parallel rankings (Open / Student / …) come free via brackets — decide the names up front.
- Scoring model. Static points are predictable; dynamic decay self-balances difficulty at scale. Mixable per challenge — Challenges.
- Rules. Author your rules / code of conduct early; the join gate records who accepted, when.
2. Stand up the platform
Section titled “2. Stand up the platform”docker compose up gives you the full stack locally
(Quick start); a real event wants a domain, TLS and
real credentials (Production deployment) — pin a
release image rather than building from source. Run
the setup wizard, set
branding, configure SMTP, and connect
SSO if your org has an IdP.
Size the box for your head count and rehearse with load in mind — the platform is a single backend process by design, so scale up, not out.
3. Author and test the challenges
Section titled “3. Author and test the challenges”- Bulk-import an existing ctfcli repo (Import & export) or author in the UI.
- Use the model: categories, tags and difficulty tiers for navigation; prerequisite chains and scheduled release for pacing; multiple-choice guess caps where brute force is trivial.
- For anything that needs a live target per team, give the challenge its own on-demand instance — each subject gets an isolated container instead of sharing one endpoint.
- Rehearse every flag in a scratch competition — regex flags especially. Attach files and download them the way a competitor would.
- Set hint costs deliberately: free hints released on a timer beat expensive hints nobody buys.
4. Staff it
Section titled “4. Staff it”Assign Judges per competition; craft custom roles if the built-ins don’t fit (a Challenge Author who can’t touch scoring, a read-only observer). Judges get the operational dashboard, the live ticket queue, and the submissions browser for disputes. If the optional AI module is configured, staff can also ask the organiser assistant operational questions in plain language — standings, ticket load, which challenges are hurting.
5. Automate the event
Section titled “5. Automate the event”Write the When → If → Then rules before the event, not during: first-blood announcements, timed hint waves, a T-60 “open the survey” trigger, freeze-on-end, and a webhook into your staff chat for new tickets. Every rule you write is a checklist item your staff doesn’t carry on game day. You can also pre-schedule announcements to post themselves at a set time — a welcome banner at kickoff, a halftime reminder — without a rule or anyone at the keyboard. And if you enable the competitor assistant as a guard-railed hint channel, choose its guidance level deliberately and have a Judge skim the AI transcripts page during the event — every conversation is reviewable.
6. Open registration early
Section titled “6. Open registration early”Open sign-ups days ahead so teams form, divisions get assigned, and SSO or email verification quirks surface before the clock starts. If you need more than a name at the door — a waiver, a Discord handle, a division preference — define custom registration fields to collect them at entry. Publish the public scoreboard and CTFtime feed opt-ins if the event is spectated or rated.
7. Game day
Section titled “7. Game day”- Start the competition. A competition begins as Not started, and that status is the gate — until it’s running, competitors see an empty challenge page. If you set a start time, the scheduler opens the doors on the clock; otherwise hit Start competition on the Controls tab. (This is the single most-missed step of the day.)
- Then the schedule runs itself:
competition.startedfires, challenges release in their waves, automations do the announcing. - Staff live in the dashboard and ticket queue; presence shows who’s looking at what.
- Pause halts submissions if something breaks; freeze hides the endgame drama while competitors keep scoring — know the difference before you need either.
- Watch analytics for a challenge with high fails and rising tickets — that’s your broken challenge alarm.
8. Afterwards
Section titled “8. Afterwards”Stop the competition (or let end_at do it) — play closes, the board
stays readable as a final result. Then wrap up:
- Certificates — release the template you designed; every participant downloads theirs from Profile → Certificates, or export them all as a ZIP.
- Post-event report — once the competition has ended, generate a branded PDF/HTML wrap-up for your sponsors and retro.
- The survey you scheduled at T-60 is already collecting; post-solve ratings tell you which challenges landed.
Export results and analytics for the retro, archive the competition (retention policy permitting), and clone it as the starting point for next year — the second run is always easier.
Running your first event and unsure about scale, format, or anything else? Ask in GitHub Discussions — organiser experience reports directly shape the roadmap.