Upgrading from v1
Migration guide from rCTF v1 to v2, covering database changes, API differences, and configuration updates.
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.
services: rctf: image: ghcr.io/otter-sec/rctf:latestWarning (Back up the database first)
Migrations are forward-only and modify the schema in place. Take a PostgreSQL dump, for example with pg_dump
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:
bun run db:migrateNew 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
sizefield (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
searchquery 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:
recaptcha: siteKey: your-site-key secretKey: your-secret-key protectedActions: - registercaptcha: provider: name: captcha/recaptcha options: siteKey: your-site-key secretKey: your-secret-key protectedEndpoints: - registerThe new format also supports captcha/hcaptcha and captcha/turnstile providers.
Analytics provider
rCTF also converts globalSiteTag automatically. Its v2 replacement is:
analytics: provider: name: analytics/google options: siteTag: G-XXXXXXXXAdditional 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.