Instancer
Configure per-team challenge instances with Docker or Kubernetes.
The instancer integration creates one isolated challenge service per team. rCTF owns the user-facing lifecycle, and an instancer provider owns the compute backend that creates, reads, extends, and deletes the running instance.
Instanced challenges work well when teams need private mutable state, a dedicated service process, or a target that should disappear after a timeout.
Warning (Hostile workloads)
Treat challenge images as hostile. Set resource limits, keep containers or pods unprivileged, and avoid mounting host paths unless the challenge explicitly needs them.
Pick a backend#
This page covers the parts that are the same for both providers, namely the architecture, the common challenge fields, and the participant lifecycle. The provider-specific deployment guides live one level deeper:
- Docker instancer is a bundled Python FastAPI service driving Docker, Traefik, and Redis.
- Kubernetes instancer is a Go operator driving GKE, Traefik, and Terraform.
Architecture#
The instancer path has three layers:
The rCTF API loads instancerProvider from rctf.d/. The provider validates challenge configs and translates rCTF lifecycle calls into Docker or Kubernetes operations underneath.
Each instanced challenge stores instancerConfig in challenge data. The common fields cover the stable challenge integration ID, timeout, exposed endpoints, and provider-specific config.
Participants create, extend, inspect, and delete their instance from the challenge page. rCTF returns provider status and endpoints in the same order as the challenge’s expose array, so the frontend can line them up cleanly.
Provider configuration#
The instancerProvider config selects one provider in rctf.d/:
instancer/docker-instancer calls into the bundled Docker instancer or any compatible tiny-instancer API:
instancerProvider: name: instancer/docker-instancer options: apiUrl: http://tiny-instancer:1337 authToken: <shared-secret>See Docker instancer for the deployment walkthrough and Docker-specific challenge schema.
instancer/k8s-instancer creates cluster-scoped ChallengeInstance custom resources:
instancerProvider: name: instancer/k8s-instancer options: apiUrl: https://k8s.example.com authToken: <service-account-token> caCertificate: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----See Kubernetes instancer for the Terraform deployment walkthrough and Kubernetes-specific challenge schema.
Challenge configuration#
Each instanced challenge needs instancerConfig. The outer envelope (challengeIntegrationId, timeoutMilliseconds, extendable, expose) is the same regardless of which provider is active, and only the inner config body changes shape. This block is also what Konata consumes. Konata accepts both snake_case and camelCase keys and posts the camelCase form rCTF expects on the wire.
instancerConfig: challengeIntegrationId: web-demo timeoutMilliseconds: 600000 extendable: true config: # Provider-specific config. expose: - kind: https hostPrefix: web-demo containerName: app containerPort: 8080 shouldDisplay: true title: ChallengeThe expose entries map public endpoints to a service container or pod:
Endpoint kinds#
Endpoint support is provider-specific:
Lifecycle and API behavior#
Participant lifecycle routes are under /api/v2/integrations/challs/:id/instance:
The returned status is one of stopped, starting, running, stopping, or errored. Docker only emits stopping through rCTF’s shared response schema, while Kubernetes returns it when a custom resource has a deletion timestamp.
Captcha can protect create and extend actions:
captcha: protectedEndpoints: - instancerStart - instancerExtendProvider schema and the admin UI#
The instancerConfig envelope (challengeIntegrationId, timeoutMilliseconds, extendable, expose, config) is provider-agnostic. The same outer shape is accepted regardless of whether the active provider is instancer/docker-instancer or instancer/k8s-instancer. Only the inner config object is provider-specific (Docker Compose-like for docker, pods[] for Kubernetes), and the active provider validates it against its own schema.
The response comes from the provider’s own schema at request time, so it always matches what the provider will actually validate against. External tooling can fetch it to validate challenge configs before pushing them.
Dynamic admin UI#
The admin challenge editor fetches the same schema endpoint and renders the form fields directly from the returned JSON Schema. Swapping the deployment between Docker and Kubernetes shows a different set of inputs without any frontend rebuild, since every field, type, and validation rule comes from the active provider. An “advanced YAML” toggle exposes the raw config block for cases the schema-driven UI doesn’t cover.
Note (Challenge repository tooling)
Konata is a CTF challenge management tool with rCTF support, including challenge syncing, Docker image publishing, and Kubernetes manifest deployment. The archived DiceCTF Quals 2026 challenges repository is a useful reference for Konata-style challenge configuration.