If your .NET projects still build on a developer’s laptop, you are one hard drive failure away from a stalled release. A Windows VPS running a self-hosted build agent gives your CI/CD pipeline a consistent, always-on environment where MSBuild, NuGet, and the .NET SDK behave exactly as they do on a developer workstation. This guide covers why .NET builds need Windows at all, how to install a GitHub Actions runner or Azure DevOps agent on Windows Server 2022, and how much RAM and CPU to budget for parallel builds. If you are still choosing hardware, the Windows VPS provider comparison lists plans suitable for build agents.
Why .NET Builds Belong on a Windows Agent
Modern .NET (Core/5+) is cross-platform, so you can compile most console and web apps on Linux runners. But a surprisingly large share of real-world .NET workloads still needs Windows:
- .NET Framework projects (net48 and earlier) require MSBuild with the .NET Framework reference assemblies, which only ship on Windows.
- WPF, WinForms, and Windows services compile Windows-specific targets and run their test suites on Windows only.
- NuGet restore behaves identically everywhere, but package caches and native assets (e.g.
Microsoft.WindowsDesktop.Appruntimes) are far happier on Windows. - IIS deployment steps (Web Deploy,
msdeploy.exe) in Azure DevOps or GitHub Actions run natively on a Windows agent without workarounds.
In short: a Windows build agent is the environment where your artifacts are actually produced, so it should match production. If you are weighing Windows vs. Linux for .NET workloads generally, our comparison of Windows vs Linux VPS for .NET development covers the broader trade-offs.
Step 1: Provision the VPS and Install Build Tooling
Order a Windows Server 2022 (or 2025) VPS with at least 4 GB of RAM and 2 vCPUs for a single build agent — the sizing table below explains the math. After your first RDP login, install the toolchain in this order:
1. Git
winget install --id Git.Git -e --silent
2. .NET SDK
Install the SDKs matching the projects you build. The dotnet-install script works well for exact versions:
# PowerShell (x64, installs to C:\Program Files\dotnet)
Invoke-WebRequest https://dot.net/v1/dotnet-install.ps1 -UseBasicParsing | iex
dotnet --list-sdks
3. Visual Studio Build Tools (for .NET Framework / MSBuild workloads)
# Download vs_BuildTools.exe from https://aka.ms/vs/17/release/vs_BuildTools.exe
.\vs_BuildTools.exe --quiet --wait --norestart --nocache ^
--add Microsoft.VisualStudio.Workload.MSBuildTools ^
--add Microsoft.VisualStudio.Workload.NetCoreBuildTools ^
--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64
Verify MSBuild is discoverable by the agent: run vswhere.exe (in C:\Program Files (x86)\Microsoft Visual Studio\Installer) to find the MSBuild path and add it to the machine PATH.
Step 2: Install a GitHub Actions Self-Hosted Runner
In your repository go to Settings > Actions > Runners > New self-hosted runner, choose Windows x64, and copy the download URL and token. Then on the VPS:
mkdir C:\actions-runner; cd C:\actions-runner
Invoke-WebRequest -Uri https://github.com/actions/runner/releases/download/v2.327.1/actions-runner-win-x64-2.327.1.zip -OutFile runner.zip
Expand-Archive runner.zip -DestinationPath . -Force
.\config.cmd --url https://github.com/your-org/your-repo --token YOUR_TOKEN
.\run.cmd # interactive test run
Once the test run shows “Listening for Jobs”, install it as a Windows service so it survives reboots and logoffs:
cd C:\actions-runner
.\svc.cmd install
.\svc.cmd start
Get-Service -Name 'actions.runner.*'
For Azure DevOps, the equivalent is the vsts-agent-win-x64 package: run config.cmd with the organization URL and a Personal Access Token scoped to Agent Pools (read, manage), then .\run.cmd. Both agents support multiple parallel workers by configuring the agent pool’s parallelism — but parallelism is bounded by your RAM and CPU, not by the software.
Step 3: Size the VPS for Parallel Builds
MSBuild parallelizes via /m and each concurrent agent job is a separate process tree. A rough sizing model for a .NET build agent:
| Parallel jobs | vCPU | RAM | Disk (with NuGet cache) | Typical VPS tier |
|---|---|---|---|---|
| 1 | 2 | 4 GB | 40 GB | Entry-level Windows VPS |
| 2 | 4 | 8 GB | 80 GB | Mid-range |
| 4 | 8 | 16 GB | 160 GB | High-end |
Budget extra disk for %LocalAppData%\NuGet\Cache (easily 10–20 GB after a few big restores) and for _work directories left behind by failed builds. Set a cleanup job: Get-ChildItem C:\actions-runner\_work -Directory | Remove-Item -Recurse -Force on a weekly schedule. Compare full specs and pricing across providers before committing — the cheapest plan often skimps on exactly the disk you will need.
Step 4: Isolate the Agent
A build agent executes arbitrary code from your repositories, so treat it as a semi-trusted workload:
- Dedicated service account: create
svc-agentwith a long password, add it to Remote Desktop Users only — never Administrators. Register the runner service under that account. - One agent per VPS: do not mix a production IIS host with a build agent. A compromised pipeline step would otherwise land inside your web server.
- Firewall: the agent only makes outbound HTTPS connections (443) to GitHub/Azure DevOps; block inbound RDP from the internet and connect over a VPN or jump host instead.
- Secrets: store deployment credentials in the CI system’s secret store, never in
appsettingsorweb.configcommitted to the repo. For a full threat model of exposing services on a Windows VPS, see our essential Windows VPS security settings guide.
Wrap-Up
A self-hosted Windows build agent removes the flakiest part of .NET delivery: the “works on my machine” gap. Provision a Windows Server VPS, install Git + .NET SDK + Build Tools, register a GitHub Actions or Azure DevOps runner as a service, and size for the parallelism you actually use. Start with 2 vCPUs / 4 GB and one job; scale up only when queue wait times hurt. For a budget-friendly starting point, Vultr’s Windows VPS instances deploy in about a minute and let you resize CPU and RAM as your pipeline grows.



