A Windows sandbox runs a Windows guest in a Linux container via KVM/QEMU and is managed end-to-end through the OpenSandbox lifecycle API (create, expose endpoints, delete). The current Windows profile is based on dockur/windows, with service integration and capabilities provided by OpenSandbox.
This guide covers the OpenSandbox Server Windows profile (platform.os=windows):
- Create a Windows sandbox
- Check status and endpoints
- Common resources and volume settings
- Delete and cleanup
- Runtime:
dockur/windowsruns the Windows guest in a Linux container (requires KVM/QEMU), using mount points such as/storageand/boot.isofor the system disk and install media. - Control plane: On create, OpenSandbox Server injects the Windows profile configuration (devices, capabilities,
execd, port mappings) and enforces resource checks, state, and endpoint publication. - Client: You call the Lifecycle API or the Python SDK with
platform.os=windows, then follow create → pollRunning→ get endpoints → use → delete.
- Reachable OpenSandbox Server (e.g.
http://localhost:8080) - Host meets the Windows profile requirements:
/dev/kvmpresent/dev/net/tunpresent
- Server
storage.allowed_host_pathsconfigured for allowed host paths - A host directory to bind to
/storage(recommended) - Optional: a local Windows ISO for
/boot.iso(cuts repeated download time)
- Set
platform: {"os":"windows","arch":"amd64"}(arm64depends on the host) - Suggested image:
dockurr/windows:latest; seedockur/windowsreleases and Docker Hub tags
The Windows profile enforces:
resourceLimits.cpu >= 2resourceLimits.memory >= 4GresourceLimits.disk >= 64G
If resourceLimits is set, the server maps it to and overwrites these env vars:
CPU_CORESRAM_SIZEDISK_SIZE
Prefer resourceLimits only; do not set those three env vars manually.
The Windows profile wires these ports by default:
44772(execd)80803389/tcp,3389/udp(RDP)8006/tcp(typical web console)
It also builds or merges USER_PORTS (often 44772,8080,3389,8006).
- Bind a writable host directory to
/storage - Optional: bind an ISO file to
/boot.iso(readOnly=true) - Host paths must fall under
storage.allowed_host_pathsor the request is rejected
This flow:
- Create a Windows sandbox
- Wait until
Running - Get the
44772endpoint - Use the Python SDK against the sandbox
- Delete the sandbox
import os
from datetime import timedelta
from opensandbox import SandboxSync
from opensandbox.config import ConnectionConfigSync
from opensandbox.models.sandboxes import PlatformSpec
BASE_URL = os.getenv("OPEN_SANDBOX_BASE_URL", "http://localhost:8080")
API_KEY = os.getenv("OPEN_SANDBOX_API_KEY", "")
def main() -> None:
cfg = ConnectionConfigSync(
domain=BASE_URL,
api_key=API_KEY or None,
use_server_proxy=True,
)
sbx = None
try:
sbx = SandboxSync.create(
image="dockurr/windows:latest",
timeout=timedelta(hours=12),
ready_timeout=timedelta(minutes=30),
resource={
"cpu": "4",
"memory": "8G",
"disk": "64G",
},
env={"VERSION": "11"},
entrypoint=["cmd", "/c", "echo OpenSandbox Windows profile"],
platform=PlatformSpec(os="windows", arch="amd64"),
connection_config=cfg,
)
print("created:", sbx.id)
endpoint = sbx.get_endpoint(44772)
print("execd endpoint:", endpoint.endpoint)
print("sdk health:", sbx.is_healthy())
finally:
if sbx is not None:
try:
sbx.kill()
print("deleted:", sbx.id)
finally:
sbx.close()
if __name__ == "__main__":
main()The sample keeps SDK health waiting (
ready_timeout=30m). Windows cold start can be slow; increaseready_timeoutas needed. For custom readiness logic, useskip_health_check=Trueand poll forRunningin your app.
Bind a host path to /storage for a persistent system/user data directory. The directory need not exist ahead of time: it may be created on bind mount (fresh), or reused if it already exists. host.path must still be under an allowed storage.allowed_host_paths prefix, regardless of whether the directory exists.
from opensandbox.models.sandboxes import Host, Volume
volumes = [
Volume(
name="win-storage",
host=Host(path="/data/opensandbox/windows-storage"),
mount_path="/storage",
read_only=False,
),
]
# Pass as SandboxSync.create(..., volumes=volumes, ...)Bind a local Windows install ISO read-only to /boot.iso to avoid downloading media each time (also requires allowed_host_paths; the path must be a file):
from opensandbox.models.sandboxes import Host, Volume
volumes = [
Volume(
name="win-iso",
host=Host(path="/data/iso/Win11_23H2.iso"),
mount_path="/boot.iso",
read_only=True,
),
]dockur/windows is configured with environment variables. OpenSandbox passes your env into the container as documented upstream. Install / UX settings often include:
VERSION: Windows variant code (e.g.11,11l,10— full table in the project README) or, in some cases, a custom ISOhttps://URLUSERNAME/PASSWORD: first user and password (defaults in the image if omitted — see upstream)LANGUAGE: install language (e.g.English,Chinese)REGION/KEYBOARD: locale and layout (e.g.en-US,zh-CN)- Advanced cases may use
DHCP,ARGUMENTS(extra QEMU args), etc. — see thedockur/windowsFAQ
If you already set CPU, memory, and disk via resourceLimits, do not repeat the same resource keys in env as in the dockur docs; see resourceLimits vs. environment variables above. Other non-resource keys can be combined freely.
env = {
"VERSION": "11l",
"USERNAME": "Docker",
"PASSWORD": "your-secure-password",
"LANGUAGE": "Chinese",
"REGION": "zh-CN",
"KEYBOARD": "zh-CN",
}For the full list, defaults, and interactions, use the dockur/windows repository and image tags.
In dockur/windows documentation, “your own” usually means which Windows install ISO to use — not a custom recipe unrelated to upstream. The custom install FAQ states:
- For an ISO not in the project’s version table, set
VERSIONto the ISO’s download URL (https://...); the container fetches and installs it. - If you already have a local ISO file, bind it to
/boot.isoas in Existing ISO on the host above; upstream documents thatVERSIONis then ignored.
In OpenSandbox, set VERSION in env and, when needed, add a volume for the local ISO at /boot.iso, matching the upstream flow; keep image as dockurr/windows or another compatible upstream image, as in the other examples.
Snippet for the VERSION = ISO URL case (same as passing env in the minimal example):
env = {
"VERSION": "https://example.com/path/to/your.iso",
# same pattern as the minimal example for resource / platform / etc.
}-
Unsupported platform.os 'windows'on create — server build has no Windows profile; upgrade to a version that includes it. -
INVALID_PARAMETERforresourceLimits.*— ensurecpu >= 2,memory >= 4G,disk >= 64G. -
Stays
Pendinga long time — first Windows install is slow; check host resources and/storagespace, and increase wait timeouts. -
Status
Runningbut endpoint unreachable — verifyGET /v1/sandboxes/{id}/endpoints/44772returns a valid address; setenv.USER_PORTSif you need more ports forwarded.