Capsa is experimental software. APIs may change without notice.
Skip to content

macOS (Virtualization.framework)

Capsa's macOS backend uses Apple's Virtualization.framework, available on macOS 11 (Big Sur) and later.

Requirements

System

  • macOS 11.0 (Big Sur) or later
  • Apple Silicon (M1/M2/M3) or Intel Mac with Hypervisor.framework support

Code Signing

Virtualization.framework requires your application to be signed with the com.apple.security.virtualization entitlement.

For distribution, add this entitlement to your app:

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.virtualization</key>
    <true/>
</dict>
</plist>

Development

For development, see the Development Guide which covers how to use the codesign-run tool for automatic signing during development.

Cargo Configuration

toml
[dependencies]
capsa = { version = "0.1" }
tokio = { version = "1", features = ["full"] }

Supported Features

FeatureStatusNotes
Linux Direct BootSupportedkernel + initrd
UEFI BootSupportedVia EFI firmware
virtio-fs SharesSupportedDynamicCaller ownership only
NAT NetworkingSupportedPlatform-native NAT
UserNat NetworkingSupportedUserspace NAT with policies
Cluster NetworkingSupportedMulti-VM communication
VM Sockets (vsock)SupportedHost-guest communication
VM PoolsSupportedPre-warmed VMs
Sandbox ModeSupportedWith guest agent

Shared Directory Ownership

macOS only supports DynamicCaller ownership mapping for shared directories. Files appear owned by whoever is accessing them. Passthrough and Squash ownership modes are silently converted to DynamicCaller with a warning.

Boot Configuration

Linux Direct Boot

rust,no_run
let boot = LinuxDirectBoot::new("kernel", "initrd");

let vm = capsa::vm(boot)
    .cpus(2)
    .memory_mb(1024)
    .console_enabled()
    .build()
    .await?;

UEFI Boot

macOS supports UEFI boot with disk images:

rust,no_run
use capsa::{ DiskImage};
let disk = DiskImage::new("disk.img");
let boot = UefiBoot::new(disk)
    .with_efi_variable_store("efi_vars.bin");

let vm = capsa::vm(boot)
    .cpus(2)
    .memory_mb(2048)
    .console_enabled()
    .build()
    .await?;

INFO

UEFI boot is slower than direct boot but supports more operating systems.

Networking

Platform NAT

The simplest option using macOS's built-in NAT:

rust,no_run
use capsa::Network;
let vm = capsa::vm(boot)
    .network(Network::Nat)?
    .build()
    .await?;

For network policies and port forwarding:

rust,no_run
use capsa::{VirtualNetwork, Gateway, NetworkInterface, NetworkPolicy};
let policy = NetworkPolicy::deny_all()
    .allow_dns()
    .allow_https();

let network = VirtualNetwork::with_gateway(
    Gateway::new("10.0.2.0/24").unwrap()
        .policy(policy).unwrap()
);

let vm = capsa::vm(boot)
    .interface(NetworkInterface::new(&network).forward_tcp(8080, 80))?
    .build()
    .await?;

Troubleshooting

Entitlement Errors

text
Error: The operation couldn't be completed. (Virtualization error -1)

Solution: Your binary needs to be signed with the virtualization entitlement. For development, use the devenv which provides automatic signing.

Slow First Start

First VM launch may be slower as macOS initializes Virtualization.framework. Subsequent launches are faster.

Limitations

  1. Single vsock Connection: Each vsock port currently supports only one connection
  2. DynamicCaller Ownership Only: Shared directories always use DynamicCaller ownership mapping
  3. Linux Guests Only: macOS guests cannot be run via Virtualization.framework directly

Sandbox Mode

The easiest way to use Capsa on macOS:

rust,no_run
let vm = capsa::sandbox()
    .build()
    .await?;

let agent = vm.agent().await?;

let result = agent.exec("uname").arg("-a").run().await?;
println!("Kernel: {}", result.stdout);

Raw VM Example

For custom configurations:

rust,no_run
use capsa::VirtualNetwork;
let boot = LinuxDirectBoot::new("kernel", "initrd");
let network = VirtualNetwork::new();

let vm = capsa::vm(boot)
    .cpus(4)
    .memory_mb(2048)
    .console_enabled()
    .network(&network)?
    .vsock_listen(1024)
    .build()
    .await?;

// Console for boot detection
let console = vm.console().await?;
console.wait_for("# ", Duration::from_secs(30)).await?;

// VM is ready for your workload...

vm.shutdown().await?;

Performance

MetricApple SiliconIntel Mac
Boot Time~2-3 seconds~3-5 seconds
Memory OverheadLowModerate
CPU OverheadVery LowLow

Apple Silicon Macs generally provide better virtualization performance due to hardware optimizations.

Released under the MIT License.