Instancer
Configure per-team challenge instances with Docker or Kubernetes.
The instancer gives each team an isolated copy of a challenge service running on Docker or Kubernetes. Participants can start, inspect, extend, and stop their instance through rCTF.
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
Both providers give participants the same controls and use the same shared challenge fields, but each backend has its own deployment guide.
- Docker instancer is a bundled Python FastAPI service driving Docker, Traefik, and Redis.
- Kubernetes instancer is a Go operator driving GKE, Traefik, and Terraform.
How it works
Each challenge uses instancerConfig to select a named instancer and set its ID, timeout, public endpoints, and provider-specific settings. If the challenge does not select one, rCTF uses defaultInstancer or the only configured instancer.
When a participant starts an instance, rCTF validates the challenge configuration and sends the request to Docker or Kubernetes. The challenge page shows the instance status and the endpoints in the order listed under expose, along with controls to extend or stop it.
Provider configuration
Define instancers under the instancers map in rctf.d/. Each key is a name you choose, and challenges use that name to select an instancer. defaultInstancer chooses the fallback for challenges that don’t specify one. It is required when you configure more than one instancer. With only one, rCTF selects it automatically.
instancers: docker: name: instancers/docker options: apiUrl: http://tiny-instancer:1337 authToken: <shared-secret> k8s: name: instancers/k8s options: apiUrl: https://k8s.example.com authToken: <service-account-token> caCertificate: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----defaultInstancer: dockerA single-instancer deployment only needs one entry, and defaultInstancer can be omitted:
instancers: docker: name: instancers/docker options: apiUrl: http://tiny-instancer:1337 authToken: <shared-secret>instancers/docker calls into the bundled Docker instancer or any compatible tiny-instancer API.
| Field or variable | Purpose |
|---|---|
options.apiUrl |
Base URL of the Docker instancer API from the rCTF API process. |
options.authToken |
Shared token sent as rctfAuthToken when rCTF creates, reads, extends, or deletes an instance. |
DOCKER_INSTANCER_API_URL |
Environment override for apiUrl. |
DOCKER_INSTANCER_AUTH_TOKEN |
Environment override for authToken. |
See Docker instancer for the deployment walkthrough and Docker-specific challenge schema.
instancers/k8s creates cluster-scoped ChallengeInstance custom resources.
| Field or variable | Purpose |
|---|---|
options.apiUrl |
Kubernetes API server URL. |
options.authToken |
Bearer token for a service account that can create, get, patch, and delete ChallengeInstance resources. |
options.caCertificate |
Kubernetes API CA certificate. This is required by the provider. |
K8S_INSTANCER_API_URL |
Environment override for apiUrl. |
K8S_INSTANCER_AUTH_TOKEN |
Environment override for authToken. |
K8S_INSTANCER_CA_CERTIFICATE |
Environment override for caCertificate. |
See Kubernetes instancer for the Terraform deployment walkthrough and Kubernetes-specific challenge schema.
Note (Environment overrides and multiple instancers)
The DOCKER_INSTANCER_* and K8S_INSTANCER_* environment variables apply globally per provider type, so they’re best suited to single-instancer deployments. When you run two instancers of the same type, set their options inline instead.
Challenge configuration
Each instanced challenge needs instancerConfig. Its ID, timeout, extension setting, and exposed endpoints work the same with either provider. The contents of config depend on whether the challenge uses Docker or Kubernetes.
instancerConfig: challengeIntegrationId: web-demo instancer: docker timeoutMilliseconds: 600000 extendable: true config: # Provider-specific config. expose: - kind: https hostPrefix: web-demo containerName: app containerPort: 8080 shouldDisplay: true title: Challenge| Field | Purpose |
|---|---|
challengeIntegrationId |
Stable ID used in Docker labels, Kubernetes resource names, and instance requests. Don’t change it after launch. |
instancer |
Name of the instancer (a key in the instancers map) this challenge runs on. Omit to use defaultInstancer. The admin challenge editor exposes this as a dropdown of configured instancers. |
timeoutMilliseconds |
Instance lifetime for create and extend operations. |
extendable |
Lets participants extend their instance when set to true. |
config |
Provider-specific service or pod configuration. See Docker or Kubernetes for the schema. |
expose |
Public endpoints rCTF should display or keep hidden for internal routing. |
The expose entries map public endpoints to a service container or pod:
| Field | Purpose |
|---|---|
kind |
Endpoint kind. The values are http, https, tcp, and tcp-ssl. |
hostPrefix |
Prefix used when generating the per-instance hostname. |
containerName |
Docker service name or Kubernetes pod name receiving traffic. |
containerPort |
Port inside the service container or Kubernetes service. |
shouldDisplay |
Controls whether the endpoint is shown to participants. Hidden endpoints still exist. |
title |
Optional display label. |
Endpoint kinds
Endpoint support is provider-specific:
| Kind | Docker behavior | Kubernetes behavior |
|---|---|---|
http |
Traefik HTTP router on the configured HTTP port. The default is 80. |
Traefik IngressRoute on the web entrypoint. The public port is 80. |
https |
Traefik HTTPS router on the configured HTTPS port. The default is 443. |
Traefik IngressRoute on the websecure entrypoint plus an HTTP redirect route. The public port is 443. |
tcp |
Rewritten to tcp-ssl because Traefik needs SNI routing. |
Returned as unsupported-by-instancer with port 0. Kubernetes configs should use tcp-ssl. |
tcp-ssl |
Traefik TCP router with TLS and HostSNI on the configured TCP port. The default is 1337. |
Traefik IngressRouteTCP with TLS and HostSNI on port 1337. |
Participant actions and API routes
The instance routes are under /api/v2/integrations/challs/:id/instance:
| Method | Action |
|---|---|
GET |
Returns current status, time left, and endpoints. |
PUT |
Creates an instance. |
PATCH |
Extends an instance when the challenge is extendable. |
DELETE |
Stops an instance. |
The returned status is stopped, starting, running, stopping, or errored.
Captcha can protect create and extend actions:
captcha: protectedEndpoints: - instancerStart - instancerExtendProvider schemas and the admin UI
The fields shared by both providers remain the same. Only config differs. Docker accepts a Compose-like service definition, while Kubernetes accepts pods[]. Each provider publishes a JSON Schema that describes and validates its version of config.
The schema endpoint returns the schema for each configured instancer and identifies the default. Deployment tools can use the same endpoint to validate a challenge before sending it to rCTF.
Dynamic admin UI
The challenge editor builds its form from these schemas. If several instancers are configured, selecting one updates the available fields and validation rules. Use the advanced YAML editor when a setting cannot be represented by the generated form.