
.NET Aspire in Windows VM using Docker on the Mac Host
This article shows the initial Docker context approach. For the ultimate solution with SSH tunnels, certificates, and port forwarding, see Part 2: Connecting Windows VMs to Mac-Hosted APIs.
The Problem
You need to build and run a .NET Aspire solution inside a Windows VM because parts of your stack (legacy services, libraries, build tooling, test harnesses, or full .NET Framework projects) are Windows-only. But you're physically on a Mac. If you try to also run Docker inside that Windows VM on Apple Silicon, you end up attempting nested (or at least layered) virtualization and translated instruction sets - it gets weird fast (works more predictably on older Intel Macs, but not reliably or efficiently on Apple Silicon). It also duplicates images, slows builds, drains battery, and explodes disk usage. You already have Docker running natively on macOS - so reuse that single, fast daemon from the Windows VM instead.
Constraints & Pain Points
- Aspire spins up multiple containers (dashboard, services, infra dependencies) - duplication across host + VM is costly.
- Windows-on-ARM or x64 translation can slow Docker inside the VM.
- Nested virtualization issues appear if you try to force Linux containers inside certain Windows VM setups.
- File sharing between VM and host can degrade I/O-heavy builds.
- Non-interactive SSH shells on macOS sometimes lack the expected PATH → docker CLI unavailable.
Desired Outcome
Run your full Aspire solution (orchestration + dashboards) from inside Windows (Parallels VM) while all containers actually execute on the macOS host's Docker daemon - with minimal friction and reliable developer ergonomics.
Architecture Overview
Windows VM:
- Runs dotnet SDK + editor (VS / VS Code)
- Uses a Docker "context" that tunnels over SSH to the Mac
macOS Host:
- Runs Docker Desktop (native daemon)
- Accepts SSH connections
- Exposes docker socket capability via remote CLI execution
Communication:
- Docker context (ssh://user@mac-ip) → invokes docker commands remotely
- No TCP daemon exposure needed (avoids opening 2375/2376)
- SSH keys recommended for auth
Primary Motivation: Windows-Only Workloads
Even if most of your modern code is .NET (Core) / .NET 8+ and technically cross-platform, many real-world solutions still include:
- Full .NET Framework class libraries or test projects
- Proprietary build steps that shell out to Windows tooling (MSBuild targets, COM automation, legacy reporting engines)
- Third-party SDKs or drivers only distributed for Windows
- Old WCF host implementations you haven't ported yet
Running those inside a Windows VM keeps the workflow intact while still letting containerized Aspire dependencies execute natively on the Mac.
Docker lets you define multiple "contexts." One context points to the remote macOS host via SSH. Once selected, any docker CLI command inside Windows transparently operates against the Mac's daemon. Aspire's orchestrator simply uses whatever Docker environment is active.
Step 1: Prepare macOS Host
- Enable Remote Login: System Settings → General → Sharing → Remote Login → ON
- Ensure docker is in PATH for non-interactive shells (SSH sessions):
echo 'export PATH="/usr/local/bin:/opt/homebrew/bin:$PATH"' >> ~/.zshenv- Test from Windows VM:
ssh <user>@<mac-ip> "command -v docker && docker version --format '{{.Server.Version}}'"If docker is “not found”, your login shell config (.zshenv vs .zprofile) is misaligned.
Step 2: Create an SSH Key
From Windows VM:
ssh-keygen -t ed25519 -C "vm-to-mac" -f "$HOME\.ssh\vm-mac"
type $HOME\.ssh\vm-mac.pub | ssh <user>@<mac-ip> "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"Step 3: Define the Docker Context (Windows VM)
docker context rm mac -f 2>$null
docker context create mac --docker "host=ssh://<user>@<mac-ip>"
docker context use mac
docker --context mac info
docker --context mac psIf this hangs: confirm you can SSH cleanly (no passphrase prompts blocking).
Step 4: Run Aspire Against Remote Docker
From your solution root in Windows:
docker context show # Should show: mac
dotnet run --project src/AppHostAll Aspire containers (dashboard, services, infra) now appear in macOS's Docker Desktop UI.
Handling File Paths & Mounts
- Volumes referencing Windows-only paths will not resolve on macOS.
- Prefer build contexts + container COPY rather than heavy bind mounts across host/VM boundary.
- If you must share code, evaluate Parallels shared folders performance; sometimes a repo clone on the Mac side (for build steps only) is faster.
Networking & Parallels Considerations
| Mode | Impact | Recommendation |
| Shared Network | VM gets NAT-like address | Usually works; confirm Mac reachable |
| Bridged | VM and Mac on same LAN | More stable IP discovery |
| Host-Only | Not suitable here | Avoid |
Find Mac IP:
ipconfig getifaddr en0If Mac IP changes (e.g., different network), update context:
docker context update mac --docker "host=ssh://<user>@<new-ip>"Why Not Just Install Docker in the VM?
Short answer: on Apple Silicon it doesn't work (double virtualization).
Intel Mac caveat: If you're on an older Intel Mac, Docker inside the VM can function more predictably because you're not crossing ARM ↔ x64 boundaries. Even then, centralizing on one daemon still simplifies your workflow.
Quick Verification Flow
docker context use mac
docker ps
dotnet new web -n sanity
cd sanity
dotnet run &Then on macOS:
docker ps | grep sanityRecap
You develop in Windows. Docker lives on macOS. An SSH-based Docker context stitches them together. Aspire just works-and you avoid duplicated engines, sluggish virtualization layers, and image sprawl.
Continue to Part 2
Next: Connecting Windows VMs to Mac-Hosted APIs for the ultimate solution with SSH tunnels, dev certificate management, and secure port forwarding.