If you’ve installed Docker on a laptop before, forget most of that experience. There’s no app icon, no system tray whale, and no Docker Desktop installer here. This guide installs Docker Engine on Windows Server 2025 the way Microsoft and Docker actually support it: headless, via PowerShell, running Windows containers only.
By the end, you’ll have Docker Engine running as a Windows service, a working daemon.json, and a Windows Server Core container running and reachable over the network. Nothing fancy. Just the plumbing you need to run real workloads on this box.
Docker Desktop vs. Docker Engine on Windows Server
Docker Desktop cannot be installed on Windows Server 2025, and you shouldn’t try. Docker Desktop is built for Windows 10/11 client machines. It bundles a GUI, a WSL2 backend, and a Hyper-V VM to run Linux containers on a desktop OS. None of that exists on Server. Docker’s own licensing terms restrict Desktop to client OSes anyway.
Windows Server instead runs the same open-source Docker Engine (dockerd, docker.exe, containerd) that powers Docker on Linux, just built for Windows. You install it as a background service and manage it entirely from PowerShell or the CLI. No GUI required. That fits how most sysadmins already manage Windows Server: RDP-free, Server Core, or remote PowerShell.
Here’s the bigger gotcha, and the one that trips up people coming from a laptop setup: this Docker Engine only runs Windows containers. There’s no Linux kernel here, and no WSL2-style compatibility layer. So docker run nginx or docker run ubuntu will fail outright. Those are Linux images, and this engine has nowhere to run them. You need Windows-based images instead: mcr.microsoft.com/windows/servercore, mcr.microsoft.com/windows/nanoserver, or IIS/.NET Framework images built on top of them. If your workload needs Linux containers, use a Linux host or VM instead of this server.
Before You Begin
Make sure you have:
- A server running Windows Server 2025 (Standard or Datacenter, either Desktop Experience or Server Core)
- Administrator access via a local session or Remote Desktop/PowerShell remoting
- At least 20 GB free disk space for the OS, container images, and layer storage
- Internet access (or an internal mirror/proxy) to reach
github.comfor the install script andmcr.microsoft.comfor base images - The Hyper-V role enabled only if you plan to run containers in Hyper-V isolation mode (optional, covered below)
- No prior Docker install via the deprecated
DockerMsftProviderPowerShell module (if you do, we’ll remove it in Step 2)
| Requirement | Details |
|---|---|
| OS | Windows Server 2025, Standard or Datacenter |
| Access | Local admin or elevated PowerShell/RDP session |
| Disk | 20 GB+ free on the system drive |
| Networking | Outbound HTTPS to github.com and mcr.microsoft.com |
| Optional | Hyper-V role (only for Hyper-V isolation mode) |
All commands below were tested on Windows Server 2025 Standard (build 26100), Docker Engine 27.x, containerd 1.7.x.
Step-by-Step Guide
Step 1: Enable the Containers Windows Feature
Docker Engine depends on Windows’ built-in Containers feature. It provides the kernel-level plumbing (namespace isolation, the Host Compute Service) that containers run on. Without it, dockerd won’t start.
Open an elevated PowerShell session (right-click the Start button > Windows Terminal (Admin)) and run:
Install-WindowsFeature -Name Containers -Restart
Expected output:
Success Restart Needed Exit Code Feature Result
——- ————– ——— ————–
True Yes SuccessRestartRequired {Containers}
The -Restart flag reboots the server automatically once the feature is staged. If you omit it, run Restart-Computer manually. The feature isn’t fully active until after reboot.
If you prefer the GUI, use Server Manager instead: Manage > Add Roles and Features > Features, scroll down, and check Containers.

Step 2: Remove Any Legacy DockerMsftProvider Install
If this server previously had Docker installed through the old DockerMsftProvider PowerShell module, remove it first. That module is deprecated and no longer maintained. It can leave behind a conflicting version of dockerd that fights with a fresh install.
Get-Package -Name Docker -ProviderName DockerMsftProvider -ErrorAction SilentlyContinue
Uninstall-Package -Name Docker -ProviderName DockerMsftProvider -ErrorAction SilentlyContinue
If nothing is installed, Get-Package returns nothing and Uninstall-Package silently no-ops. That’s expected on a clean server. Skip straight to Step 3.
Why not just use
DockerMsftProviderfrom the PowerShell Gallery? It was Microsoft’s original recommended method years ago. Since then, it’s been deprecated in favor of Docker’s own install script. It installs older Docker Engine builds and doesn’t track current releases. It also isn’t the path Microsoft’s own Windows Containers documentation points to anymore. Don’t use it for new installs.
Step 3: Install Docker Engine with install-docker-ce.ps1
Microsoft maintains an install script in the Windows-Containers GitHub repository. It downloads the current Docker Engine release, registers it as a Windows service, and configures the docker CLI. This is the currently supported install method.
Download and unblock the script first. Files downloaded via Invoke-WebRequest get flagged with a “mark of the web,” and PowerShell’s execution policy blocks those by default:
Invoke-WebRequest -UseBasicParsing `
"https://raw.githubusercontent.com/microsoft/Windows-Containers/Main/helpful_tools/Install-DockerCE/install-docker-ce.ps1" `
-OutFile install-docker-ce.ps1
Unblock-File .\install-docker-ce.ps1
Note: The branch name in the raw URL above is capitalized
Main(notmain) – GitHub raw-content paths are case-sensitive, and this repository’s default branch is capitalized. Microsoft also periodically reorganizes files in this repository, so if the path above 404s, browse the Windows-Containers repository directly to confirm the current location ofinstall-docker-ce.ps1before downloading.
Then run it:
.\install-docker-ce.ps1
The script downloads the Docker Engine binaries and extracts them to C:\Program Files\Docker. It adds that path to the system PATH environment variable and registers docker as a Windows service. Expect a couple minutes of output ending in a success message and a prompt to reboot. It’s not exciting to watch, but that’s the point. It should just work.

Tip: If your execution policy still blocks the script after unblocking the file, run
Set-ExecutionPolicy RemoteSigned -Scope Processfirst. This only affects the current PowerShell session, not the whole machine.
Step 4: Restart the Server
A reboot finalizes the Docker service registration. It also finalizes the container networking components (HNS, Host Networking Service) that Docker depends on.
Restart-Computer -Force
Warning: This immediately restarts the server. Make sure no one else is mid-task on it. Also make sure you have console or out-of-band access in case the server doesn’t come back cleanly (rare, but worth having a fallback for on a production box).
Step 5: Verify Docker Engine Installed and Is Running
Once the server is back up, reconnect and check the service state:
Get-Service docker
Expected output:
Status Name DisplayName
—— —- ———–
Running docker Docker Engine
Then confirm the CLI and daemon versions match and the daemon responds:
docker version
docker info
docker version should show both a Client and Server section. If only the client section prints, and the server section errors out, the service isn’t running or isn’t reachable yet. Check the troubleshooting section below.

Step 6: Configure the Docker Daemon (daemon.json)
Docker Engine on Windows reads its daemon configuration from C:\ProgramData\docker\config\daemon.json. This file may not exist yet on a fresh install. Create it if needed.
Open it in Notepad (as admin):
notepad C:\ProgramData\docker\config\daemon.json
A reasonable starting config:
{
"data-root": "D:\\docker-data",
"hosts": ["npipe:////./pipe/docker_engine"],
"log-level": "info",
"registry-mirrors": []
}
| Setting | What it controls | Default |
|---|---|---|
data-root | Where images, container layers, and volumes are stored on disk | C:\ProgramData\docker |
hosts | Which endpoints the Docker API listens on (named pipe vs. TCP) | npipe:////./pipe/docker_engine |
log-level | Verbosity of the daemon’s own logs, useful for startup troubleshooting | info |
registry-mirrors | Internal registry mirror(s) to pull from instead of Docker Hub / MCR directly | none |
Move data-root to a dedicated data volume (D:\ in the example above) before you pull any images. Container layers add up fast, and resizing the system drive later is painful. Set this once, up front. Learn that lesson now instead of at 2 a.m. when your system drive fills up.
Warning: Don’t add a TCP host (
tcp://0.0.0.0:2375) tohostswithout also configuring TLS. An unauthenticated TCP Docker API listening on the network is a straightforward path to remote code execution on the host.

After editing, restart the service to apply the changes:
Restart-Service docker
Step 7: Pull and Run a Windows Container Image
Time to prove the whole stack works end to end. Pull a Windows Server Core image. This is the standard base image for most Windows container workloads:
docker pull mcr.microsoft.com/windows/servercore:ltsc2025
Run it interactively:
docker run -it mcr.microsoft.com/windows/servercore:ltsc2025 cmd
You should land inside a container shell prompt like C:\>. Type exit to leave it. Confirm it ran (and check past containers) with:
docker ps -a
Expected output:
CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES
7a1b2c3d4e5f mcr.microsoft.com/windows/servercore:ltsc2025 “cmd” Exited (0) 12 seconds ago gifted_hopper

Note on isolation mode: By default, Docker on Windows Server uses process isolation. It shares the host kernel directly, which is fast. But it requires the container image’s Windows build to match (or be compatible with) the host’s build. If you need to run an image built for a different Windows version, add
--isolation=hypervtodocker run. That boots the container in a lightweight Hyper-V partition. It’s slower to start and uses more memory, but it tolerates version mismatches.
Step 8: Configure Container Networking
Docker on Windows creates a default NAT network automatically. Confirm it exists:
docker network ls
Expected output includes a nat entry:
NETWORK ID NAME DRIVER SCOPE
1a2b3c4d5e6f nat nat local
To reach a containerized service from another machine, publish a port when you run the container. Here’s an example using an IIS-based image listening on port 80:
docker run -d -p 8080:80 mcr.microsoft.com/windows/servercore-iis:ltsc2025
-p 8080:80 maps host port 8080 to container port 80. Confirm it’s up with docker ps. Then open a firewall rule so external clients can reach it, since Windows Defender Firewall blocks inbound traffic by default:
New-NetFirewallRule -DisplayName "Docker Container 8080" `
-Direction Inbound -LocalPort 8080 -Protocol TCP -Action Allow

Test from another machine on the network:
curl http://your-server-ip:8080
Configuration Notes
Beyond daemon.json, a few things are worth knowing before you go further:
- Isolation mode per-container: set globally in
daemon.jsonwith"exec-opts": ["isolation=hyperv"], or per-run with--isolation. - Windows base image tags matter.
ltsc2025tracks the long-term servicing channel matching Windows Server 2025’s build. Mixing anltsc2022-tagged image on a 2025 host under process isolation is the single most common source of the “no matching manifest” error covered below. - Storage location: if you set a custom
data-root, make sure the target volume has enough free space before pulling large images. Windows base images (servercore) run 3–4 GB uncompressed.
Tips and Troubleshooting
Docker service won’t start after installation
Why it happens: The Containers feature wasn’t fully enabled and rebooted, or a leftover DockerMsftProvider install is conflicting with the new engine.
Fix:
Get-WindowsFeature -Name Containers
Confirm Installed is True. If not, redo Step 1 and reboot. If it’s already installed, check for a lingering old package (Get-Package -ProviderName DockerMsftProvider), remove it, then re-run install-docker-ce.ps1 and check Get-Service docker again.
“no matching manifest for windows/amd64” when pulling or running an image
Why it happens: The image’s Windows build doesn’t match your host’s build. Process isolation requires a matching (or compatible) kernel version. This is the error you’ll hit most often, so it’s worth remembering the fix.
Fix: Pull a tag that matches your host OS build (ltsc2025 for Windows Server 2025), or run the container with Hyper-V isolation, which tolerates version mismatches:
docker run -it --isolation=hyperv mcr.microsoft.com/windows/servercore:ltsc2022 cmd
Container can’t reach the network or the internet
Why it happens: The default NAT network wasn’t recreated after a reboot, or WinNAT conflicts with another virtual switch (commonly one created by Hyper-V).
Fix: Check the NAT network and WinNAT status:
docker network ls
Get-NetNat
If nat is missing, restart the docker service to force recreation. Avoid running Hyper-V virtual switches and Docker’s NAT network on overlapping IP ranges.
install-docker-ce.ps1 refuses to run
Why it happens: PowerShell’s execution policy or the file’s “mark of the web” blocks unsigned downloaded scripts.
Fix:
Unblock-File .\install-docker-ce.ps1
Set-ExecutionPolicy RemoteSigned -Scope Process
.\install-docker-ce.ps1
Exposed container ports aren’t reachable from other machines
Why it happens: Windows Defender Firewall blocks inbound traffic to the published port by default.
Fix: Add an inbound rule for the specific port, as shown in Step 8. Double-check you published the port at docker run time (-p hostport:containerport). A missing -p flag is the more common mistake.
Trying to run a Linux container image fails immediately
Why it happens: This Docker Engine configuration only supports Windows containers. There’s no Linux kernel, and no WSL2 backend the way Docker Desktop provides.
Fix: Use a Windows-based image (mcr.microsoft.com/windows/...), or run Linux workloads on a separate Linux host or VM instead.
Wrapping Up
You’ve got Docker Engine running as a native Windows service on Windows Server 2025. daemon.json is tuned for your storage layout, and a Windows container is reachable over the network. That’s the full loop: install, configure, run, expose.
Day-to-day Docker on Windows Server now feels a lot like Docker on Linux: same CLI, same docker-compose.yml concepts. The friction is almost entirely in image build-version matching, plus remembering you’re locked to Windows containers here. If you’re mixing workloads, keep this box for the Windows-only pieces (IIS, .NET Framework, legacy Windows services). Run Linux containers on a Linux host instead, where Docker’s ecosystem is deeper and image choice is much wider.
| Step | Action | Applies To |
|---|---|---|
| 1 | Enable Containers Windows feature | All installs |
| 2 | Remove legacy DockerMsftProvider | Only if previously installed |
| 3 | Run install-docker-ce.ps1 | All installs |
| 4 | Reboot server | All installs |
| 5 | Verify with Get-Service and docker version | All installs |
| 6 | Configure daemon.json | Optional, recommended |
| 7 | Pull and run a Windows image | All installs |
| 8 | Configure networking and firewall | When exposing services |
Resources
- Docker Engine install documentation
- Microsoft Windows Containers documentation
- Microsoft Windows-Containers GitHub repository
- Windows container version compatibility
- Docker Networking Troubleshooting: Fix Container Connection Failures on Linux (2026)
- Windows Server 2025 as an AI Host: Docker, GPU Passthrough, and Operational Baselines
- https://docs.docker.com/engine/install/binaries/
- https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-docker/configure-docker-daemon
- https://www.progressiverobot.com/2026/02/02/how-to-install-docker-on-windows-server-2025/