FreeQEMU 1.0.4

dotnet add package FreeQEMU --version 1.0.4
                    
NuGet\Install-Package FreeQEMU -Version 1.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FreeQEMU" Version="1.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FreeQEMU" Version="1.0.4" />
                    
Directory.Packages.props
<PackageReference Include="FreeQEMU" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FreeQEMU --version 1.0.4
                    
#r "nuget: FreeQEMU, 1.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FreeQEMU@1.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FreeQEMU&version=1.0.4
                    
Install as a Cake Addin
#tool nuget:?package=FreeQEMU&version=1.0.4
                    
Install as a Cake Tool

FreeQEMU

NuGet GitHub License: MIT

Run Linux commands from .NET using a lightweight QEMU VM. Perfect for cross-platform development, CI/CD pipelines, and testing Linux-specific code on Windows.

โœจ Features

  • ๐Ÿš€ Instant Boot Snapshots - Pre-configured VMs boot in ~5 seconds
  • ๐Ÿ”ง Built-in Presets - .NET 8/9/10, Docker, Docker+.NET SDK, or stock Debian 12
  • ๐Ÿ“ฆ NuGet Package - QEMU binaries bundled, just add and go
  • ๐Ÿ”„ File Sync - Upload/download folders via SCP
  • ๐Ÿ“ก Streaming Output - Real-time command output callbacks
  • ๐Ÿ›ก๏ธ Ephemeral Mode - Changes discarded on shutdown
  • ๐Ÿ’พ Snapshot Management - Save/restore VM states
  • ๐Ÿณ Docker Support - Run containers inside the VM with pre-pulled images

๐Ÿ“ฆ Installation

dotnet add package FreeQEMU

Important for v1.x users: Also add the QEMU binaries package:

dotnet add package Mosa.Tools.Package.Qemu

Note: v2.0.0+ will include QEMU binaries transitively.

๐Ÿš€ Quick Start

using FreeQEMU;

// Create a VM with .NET 10 pre-installed
await using var vm = new LinuxVm(VmPreset.DotNet10);

// First run downloads/configures VM (~3min), subsequent runs use cached snapshot (~5s)
await vm.EnsureReadyAsync();

// Run commands
var result = await vm.ExecuteAsync("dotnet --version");
Console.WriteLine(result.Output); // "10.0.xxx"

// Upload a project, build it, download results
await vm.UploadFolderAsync("./MyProject", "/root/MyProject");
await vm.ExecuteAsync("cd /root/MyProject && dotnet publish -c Release -o /root/out");
await vm.DownloadFolderAsync("/root/out", "./linux-build");

๐Ÿ”ง VM Presets

Preset Description First Boot Cached Boot
Stock Vanilla Debian 12 ~30s ~5s
DotNet8 Debian 12 + .NET 8 SDK ~3min ~5s
DotNet9 Debian 12 + .NET 9 SDK ~3min ~5s
DotNet10 Debian 12 + .NET 10 SDK ~3min ~5s
Docker Debian 12 + Docker Engine ~3min ~5s
DockerDotNet9 Docker + .NET 9 SDK image pre-pulled ~5min ~5s
DockerDotNet10 Docker + .NET 10 SDK image pre-pulled ~5min ~5s
Full Debian 12 + .NET 8/9/10 + Docker ~8min ~5s

โš™๏ธ Builder Pattern (v2.0.0+)

Use the fluent builder for advanced scenarios:

await using var vm = LinuxVm.Create()
    .WithPreset(VmPreset.DockerDotNet10)
    .WithMemory(4096)              // 4GB RAM (default: 2048)
    .WithCpus(4)                   // 4 vCPUs (default: 2)
    .WithDiskSize(15)              // 15GB disk (default: 10)
    .WithSnapshot("my-dev-env")    // Custom snapshot name
    .WithSetupCommands("apt install -y nodejs npm") // Additional setup
    .Build();

await vm.EnsureReadyAsync();

๐Ÿณ Docker Example

Build and run .NET projects using Docker containers inside the VM:

await using var vm = new LinuxVm(VmPreset.Docker);
await vm.EnsureReadyAsync();

// Pull .NET SDK image (or use DockerDotNet10 preset to have it pre-cached)
await vm.ExecuteAsync("docker pull mcr.microsoft.com/dotnet/sdk:10.0");

// Upload project
await vm.UploadFolderAsync("./MyProject", "/root/MyProject");

// Build and run in container
await vm.ExecuteAsync(@"
    docker run --rm \
        -v /root/MyProject:/src \
        -w /src \
        mcr.microsoft.com/dotnet/sdk:10.0 \
        sh -c 'dotnet restore && dotnet build && dotnet run'
");

๐Ÿ“Š Progress Reporting

Track VM setup progress:

var progress = new Progress<VmSetupProgress>(p => 
    Console.WriteLine($"[{p.Stage}] {p.Message}"));

await vm.EnsureReadyAsync(progress);

Output:

[DownloadingBaseImage] Checking base image...
[GeneratingKeys] Checking SSH keys...
[CheckingSnapshot] Checking snapshot 'freeqemu-dotnet10'...
[StartingVm] Starting VM...
[WaitingForSsh] Waiting for SSH...
[Ready] VM is ready!

๐Ÿ“ก Streaming Command Output

Get real-time output from long-running commands:

var result = await vm.ExecuteAsync(
    "apt update && apt upgrade -y",
    onOutput: line => Console.WriteLine($"  {line}"),
    onError: line => Console.Error.WriteLine($"  ERR: {line}"),
    timeoutSeconds: 300);

if (!result.Success)
    Console.WriteLine($"Failed with exit code: {result.ExitCode}");

๐Ÿ“ File Transfer

Upload and download files/folders:

// Upload a folder
await vm.UploadFolderAsync(
    "./local/project", 
    "/root/project",
    new Progress<FileTransferProgress>(p => 
        Console.WriteLine($"Uploaded: {p.CurrentFile} ({p.FilesTransferred}/{p.TotalFiles})")));

// Download results
await vm.DownloadFolderAsync("/root/output", "./local/output");

๐Ÿ’พ Snapshot Management

Save and restore VM state:

// Save current state
await vm.SaveSnapshotAsync("after-npm-install");

// Later: restore to that state
await vm.RestoreSnapshotAsync("after-npm-install");

// List all snapshots
var snapshots = await vm.ListSnapshotsAsync();
foreach (var snap in snapshots)
    Console.WriteLine($"  {snap.Name}: {snap.Size}");

๐Ÿ“‹ Requirements

Requirement Details
OS Windows 10/11 (with Hyper-V or WHPX enabled recommended)
Disk ~500MB base image + ~1-2GB per preset snapshot
RAM 2-4GB for VM (configurable)
Runtime .NET 8.0 or later

Note: QEMU binaries are provided via the Mosa.Tools.Package.Qemu NuGet dependency.

๐Ÿ—๏ธ Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Your .NET Application                                   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ FreeQEMU Library                                        โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚   LinuxVm    โ”‚  โ”‚ VmConfiguration โ”‚  โ”‚  VmPreset  โ”‚ โ”‚
โ”‚  โ”‚   Builder    โ”‚  โ”‚                 โ”‚  โ”‚            โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Internal Components                                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚ QemuProcessMgr   โ”‚  โ”‚ SshConnectionManager      โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚ SnapshotManager  โ”‚  โ”‚ CloudInitGenerator        โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ QEMU VM (Debian 12)                 SSH.NET             โ”‚
โ”‚  - qemu-system-x86_64               - Command exec      โ”‚
โ”‚  - KVM/WHPX acceleration            - SCP transfer      โ”‚
โ”‚  - qcow2 snapshots                                      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ”„ How It Works

  1. First Run

    • Downloads official Debian 12 cloud image (~350MB)
    • Generates SSH keypair for secure VM access
    • Boots VM with cloud-init (injects SSH key)
    • Installs tools based on preset (e.g., .NET SDK, Docker)
    • Saves "golden snapshot" for instant restore
  2. Subsequent Runs

    • Loads snapshot directly using QEMU's -loadvm flag
    • VM starts in ~5 seconds with everything ready
    • No re-download, no re-install
  3. Command Execution

    • Commands execute via SSH connection
    • Real-time stdout/stderr streaming
    • Configurable timeouts
  4. File Transfer

    • Uses SCP via SSH.NET library
    • Supports folders with recursive transfer
    • Progress reporting

๐Ÿงช Example: CI/CD Linux Build

// Build a .NET project for Linux in CI/CD on Windows
await using var vm = new LinuxVm(VmPreset.DotNet10);
await vm.EnsureReadyAsync();

// Upload source
await vm.UploadFolderAsync("./src/MyApp", "/root/MyApp");

// Build for linux-x64
await vm.ExecuteAsync(
    "cd /root/MyApp && dotnet publish -c Release -r linux-x64 --self-contained -o /root/publish",
    onOutput: Console.WriteLine);

// Download Linux binary
await vm.DownloadFolderAsync("/root/publish", "./artifacts/linux-x64");

๐Ÿงช Example: Docker Container Build

// Use Docker inside the VM to build (no .NET installed on VM itself)
await using var vm = LinuxVm.Create()
    .WithPreset(VmPreset.DockerDotNet10)  // Docker + .NET 10 image pre-pulled
    .Build();

await vm.EnsureReadyAsync();

// Upload project
await vm.UploadFolderAsync("./MyApp", "/root/MyApp");

// Build and run entirely in Docker
var result = await vm.ExecuteAsync(@"
    docker run --rm -v /root/MyApp:/src -w /src mcr.microsoft.com/dotnet/sdk:10.0 \
        sh -c 'dotnet publish -c Release -o /app && dotnet /app/MyApp.dll'
", onOutput: Console.WriteLine);

Console.WriteLine($"Exit code: {result.ExitCode}");

๐Ÿ› Troubleshooting

Issue Solution
VM won't start Check if another QEMU process is running; FreeQEMU kills orphaned processes by default
SSH connection fails Ensure port 2222+ isn't blocked; check firewall settings
Slow first boot Normal - downloading ~350MB image and installing tools; subsequent boots use snapshot
Out of disk space Delete old snapshots in bin/Debug/net10.0/images/ directory
QEMU not found Ensure Mosa.Tools.Package.Qemu package is referenced (v1.x requirement)
"no space left on device" in VM Use WithDiskSize(15) to increase VM disk size (v2.0.0+)

๐Ÿ“„ API Reference

LinuxVm

Method Description
EnsureReadyAsync(progress?) Downloads image, creates snapshot, starts VM
ExecuteAsync(command, onOutput?, onError?, timeout?) Runs a shell command, returns result
UploadFolderAsync(local, remote, progress?) Uploads folder via SCP
DownloadFolderAsync(remote, local, progress?) Downloads folder via SCP
SaveSnapshotAsync(name) Saves current VM state
RestoreSnapshotAsync(name) Restores to saved state
ListSnapshotsAsync() Lists available snapshots
StopAsync() Gracefully stops the VM

LinuxVmBuilder (v2.0.0+)

Method Description
LinuxVm.Create() Start building a VM configuration
.WithPreset(preset) Set the VM preset
.WithMemory(mb) Set RAM in megabytes
.WithCpus(count) Set number of vCPUs
.WithDiskSize(gb) Set disk size in gigabytes
.WithSnapshot(name) Set custom snapshot name
.WithSetupCommands(cmd) Add custom setup commands
.Build() Create the LinuxVm instance

CommandResult

Property Type Description
Success bool True if exit code was 0
ExitCode int Process exit code
Output string Standard output
Error string Standard error
Duration TimeSpan Execution time

VmPreset

Value Description
Stock Vanilla Debian 12
DotNet8 .NET 8 SDK installed
DotNet9 .NET 9 SDK installed
DotNet10 .NET 10 SDK installed
Docker Docker Engine installed
DockerDotNet9 Docker + .NET 9 SDK image pre-pulled
DockerDotNet10 Docker + .NET 10 SDK image pre-pulled
Full .NET 8/9/10 + Docker

๐Ÿ“š Examples in Repository

The repository includes full working examples:

Project Description
FreeQEMU.HelloWorldExample Basic build/run with .NET SDK preset
FreeQEMU.DockerExample Docker container builds with DockerDotNet10 preset
FreeQEMU.HelloWorldExampleNugetTest Same as HelloWorld but using NuGet package
FreeQEMU.DockerExampleNugetTest Same as Docker but using NuGet package
HelloWorldTest Simple .NET 10 console app used as build target

๐Ÿ“„ License

MIT License - See LICENSE for details.

๐Ÿค Contributing

Contributions welcome! Please see the GitHub repository for guidelines.


Made with โค๏ธ by WSU-EIT

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.4 117 1/27/2026
1.0.3 97 1/26/2026
1.0.1 103 1/23/2026