self-host →

Nested virtualization

When to use Linux KVM or Windows Hyper-V inside RunsOn runners, and the EC2 constraints that matter.

Nested virtualization lets a CI runner start another virtual machine inside the EC2 instance. The common cases are Linux KVM workloads, Android emulator acceleration, VM-based integration tests, and Windows Hyper-V workloads.

Usage

Flex

On Linux, nested-virt exposes KVM to the job so VM-based tests and accelerated emulators can run:

jobs:
kvm:
runs-on: runs-on=${{ github.run_id }}/family=c8i.large/image=ubuntu24-full-x64/nested-virt
steps:
- name: Verify KVM
run: |
test -c /dev/kvm
sudo apt-get update -qq
sudo apt-get install -y cpu-checker
sudo kvm-ok

On Windows, the same idea enables Hyper-V features and Hyper-V-isolated containers:

jobs:
hyperv:
runs-on: runs-on=${{ github.run_id }}/family=m8i.large/image=windows25-full-x64/nested-virt
steps:
- shell: pwsh
run: |
Import-Module Hyper-V
Get-WindowsFeature Hyper-V,Hyper-V-PowerShell,Containers
$Image = "mcr.microsoft.com/windows/nanoserver:ltsc2025"
docker run --isolation=hyperv $Image cmd /c ver

See nested-virt and Windows runners for full Flex syntax.

Fleet

For Fleet, nested virtualization is configured in Terraform. On a current stack the nested-enabled launch templates already exist, so you only mark the runner definitions that should launch with nested virtualization:

...
runners = {
deploy-nested-virt = {
family = ["m8i.large"]
image = "windows25-full-x64"
nested-virt = true
}
}

See Runner fleets for the full runner-catalog configuration.

Constraints

Nested virtualization is a host capability, not a package you can install after boot. The runner must launch on an EC2 family that supports it, and the stack must include the right launch templates.

Practical constraints:

  • x64 only — arm64 EC2 families do not support nested virtualization;
  • Linux uses KVM; Windows uses Hyper-V;
  • supported EC2 families only — current x64 Nitro families that expose nested virtualization;
  • requires a current RunsOn stack — existing stacks must be upgraded to include the nested-enabled launch templates before nested-virt jobs can run, otherwise the launch fails.

Flex vs Fleet

Same hardware requirement; the difference is who decides which jobs get the capability.

AspectFlexFleet
How a job enables itnested-virt job labelTarget a runner fleet that the platform team has pre-approved for nested-virt
Per-workflow override
Where the policy livesWorkflow author chooses at runtimeTerraform-owned runner fleet (family, image, IAM, network)
Supported familiesSame x64 Nitro familiesSame x64 Nitro families

When not to use it

Do not enable nested virtualization for ordinary builds, tests, or Docker workloads. It narrows instance selection and can increase launch pressure if you also require a specific family, image, region, or Spot capacity pool.