NetContainer.Ref
2.6.2
dotnet add package NetContainer.Ref --version 2.6.2
NuGet\Install-Package NetContainer.Ref -Version 2.6.2
<PackageReference Include="NetContainer.Ref" Version="2.6.2" />
<PackageVersion Include="NetContainer.Ref" Version="2.6.2" />
<PackageReference Include="NetContainer.Ref" />
paket add NetContainer.Ref --version 2.6.2
#r "nuget: NetContainer.Ref, 2.6.2"
#:package NetContainer.Ref@2.6.2
#addin nuget:?package=NetContainer.Ref&version=2.6.2
#tool nuget:?package=NetContainer.Ref&version=2.6.2
NetContainer.Ref
Self-contained .NET middleware library for embedding isolated Linux guests (QEMU-backed) inside any ASP.NET Core application.
Quick Start
1. Install
dotnet add package NetContainer.Ref
2. Register Services
// Program.cs
builder.Services.AddNetContainerRef(opts =>
{
opts.PreferCliDelegation = true; // Use CLI for proven boot flow
opts.MaxConcurrentGuests = 10; // Global limit
opts.DefaultTenantMaxGuests = 3; // Per-tenant limit
opts.TenantQuotas["premium"] = 10; // Custom quota for specific tenant
});
// Map the xterm.js WebSocket terminal endpoint
app.MapNetContainerTerminal(); // → /nc-terminal/{guestId}
3. Start a Guest
public class MyController(IRefOrchestratorService orchestrator) : Controller
{
[HttpPost("start")]
public async Task<IActionResult> StartGuest(CancellationToken ct)
{
// One-liner: boot a stable OpenWrt guest
var guest = await orchestrator.StartGuestAsync(
KnownDistribution.OpenWrt,
configure: opts => opts with { TenantId = "my-tenant" },
ct: ct);
return Ok(new
{
guest.Id,
guest.TenantId,
guest.SshPort, // ssh root@127.0.0.1 -p {SshPort}
guest.HttpPort, // LuCI at http://127.0.0.1:{HttpPort}
guest.VncWsPort, // noVNC WebSocket
guest.IsRunning
});
}
}
Built-in Distributions
| Distribution | Boot Method | Architectures | Default Hardware |
|---|---|---|---|
| Alpine Linux | Kernel+initramfs | x86_64, aarch64 | 2 vCPU, 256 MB |
| OpenWrt 24.10.5 | Disk Image (ext4) | x86_64, aarch64 | 2 vCPU, 512 MB |
| QEMU-only Linux | Disk Image (ext4) | x86_64, aarch64 | 2 vCPU, 512 MB |
// Alpine
var alpine = await orchestrator.StartGuestAsync(KnownDistribution.Alpine);
// OpenWrt
var openwrt = await orchestrator.StartGuestAsync(KnownDistribution.OpenWrt);
// QEMU-only profile (native QEMU pipelines)
var qemuOnly = await orchestrator.StartGuestAsync(KnownDistribution.QemuOnly);
// With custom options
var custom = await orchestrator.StartGuestAsync(
KnownDistribution.OpenWrt,
arch: "x86_64",
configure: opts => opts with
{
TenantId = "customer-7",
HardwareProfile = new HardwareProfile { MemoryMb = 1024, VirtualCpuCores = 4 }
});
Multi-Tenant Isolation
Every guest is scoped to a tenant. The default tenant is "default".
Per-Tenant Quotas
builder.Services.AddNetContainerRef(opts =>
{
opts.MaxConcurrentGuests = 50; // Global hard limit
opts.DefaultTenantMaxGuests = 3; // Each tenant gets 3 by default
opts.TenantQuotas["enterprise"] = 20; // Override for specific tenant
opts.TenantQuotas["trial"] = 1; // Trial users get 1
});
Tenant-Scoped Operations
// Start guest for a specific tenant
var guest = await orchestrator.StartGuestAsync(
KnownDistribution.OpenWrt,
configure: opts => opts with { TenantId = tenantId });
// List only this tenant's guests
var myGuests = orchestrator.GetGuestsForTenant(tenantId);
// Safe lookup — returns null if guest belongs to another tenant
var safe = orchestrator.GetGuestForTenant(tenantId, guestId);
// Count
int count = orchestrator.GetTenantGuestCount(tenantId);
// Stop one guest (only if it belongs to this tenant)
bool stopped = await orchestrator.StopGuestForTenantAsync(tenantId, guestId);
// Stop all tenant's guests
await orchestrator.StopAllForTenantAsync(tenantId);
Cross-Tenant Protection
// Tenant A starts a guest
var guest = await orchestrator.StartGuestAsync(
KnownDistribution.OpenWrt,
configure: opts => opts with { TenantId = "tenant-a" });
// Tenant B cannot access it
var result = orchestrator.GetGuestForTenant("tenant-b", guest.Id);
// result == null ✓
// Tenant B cannot stop it
bool ok = await orchestrator.StopGuestForTenantAsync("tenant-b", guest.Id);
// ok == false ✓
Per-Guest Services
Every IGuestContext exposes scoped services:
var guest = await orchestrator.StartGuestAsync(KnownDistribution.OpenWrt);
// Execute shell commands
var result = await guest.Shell.RunAsync("uname -a");
// Package management
await guest.Packages.InstallAsync("htop");
var packages = await guest.Packages.ListAsync();
// Metrics
var metrics = await guest.Analytics.GetMetricsAsync();
// Log streaming
await foreach (var line in guest.Logs.StreamAsync())
Console.WriteLine(line);
Runtime Control
// Freeze (pause vCPUs)
await guest.FreezeAsync();
// Export snapshot (must be frozen first)
var snapshot = await guest.ExportSnapshotAsync("/path/to/export");
// snapshot.Info.VmStateFile = "vmstate.bin"
// snapshot.Info.DiskImageFile = "disk.img"
// Resume
await guest.ResumeAsync();
// Memory balloon (live resize)
await guest.SetMemoryBalloonAsync(targetMb: 256);
// Stop
await orchestrator.StopGuestAsync(guest.Id);
Snapshots: Export & Restore
Save a guest's full state (RAM + disk) and restore it later:
// 1. Freeze → Export
await guest.FreezeAsync();
var result = await guest.ExportSnapshotAsync("/snapshots/my-save");
// 2. List available snapshots
var snapshots = orchestrator.ListSnapshots();
// 3. Restore from snapshot (starts QEMU with -incoming file:)
var restored = await orchestrator.StartFromSnapshotAsync("/snapshots/my-save");
// Guest resumes exactly where it was frozen
Encapsulation Audit
Verify QEMU is fully sandboxed through the host application:
var audit = orchestrator.Audit;
var report = audit?.GetAuditReport(guest.Id);
// report.EnvIsolated — QEMU sees only injected env vars
// report.PathsSandboxed — No host filesystem access
// report.LoopbackOnly — Network bound to 127.0.0.1
// report.BinaryEmbedded — QEMU binary from app's assets
Hardware Profiles
var profile = new HardwareProfile
{
VirtualCpuCores = 4,
MemoryMb = 2048,
CpuModel = "host", // or "Haswell", "max"
EnableMemoryBalloon = true, // Live memory resize
};
var guest = await orchestrator.StartGuestAsync(new RefGuestOptions
{
Arch = "x86_64",
TenantId = "my-tenant",
HardwareProfile = profile,
Display = GuestDisplayMode.Vnc, // Headless, Vnc, or Gtk
});
DI Registration Summary
| Service | Lifetime | Description |
|---|---|---|
RefOptions |
Singleton | Global configuration |
HostPlatformContext |
Singleton | OS/arch/accelerator detection |
IQemuAuditService |
Singleton | Encapsulation verification |
IRefOrchestratorService |
Singleton | Guest lifecycle + registry |
XtermWebSocketBridge |
Singleton | Browser terminal bridge |
HostProbeService |
Singleton | Host hardware diagnostics |
GuestProbeService |
Singleton | Guest runtime diagnostics |
Requirements
- .NET 10.0+
- QEMU binaries (embedded in
assets/or system-installed) - Windows: WHPX (Hyper-V) or TCG fallback
- Linux: KVM or TCG fallback
License
MIT — See LICENSE for details.
| Product | Versions 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. |
-
net10.0
- NetContainer.Common (>= 2.6.2)
- NetContainer.SelfContained (>= 2.6.2)
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 |
|---|---|---|
| 2.6.2 | 122 | 4/4/2026 |
v2.6.0:
- Multi-tenant guest isolation (TenantId, per-tenant quotas, tenant-scoped registry)
- VM snapshot export/restore via QMP migration
- Built-in Alpine + OpenWrt distributions
- Encapsulation audit service