Skip to main content

Installation

dotnet add package Alibaba.OpenSandbox

Quick Start

using OpenSandbox;
using OpenSandbox.Config;
using OpenSandbox.Core;

var config = new ConnectionConfig(new ConnectionConfigOptions
{
    Domain = "api.opensandbox.io",
    ApiKey = "your-api-key",
    // Protocol = ConnectionProtocol.Https,
    // RequestTimeoutSeconds = 60,
});

try
{
    await using var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions
    {
        ConnectionConfig = config,
        Image = "ubuntu",
        TimeoutSeconds = 10 * 60,
    });

    var execution = await sandbox.Commands.RunAsync("echo 'Hello Sandbox!'");
    Console.WriteLine(execution.Logs.Stdout.FirstOrDefault()?.Text);

    // Optional but recommended: terminate the remote instance when you are done.
    await sandbox.KillAsync();
}
catch (SandboxException ex)
{
    Console.Error.WriteLine($"Sandbox Error: [{ex.Error.Code}] {ex.Error.Message}");
}

Core Features

Lifecycle Management

Manage the sandbox lifecycle, including renewal, pausing, and resuming.
var info = await sandbox.GetInfoAsync();
Console.WriteLine($"State: {info.Status.State}");
Console.WriteLine($"Created: {info.CreatedAt}");
Console.WriteLine($"Expires: {info.ExpiresAt}");

await sandbox.PauseAsync();

// Resume returns a fresh, connected Sandbox instance.
var resumed = await sandbox.ResumeAsync();

// Renew: expiresAt = now + timeoutSeconds
await resumed.RenewAsync(30 * 60);

Connect to an Existing Sandbox

Use ConnectAsync when you already have a sandbox ID and need a new SDK instance bound to it.
var connected = await Sandbox.ConnectAsync(new SandboxConnectOptions
{
    SandboxId = "existing-sandbox-id",
    ConnectionConfig = config
});

Custom Health Check

Define custom logic to determine whether the sandbox is ready/healthy.
var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions
{
    ConnectionConfig = config,
    Image = "nginx:latest",
    HealthCheck = async (sbx) =>
    {
        // Example: consider the sandbox healthy when port 80 endpoint becomes available
        var ep = await sbx.GetEndpointAsync(80);
        return !string.IsNullOrEmpty(ep.EndpointAddress);
    },
});

Command Execution & Streaming

Execute commands and handle output streams in real-time.
using OpenSandbox.Models;

var handlers = new ExecutionHandlers
{
    OnStdout = msg => { Console.WriteLine($"STDOUT: {msg.Text}"); return Task.CompletedTask; },
    OnStderr = msg => { Console.Error.WriteLine($"STDERR: {msg.Text}"); return Task.CompletedTask; },
    OnExecutionComplete = c => { Console.WriteLine($"Finished in {c.ExecutionTimeMs}ms"); return Task.CompletedTask; },
};

await sandbox.Commands.RunAsync(
    "for i in 1 2 3; do echo \"Count $i\"; sleep 0.2; done",
    handlers: handlers
);

Background Commands

For background commands, you can poll status and incremental logs:
var execution = await sandbox.Commands.RunAsync(
    "python /app/server.py",
    options: new RunCommandOptions
    {
        Background = true,
        TimeoutSeconds = 120,
    });

var status = await sandbox.Commands.GetCommandStatusAsync(execution.Id!);
var logs = await sandbox.Commands.GetBackgroundCommandLogsAsync(execution.Id!, cursor: 0);
Console.WriteLine($"running={status.Running}, cursor={logs.Cursor}");

File Operations

Manage files and directories, including read, write, list/search, and delete.
await sandbox.Files.CreateDirectoriesAsync(new[]
{
    new CreateDirectoryEntry { Path = "/tmp/demo", Mode = 755 }
});

await sandbox.Files.WriteFilesAsync(new[]
{
    new WriteEntry { Path = "/tmp/demo/hello.txt", Data = "Hello World", Mode = 644 }
});

var content = await sandbox.Files.ReadFileAsync("/tmp/demo/hello.txt");
Console.WriteLine($"Content: {content}");

var files = await sandbox.Files.SearchAsync(new SearchEntry { Path = "/tmp/demo", Pattern = "*.txt" });
foreach (var file in files)
{
    Console.WriteLine(file.Path);
}

await sandbox.Files.DeleteDirectoriesAsync(new[] { "/tmp/demo" });

// Delete one or more files directly.
await sandbox.Files.DeleteFilesAsync(new[] { "/tmp/demo/hello.txt" });

Endpoints

GetEndpointAsync() returns an endpoint without a scheme (for example "localhost:44772"). Use GetEndpointUrlAsync() if you want a ready-to-use absolute URL.
var endpoint = await sandbox.GetEndpointAsync(44772);
Console.WriteLine(endpoint.EndpointAddress);

var url = await sandbox.GetEndpointUrlAsync(44772);
Console.WriteLine(url); // e.g., "http://localhost:44772"

Sandbox Management (Admin)

Use SandboxManager for administrative tasks and finding existing sandboxes.
await using var manager = SandboxManager.Create(new SandboxManagerOptions
{
    ConnectionConfig = config
});

var list = await manager.ListSandboxInfosAsync(new SandboxFilter
{
    States = new[] { SandboxStates.Running },
    PageSize = 10
});

foreach (var s in list.Items)
{
    Console.WriteLine(s.Id);
}

Configuration

Connection Configuration

The ConnectionConfig class manages API server connection settings.
ParameterDescriptionDefaultEnvironment Variable
ApiKeyAPI key for authenticationOptionalOPEN_SANDBOX_API_KEY
DomainSandbox service domain (host[:port])localhost:8080OPEN_SANDBOX_DOMAIN
ProtocolHTTP protocol (Http/Https)Http-
RequestTimeoutSecondsRequest timeout applied to SDK HTTP calls30-
UseServerProxyRequest server-proxied sandbox endpoint URLsfalse-
HeadersExtra headers applied to every request{}-
using OpenSandbox.Config;

var config = new ConnectionConfig(new ConnectionConfigOptions
{
    Domain = "api.opensandbox.io",
    ApiKey = "your-key",
    RequestTimeoutSeconds = 60,
});

Diagnostics and Logging

The SDK uses Microsoft.Extensions.Logging abstractions.
using Microsoft.Extensions.Logging;
using OpenSandbox.Config;

using var loggerFactory = LoggerFactory.Create(builder =>
{
    builder.SetMinimumLevel(LogLevel.Debug);
    builder.AddConsole();
});

var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions
{
    Image = "python:3.11",
    ConnectionConfig = new ConnectionConfig(),
    Diagnostics = new SdkDiagnosticsOptions
    {
        LoggerFactory = loggerFactory
    }
});

Sandbox Creation Configuration

Sandbox.CreateAsync() allows configuring the sandbox environment.
ParameterDescriptionDefault
ImageDocker image to useRequired
TimeoutSecondsAutomatic termination timeout (server-side TTL)10 minutes
EntrypointContainer entrypoint command["tail","-f","/dev/null"]
ResourceCPU and memory limits (string map){"cpu":"1","memory":"2Gi"}
EnvEnvironment variables{}
MetadataCustom metadata tags{}
NetworkPolicyOptional outbound network policy (egress)-
VolumesOptional storage mounts (Host / PVC, supports ReadOnly and SubPath)-
ExtensionsExtra server-defined fields{}
SkipHealthCheckSkip readiness checks (Running + health check)false
HealthCheckCustom readiness check-
ReadyTimeoutSecondsMax time to wait for readiness30 seconds
HealthCheckPollingIntervalPoll interval while waiting (milliseconds)200 ms
var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions
{
    ConnectionConfig = config,
    Image = "python:3.11",
    NetworkPolicy = new NetworkPolicy
    {
        DefaultAction = NetworkRuleAction.Deny,
        Egress = new List<NetworkRule>
        {
            new() { Action = NetworkRuleAction.Allow, Target = "pypi.org" }
        }
    },
    Volumes = new[]
    {
        new Volume
        {
            Name = "workspace",
            Host = new Host { Path = "/tmp/opensandbox-e2e/host-volume-test" },
            MountPath = "/workspace",
            ReadOnly = false
        }
    }
});

Timeout and Retry Behavior

  • ConnectionConfig.RequestTimeoutSeconds controls timeout for SDK HTTP calls.
  • RunCommandOptions.TimeoutSeconds controls command execution timeout for command runs.
  • SandboxCreateOptions.TimeoutSeconds controls sandbox server-side TTL.
  • ReadyTimeoutSeconds controls how long CreateAsync / ConnectAsync waits for readiness.
  • The SDK does not automatically retry failed API requests; implement retries in caller code where appropriate.

Resource Cleanup

Both Sandbox and SandboxManager implement IAsyncDisposable. Use await using or call DisposeAsync() when done.
await using var sandbox = await Sandbox.CreateAsync(options);
// ... use sandbox ...
// Automatically disposed when leaving scope

Error Handling

The SDK throws SandboxException (and derived exceptions such as SandboxApiException, SandboxReadyTimeoutException, and InvalidArgumentException) when operations fail.
try
{
    var execution = await sandbox.Commands.RunAsync("echo 'Hello Sandbox!'");
    Console.WriteLine(execution.Logs.Stdout.FirstOrDefault()?.Text);
}
catch (SandboxReadyTimeoutException)
{
    Console.Error.WriteLine("Sandbox did not become ready before the configured timeout.");
}
catch (SandboxApiException ex)
{
    Console.Error.WriteLine($"API Error: status={ex.StatusCode}, requestId={ex.RequestId}, message={ex.Message}");
}
catch (SandboxException ex)
{
    Console.Error.WriteLine($"Sandbox Error: [{ex.Error.Code}] {ex.Error.Message}");
}

Supported Frameworks

The SDK supports a wide range of .NET platforms:
  • .NET Standard 2.0 (for maximum compatibility with .NET Framework 4.6.1+, .NET Core 2.0+, Mono, Xamarin, etc.)
  • .NET Standard 2.1
  • .NET 6.0 (LTS)
  • .NET 7.0
  • .NET 8.0 (LTS)
  • .NET 9.0
  • .NET 10.0

API Reference

Sandbox

Main class for interacting with sandboxes.

Methods

CreateAsync
static method
Creates and initializes a new sandbox instance.Parameters:
  • options (SandboxCreateOptions): Configuration options
Returns: Task<Sandbox>
ConnectAsync
static method
Connects to an existing sandbox by ID.Parameters:
  • options (SandboxConnectOptions): Connection options including sandbox ID
Returns: Task<Sandbox>
Commands
property
Access to command execution operations.Returns: CommandsClient
Files
property
Access to file system operations.Returns: FilesClient
RenewAsync
method
Extends the sandbox expiration time.Parameters:
  • timeoutSeconds (int): Extension duration in seconds
Returns: Task
PauseAsync
method
Pauses the sandbox (suspends all processes).Returns: Task
ResumeAsync
method
Resumes this paused sandbox.Returns: Task<Sandbox>
KillAsync
method
Terminates the sandbox immediately.Returns: Task
GetInfoAsync
method
Retrieves current sandbox information.Returns: Task<SandboxInfo>
GetEndpointAsync
method
Gets the external endpoint for a port (without scheme).Parameters:
  • port (int): Internal port number
Returns: Task<SandboxEndpoint>
GetEndpointUrlAsync
method
Gets the full URL for a port (with scheme).Parameters:
  • port (int): Internal port number
Returns: Task<string>

Examples

Running a C# Script

await sandbox.Files.WriteFilesAsync(new[]
{
    new WriteEntry
    {
        Path = "/app/Program.cs",
        Data = @"
using System;
Console.WriteLine($".NET version: {Environment.Version}");
Console.WriteLine("Hello from OpenSandbox!");
        ",
        Mode = 644
    }
});

var execution = await sandbox.Commands.RunAsync("dotnet script /app/Program.cs");
foreach (var line in execution.Logs.Stdout)
{
    Console.WriteLine(line.Text);
}

Network Policy Example

var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions
{
    ConnectionConfig = config,
    Image = "mcr.microsoft.com/dotnet/sdk:8.0",
    NetworkPolicy = new NetworkPolicy
    {
        DefaultAction = NetworkRuleAction.Deny,
        Egress = new List<NetworkRule>
        {
            new() { Action = NetworkRuleAction.Allow, Target = "nuget.org" },
            new() { Action = NetworkRuleAction.Allow, Target = "api.nuget.org" },
        }
    },
});

Port Forwarding

// Start a web server in the sandbox
await sandbox.Commands.RunAsync(
    "dotnet run --project /app/WebApp.csproj",
    options: new RunCommandOptions { Background = true }
);

// Get the external URL
var url = await sandbox.GetEndpointUrlAsync(5000);
Console.WriteLine($"Access your server at: {url}");

Next Steps

Python SDK

Explore the Python SDK

JavaScript SDK

Explore the JavaScript/TypeScript SDK

API Reference

Detailed API documentation

Examples

Browse more code examples

Build docs developers (and LLMs) love