Galvanize Instancer is a lightweight service that deploys on-demand CTF challenge instances via Ansible and Docker. It is designed to work alongside the Zync CTFd plugin (https://github.com/28Pollux28/zync) and provides a simple HTTP API for deploy, status, extend, and terminate workflows.
- Per-team challenge instances with TTL and extension controls
- Ansible playbooks for HTTP, TCP, or custom Compose deployments
- Simple YAML challenge definitions matching CTFd challenge format
- JWT-protected API for easy integration with CTF platforms
- The Instancer service runs in a container and exposes an HTTP API.
- Challenges are defined in
data/challenges/*/challenge.yml. - Ansible playbooks in
data/playbooks/handle deployments on your target hosts. - Target hosts must be reachable over SSH and have Docker installed.
- HTTP challenges use Traefik to automatically set the domain name and SSL.
-
Create your configuration file:
cp config.example.yaml config.yaml
-
Edit
config.yamlto set:auth.jwt_secretinstancer.instancer_hostinstancer.ansible.inventoryinstancer.ansible.userinstancer.ansible.private_key
-
Update the SSH key mount in
docker-compose.yml:volumes: - /path/to/your/ssh/key:/home/galvanize/.ssh/ansible-ssh:Z,ro
-
Start the service:
docker compose up -d --build
-
Check health:
curl -f http://localhost:8080/health
Append the monitoring overlay to bring up Prometheus and Grafana alongside the instancer:
docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d --build| Service | URL | Credentials |
|---|---|---|
| Grafana | http://localhost:3000 | admin / admin |
| Prometheus | http://localhost:9090 | — |
Grafana is pre-provisioned with the Galvanize CTF Instancer dashboard covering deployment counts, operation durations, extension stats, worker queue metrics, HTTP API latency, and more. The instancer exposes Prometheus metrics on port 5001 (/metrics).
Configure the Zync plugin to use your Instancer base URL and the same JWT secret you set in config.yaml.
- Base URL example:
http://your-instancer-host:8080 - JWT secret:
auth.jwt_secretinconfig.yaml
Refer to the Zync plugin documentation for the exact configuration fields.
The API is documented in galvanize-instancer/api/openapi.yaml. Main endpoints:
POST /deployGET /statusPOST /extendPOST /terminateGET /health
All endpoints except /health require a JWT bearer token. Tokens are generated automatically by the Zync plugin.
Example challenge file:
data/challenges/example/challenge.yml
Key fields:
name,author,categoryplaybook_name:http,tcp, orcustom_composedeploy_parameters: image, ports, env, or Compose definitionflags,value,description,tags
- If deployments fail, verify SSH access to the target host and that Docker is installed.
- Ensure the mounted SSH key path in
docker-compose.ymlmatchesinstancer.ansible.private_key. - Check container logs with
docker logs galvanize-instancer.