# Deploy the CPU render-farm worker pool template with OpenTofu

Source: https://docs.quake.ai/resources/deployments/deploy-render-farm-worker-template
Markdown: https://docs.quake.ai/resources/deployments/deploy-render-farm-worker-template.md
> Stand up a dispatcher VM plus CPU workers that pull render jobs and upload results to Object Storage using the render-farm-worker OpenTofu template.

---

# Deploy the CPU render-farm worker pool template with OpenTofu

Stand up a dispatcher VM plus CPU workers that pull render jobs and upload results to Object Storage using the [validated OpenTofu template](/docs/platform/validation#how-infrastructure-templates-are-checked) `render-farm-worker`. Quake AI has no GPU rendering; this template provisions a CPU-only render pool for hobbyist previews, overnight batch jobs, and audio-render workloads.

<PricingCompanion
  components={[
    { kind: "template", slug: "render-farm-worker", required: true },
  ]}
/>

<Figure size="md" caption="Render farm topology: dispatcher queues jobs on a floating IP; CPU workers on a private subnet pull work and write rendered frames to Object Storage">

```d2
direction: right

cloud: Quake AI {
  jobs: Jobs bucket\nmanifests + assets
  output: Output bucket\nrendered frames
  dispatcher: Dispatcher VM\nqueue API :8080
  workers: CPU worker pool\nFFmpeg / Blender
  private: Private network\nno worker FIPs
}

cloud.workers -> cloud.dispatcher: poll queue
cloud.workers -> cloud.jobs: fetch assets
cloud.workers -> cloud.output: upload results
```

</Figure>

## Prerequisites

You need:

- A Quake AI account with [application credentials](/docs/tools/generate-app-credentials)
- OpenTofu 1.6.0 or later ([installation guide](https://opentofu.org/docs/intro/install/))
- The AWS CLI and `curl` installed
- OpenStack credentials sourced into the shell. See [the OpenStack CLI guide](/docs/tools/openstack-cli).
- A copy of the `render-farm-worker` template from [the template reference page](/resources/iac-templates/render-farm-worker)
- Enough project quota for one dispatcher and two `c2a.large` workers by default, plus two Object Storage buckets

## Step 1: Mint credentials and configure variables

Mint EC2-compatible credentials and export the standard AWS variables:

```bash
openstack ec2 credentials create
export AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY
export AWS_SECRET_ACCESS_KEY=YOUR_SECRET_KEY
export AWS_ENDPOINT_URL_S3=https://object.us-east-1.rumble.cloud
```

Copy `terraform.tfvars.example` to `terraform.tfvars` and set:

```hcl
key_name              = "YOUR_KEY_NAME"
jobs_bucket_name      = "YOUR_PROJECT_RENDER_JOBS"
output_bucket_name    = "YOUR_PROJECT_RENDER_OUT"
s3_access_key         = "YOUR_ACCESS_KEY"
s3_secret_key         = "YOUR_SECRET_KEY"
enable_dispatcher_fip = true

worker_count = 2
```

Workers stay on the private subnet with no floating IPs. Setting `enable_dispatcher_fip = true` allocates one floating IP on the dispatcher so your workstation can reach the job API.

## Step 2: Apply the template

From the template directory, run:

```bash
tofu init
tofu plan
tofu apply
```

Type `yes` when prompted. Cloud-init installs the dispatcher API and worker agents on each node. First boot can take 10 to 15 minutes while FFmpeg and Blender install on the workers.

When the run finishes, note `job_submit_url`, `jobs_bucket`, and `output_bucket` from the outputs.

## Step 3: Submit a sample job and verify output

Upload a short test asset:

```bash
ffmpeg -f lavfi -i "color=c=blue:s=320x240:d=2" -pix_fmt yuv420p /tmp/frame-source.mp4
aws s3 cp /tmp/frame-source.mp4 \
  "s3://$(tofu output -raw jobs_bucket)/jobs/tutorial-frame/source.mp4" \
  --endpoint-url "$AWS_ENDPOINT_URL_S3"
```

Create and submit a job manifest:

```bash
cat > /tmp/tutorial-job.json <<'EOF'
{
  "job_id": "tutorial-frame",
  "input_key": "jobs/tutorial-frame/source.mp4",
  "output_prefix": "jobs/tutorial-frame/out/",
  "profile": "ffmpeg-transcode",
  "params": { "format": "mp4" }
}
EOF

curl -sS -X POST \
  -H "Content-Type: application/json" \
  --data-binary @/tmp/tutorial-job.json \
  "$(tofu output -raw job_submit_url)"
```

Workers poll the queue on the private subnet. Allow 10 to 15 minutes after `tofu apply` for cloud-init to finish before you expect rendered output. Poll the output bucket:

```bash
aws s3 ls "s3://$(tofu output -raw output_bucket)/tutorial-frame/" \
  --endpoint-url "$AWS_ENDPOINT_URL_S3"
```

You should see `render.mp4` under the `tutorial-frame/` prefix. If nothing appears after 15 minutes, confirm dispatcher and worker instances are **Active** in the Console.

## Next steps

- [CPU render-farm worker pool template](/resources/iac-templates/render-farm-worker)
- [Media streaming](/resources/solutions/media-streaming)
- [Self-Hosted AI on Cloud Infrastructure](/docs/compute/concepts/self-hosted-ai)
- [Monitoring stack template](/resources/iac-templates/monitoring-stack) when you set `enable_monitoring = true`

## Clean up

Empty both buckets, then run `tofu destroy` from the project directory:

```bash
aws s3 rm "s3://$(tofu output -raw jobs_bucket)" --recursive --endpoint-url "$AWS_ENDPOINT_URL_S3"
aws s3 rm "s3://$(tofu output -raw output_bucket)" --recursive --endpoint-url "$AWS_ENDPOINT_URL_S3"
tofu destroy
```

Delete the EC2-compatible credential with `openstack ec2 credentials delete YOUR_ACCESS_KEY` if you created one only for this deployment.
