Skip to content

RTV Capacity & Hosting Plan

Decision-support for hosting the DEF CON 34 Red Team Village tactic on-prem. It gives you the measured per-estate footprint, per-machine capacity, a sizing worksheet, and the hosting paths so you can size the fleet the moment RTV confirms the attendee count.

What's locked vs. pending

Locked: on-prem is primary (con Wi-Fi is unreliable); an estate is the full 5-VM lab; AWS is break-glass backup only. Equally supported, not yet decided: how groups map to estates — isolated (one estate per group) and shared (several groups per estate) are both first-class options; isolated is the nicer outcome and the Proxmox multi-estate path is now validated — 3 isolated estates ran green in parallel on one box (§4), so the choice is a capacity question, not a feasibility one. Pending from organizers: attendee/group count + wave timing (see the Operator Checklist week-1 questions).


1. Measured per-estate footprint

One estate = the full 5-VM lab. Every VM is cloned at 4 GB RAM / 2 vCPU (proxmox-setup.sh sets --memory 4096 --cores 2 uniformly); disks are full clones of a 30 GB template.

VM ID IP RAM vCPU Disk (alloc) Heavy services
ailab-dev 210 .10 4 GB 2 30 GB MCP server, Ollama
ailab-ml 220 .20 4 GB 2 30 GB Ray, MLflow backend, LiteLLM, vector DBs
ailab-ds 230 .30 4 GB 2 30 GB MLflow gateway, Ollama
ailab-app 250 .40 4 GB 2 30 GB TGI/inference gateway, A2A
ailab-attack 240 .99 4 GB 2 30 GB attack box (per-group operator host)
Per estate 20 GB 10 vCPU ~150 GB

Sizing notes (from measurement, not guesswork):

  • RAM is the hard limit. The only real RAM hogs are the two Ollama instances (dev + ds, ~1.5 GB resident each driving the CPU-real local inference); everything else is lightweight Python services. Plan to the full 20 GB/estate — don't bank on under-commit.
  • vCPU over-commits cleanly. Estates are idle-heavy (attendees read/enumerate, with short bursts of CPU inference), so 10 vCPU/estate is a scheduling target, not a reservation. A 16-core/32-thread host comfortably runs several estates' worth of vCPU.
  • Disk is a ceiling, not a reservation. Full clones allocate ~150 GB/estate, but thin storage (LVM-thin / qcow2) only consumes written blocks — real usage is well below the ceiling. Size the array to the ceiling anyway so you never run a pool dry mid-con.

2. Per-machine capacity

Capacity is RAM-bound: estates ≈ floor((host_RAM − host_headroom) / 20 GB), with ~8–16 GB reserved for the hypervisor itself. Use 24 GB/estate as the planning figure (20 GB VMs + ~4 GB overhead) to stay off the edge.

Host Usable RAM Estates (planning) Notes
Strix Halo mini-PC (128 GB) ~112 GB ~5 RAM-bound; 16C/32T absorbs the vCPU over-commit; fast NVMe handles the disk ceiling
Proxmox host — 64 GB (nucprox — validated) ~46 GB ~2–3 ran 3 at the edge (verified); 5 would exceed RAM
Proxmox host — 128 GB ~112 GB ~5
Proxmox host — 256 GB ~232 GB ~9–10

Combined capacity for the two-machine plan is simply the sum. Strix Halo (~5) + a 128 GB Proxmox host (~5) = ~10 estates of headroom before AWS is even considered.


3. Sizing worksheet (fill in once the count lands)

groups            = ceil(attendees / 5)
spares            = 1–2          # always carry hot spares for a failed range

Isolated-per-group and shared are equally supported delivery modes — size for whichever the hardware supports. Isolated is the nicer outcome, and the Proxmox multi-estate path is now validated (§4), so isolated capacity is bounded by RAM/disk rather than by an unproven mechanism — keep both ready and size to the box.

Isolated model — one estate per group (Ludus ranges today, Proxmox multi-estate once Track B lands — see Track B):

estates = groups + spares
machines ≈ ceil(estates / 5)    # ~5 estates per 128 GB box

Shared model — several groups per estate. The guided chain is read-mostly and each attendee scores their own ~/lab-results, so a shared estate covers the core tactic well — only the optional mutating extras collide:

estates = ceil(groups / groups_per_estate) + spares   # groups_per_estate ≈ 2–3
machines ≈ ceil(estates / 5)

Worked example — 40 attendees → 8 groups:

Model Estates (+1 spare) Machines
Isolated (1 group/estate) 9 2 (Strix Halo 5 + Proxmox 4)
Shared (2 groups/estate) 5 1 (Strix Halo)
Shared (3 groups/estate) 4 1 (Strix Halo)

We build both paths (Track B) and treat them as equal options — the con may run isolated, shared, or a mix (e.g. isolated for some groups, shared for others). The Proxmox isolated path is validated (§4), so the choice is now driven by attendee count and per-box capacity, not feasibility.


4. Per-group isolation model

Each group gets a self-contained slice (per the Operator Checklist):

  • 5 lab VMs on an isolated bridge/VLAN — no cross-group reachability.
  • Its own attack box (ailab-attack, .99) as the single foothold.
  • Its own WireGuard config, handed out at the table, terminating on that group's attack box.

In the shared model the lab VMs are shared, but each attendee still works from their own shell on the shared attack box and scores their own output — isolation degrades to "shared estate, per-attendee results," which is fine for the read-mostly guided chain. Both modes are equally supported; which a group gets depends on the hardware and what validates by con time.

The mechanism for standing up N isolated slices on one box is Track B — two paths:

  1. Proxmox bash (validated): the standard deploy parameterized by GROUP_ID — a per-estate offset for the subnet, VM IDs, and bridge so one box hosts several isolated estates. See the Multi-Estate Standup runbook for the exact commands.
  2. Ludus multi-range (isolated-per-group): purpose-built multi-tenancy — each range is {{ range_id }}-prefixed on its own VLAN with native ludus testing start/stop snapshots.

Measured: 3 isolated estates on one Proxmox host (2026-06-29)

Stood up estates 0/1/2 via GROUP_ID (VM IDs base+1000·K, subnet 172.16.(50+K), bridge vmbr10K) on a single host (nucprox, 62 GB RAM / 8 cores). Each estate independently passed verify-lab 58/0/0 + verify-chain 13/13; a parallel reset-wave --groups "0 1 2" reset and re-verified all three in a 99 s wall-clock (SLA 600 s). Per-estate footprint was ~32 GB actual on thin storage (vs the 30 GB-per-VM allocation in §1) and a fresh estate deployed in ~11 min. The limit is purely RAM: on this 62 GB box, 3 estates (~60 GB committed) is the practical ceiling — 5 estates (~100 GB) need a 128 GB box. Disk and the mechanism are not the bottleneck (8 cores absorb the vCPU over-commit; thin storage holds many estates).

See Ludus Deployment for the Ludus path's per-range deploy + WireGuard steps.

terraform/ defines a real, complete topology — all 5 instances (t3.medium ×4 + t3.xlarge for ailab-ml), a VPC/subnet/security-group, and cloud-init that sets hostnames, the labadmin user, and base packages. It is backup-only and not yet turnkey:

Capability Status
Compute + network (5 instances, VPC, SG, ENIs) Defined in terraform
Base OS bring-up (packages, labadmin, SSH) In cloud-init
Lab provisioning (deploy-all.sh) + data seeding NOT wired into apply — manual post-boot bash run
Multi-estate / multi-range No — single VPC (10.0.1.0/24, fixed IPs)
End-to-end validation by us No — never stood up + verified green

Minimum to make AWS usable as a backup (do before the con, once, then snapshot an AMI):

  1. terraform apply one range; from the attack box run the standard provisioning (deploy-all.sh against the terraform-output IPs) + seed.
  2. Run verify-lab.sh + verify-chain.sh to green.
  3. Bake AMIs so a backup range is a fast apply, not a 30-min provision.
  4. Lock allowed_ssh_cidr down from 0.0.0.0/0 before exposing anything.

Framing for the day: AWS is the parachute, not the plane. Primary is on-prem; reach for AWS only if both machines are unrecoverable and con uplink is usable.


6. Con-day contingencies (Wi-Fi-down operation)

The whole reason on-prem is primary — assume the venue network is hostile:

  • Network: bring your own switch + cabling; run each machine's estates on a local bridge so the tactic never depends on venue DHCP/DNS/uplink. Attendees reach their attack box over WireGuard on the local segment, not the internet.
  • Power: two machines + switch + a small UPS; know the per-machine draw and the booth's circuit budget. A Strix Halo mini-PC is ~120–180 W under load — trivial; a tower Proxmox host is the one to check.
  • Uplink fallback: a phone/USB tether is enough for the operator to pull a fix or reach AWS — it is not the attendee data path. Keep attendee traffic entirely local.
  • Snapshots staged: have lab-ready snapshots (and, on Ludus, pre-test snapshots) taken and verified before doors open, so the between-wave reset (Track C) is a rollback + re-seed, not a rebuild.
  • Recorded demo: keep the recorded backup demo on local disk so the talk survives a total range failure.