Upgrading from v1

Migration guide from rCTF v1 to v2, covering database changes, API differences, and configuration updates.

Edit this page View Markdown

This guide explains the v1 to v2 upgrade and lists the database, API, and configuration changes.

In short, swap the image and restart

The upgrade is automated. Point your existing deployment at the v2 image and start it. Drizzle migrations run on boot, and rCTF converts the v1 recaptcha / globalSiteTag config to the v2 format at startup. You do not need to run SQL or rewrite the config first.

compose.yml
services:
rctf:
image: ghcr.io/otter-sec/rctf:latest
Warning (Back up the database first)

Migrations are forward-only and modify the schema in place. Take a PostgreSQL dump, for example with pg_dump, before swapping the image so you have a way back if something goes wrong.

Database migration

Set database.migrate to before to run Drizzle migrations during startup. The bundled deployment already does this. The schema default is never, so custom deployments must enable migrations or run them manually:

Terminal window
bun run db:migrate

New tables

Table Purpose
admin_bot_jobs Tracks admin bot job queue (status, inputs, logs)
settings Stores runtime-editable settings (CTF name, client timing, sponsors, etc.)

New columns on users

Column Type Description
avatar_url text URL to user’s avatar image
country_code text ISO 3166-1 alpha-2 country code
status_text text User status message (max 60 chars)
score integer Cached current score
global_rank integer Cached global leaderboard rank
division_rank integer Cached division-specific rank
last_solve_at timestamp Time of last solve (for tiebreaking)
last_tiebreak_solve_at timestamp Time of last tiebreak-eligible solve

New columns on challenges

Column Type Description
score integer Cached current challenge score
solve_count integer Cached number of solves

API changes

All v1 routes still work. V2 routes use the /api/v2/... prefix and include the following changes.

Captcha field rename

V2 routes use captchaCode instead of recaptchaCode in request bodies. This applies to every endpoint that supports captcha validation.

File uploads

The v2 admin upload endpoint (POST /api/v2/admin/upload) takes binary files via multipart/form-data rather than the base64-encoded data URIs v1 used.

New v2 endpoints

Endpoint Description
GET /v2/auth/verify-info Returns info about a verification token
GET /v2/leaderboard/challs Challenge metadata with first 3 solvers per challenge
GET /v2/leaderboard/with-graph Combined leaderboard and graph in one request
PATCH /v2/users/me/avatar Upload and moderate avatar images
GET/POST /v2/admin/users List all users with search, filters, and pagination
GET/PUT /v2/admin/settings Runtime settings management
POST /v2/admin/users/:id/token Generate login token for a team
DELETE /v2/admin/challs/:id/solves/:userId Delete a specific solve
GET /v2/admin/instancer/schema Instancer config JSON schema
GET/POST /v2/admin/admin-bot/* Admin bot job management
GET/PUT/PATCH/DELETE /v2/integrations/challs/:id/instance Challenge instance lifecycle
GET/POST /v2/integrations/challs/:id/admin-bot/* Admin bot submission and status

Response differences

  • Challenge files in v2 include a size field (v1 did not track file sizes)
  • Challenge solves in v2 include user profile data (avatar, country, status) and blood status
  • Leaderboard in v2 supports a search query parameter for team name search (rate limited)

Configuration changes

Captcha provider

rCTF converts the v1 recaptcha block at startup, but new configuration should use captcha.provider:

v1
recaptcha:
siteKey: your-site-key
secretKey: your-secret-key
protectedActions:
- register

The new format also supports captcha/hcaptcha and captcha/turnstile providers.

Analytics provider

rCTF also converts globalSiteTag automatically. Its v2 replacement is:

v2 (recommended)
analytics:
provider:
name: analytics/google
options:
siteTag: G-XXXXXXXX

Additional analytics providers are also available, such as analytics/cloudflare.

New configuration sections

v2 adds the following configuration sections:

Section Purpose
adminBot Admin bot provider and settings
avatarsModeration Avatar content moderation (OpenAI)
bloodBot First blood notifications (Discord/Telegram)
analytics Analytics provider
proxy Reverse proxy and Cloudflare settings
maxAvatarSize Maximum avatar upload size (default 1 MB)

See the Configuration reference for details on every option.

Type to search.