Introduction
Docker Compose is a tool for defining and running multi-container Docker applications using a declarative YAML file. On Windows Server 2022, Docker Compose allows you to define complex applications — such as an IIS web server paired with a SQL Server database — in a single docker-compose.yml file, and manage the entire stack with simple commands. This guide covers installing Docker Compose on Windows Server 2022, writing Compose files for Windows containers, handling Windows-style volume paths, environment variable files, networking, and running Compose with Hyper-V isolation in production.
Installing Docker Compose on Windows Server 2022
Docker Compose is distributed as a standalone binary for Windows. The recommended installation method is to download the latest release from GitHub using PowerShell. First, create a directory for the binary and download it:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$composeVersion = "2.27.0"
$dest = "$Env:ProgramFilesDockerdocker-compose.exe"
Invoke-WebRequest -Uri "https://github.com/docker/compose/releases/download/v${composeVersion}/docker-compose-windows-x86_64.exe" -OutFile $dest
Verify Docker Compose is accessible (it should be in a directory already on the PATH if installed to Program FilesDocker):
docker-compose --version
Alternatively, if Python is installed on the server, you can install Docker Compose via pip, though the standalone binary is preferred for server environments:
pip install docker-compose
Note that modern Docker Desktop bundles Compose as a Docker CLI plugin (accessed via docker compose without the hyphen). On Windows Server without Docker Desktop, the standalone binary is the correct tool and uses docker-compose with the hyphen. Both syntaxes work for the operations covered here.
docker-compose.yml Syntax for Windows
A docker-compose.yml file for Windows containers follows the same Compose specification as Linux, with two key differences: base images must be Windows container images, and paths use Windows-style drive letters and backslashes (which must be escaped in YAML). Here is the basic structure of a Windows Compose file:
version: "3.8"
services:
webapp:
image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022
ports:
- "80:80"
volumes:
- C:inetpubmysite:C:inetpubwwwroot
environment:
- APP_ENV=production
networks:
- frontend
networks:
frontend:
driver: nat
Important YAML quoting rules for Windows paths: backslashes in YAML strings must be escaped as double backslashes, or the entire path must be quoted. The volume paths above are unquoted and Docker Compose on Windows handles them correctly; however, if paths contain spaces, they must be quoted. The network driver must be a Windows-compatible driver — nat is the correct equivalent of the default Linux bridge driver.
Defining Windows Services in Compose
Each service in the Compose file maps to a container. For Windows workloads, specify the image tag corresponding to your Windows Server version (ltsc2022) to ensure kernel compatibility. You can also build images inline by pointing to a Dockerfile:
version: "3.8"
services:
api:
build:
context: .
dockerfile: Dockerfile.windows
image: mycompany/myapi:1.0
ports:
- "8080:80"
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ConnectionStrings__Default=Server=db;Database=AppDB;User Id=sa;Password=StrongP@ss1;
depends_on:
- db
networks:
- appnet
db:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
- ACCEPT_EULA=Y
- MSSQL_SA_PASSWORD=StrongP@ss1
- MSSQL_PID=Developer
ports:
- "1433:1433"
volumes:
- sqldata:C:data
networks:
- appnet
volumes:
sqldata:
networks:
appnet:
driver: nat
Note that the SQL Server image (mcr.microsoft.com/mssql/server) is a Linux container image. Running it alongside Windows container services in the same Compose file requires LCOW (Linux Containers on Windows) to be enabled on the Docker host, or the SQL Server container must run on a separate Linux host. For purely Windows-native environments, consider using Windows-compatible alternatives or a separate SQL Server on Windows installation.
Windows-Style Volume Paths
Volume mounts in Windows containers use drive letter paths. Named volumes are managed by Docker and stored under C:ProgramDataDockervolumes on the host. Bind mounts reference actual host filesystem paths. In a Compose file, bind mounts for Windows look like this:
services:
webapp:
image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022
volumes:
- type: bind
source: C:Projectsmyappwwwroot
target: C:inetpubwwwroot
- type: bind
source: C:Projectsmyapplogs
target: C:inetpublogs
Using the long-form volume syntax (type, source, target) is clearer and avoids ambiguity with Windows paths that contain colons. The short-form : syntax also works but can confuse YAML parsers if the paths contain unescaped characters.
For named volumes (persisted across container restarts and removed only when explicitly deleted):
services:
api:
volumes:
- appdata:C:appdata
volumes:
appdata:
driver: local
Environment Files
Storing sensitive values such as database passwords in a Compose file is not recommended for production. Docker Compose supports .env files that are loaded automatically from the same directory as the Compose file, and env_file directives that load named files for specific services:
# .env file in the project root
APP_ENV=production
DB_PASSWORD=StrongP@ss1
API_KEY=abc123xyz
Reference these variables in docker-compose.yml using ${VARIABLE} syntax:
services:
api:
environment:
- APP_ENV=${APP_ENV}
- DB_PASSWORD=${DB_PASSWORD}
Alternatively, use an env_file directive to load all variables from a named file into the container’s environment:
services:
api:
env_file:
- ./config/api.env
The .env file is not committed to source control — add it to .gitignore. Provide a .env.example file with placeholder values for documentation.
IIS and SQL Server Compose Example
Here is a complete production-oriented Compose file for an ASP.NET application hosted in IIS alongside SQL Server, using Windows containers exclusively:
version: "3.8"
services:
iis:
build:
context: ./iis
dockerfile: Dockerfile
ports:
- "80:80"
- "443:443"
volumes:
- type: bind
source: C:LogsIIS
target: C:inetpublogsLogFiles
environment:
- DB_SERVER=sqlserver
- DB_NAME=AppDatabase
env_file:
- .env
depends_on:
- sqlserver
networks:
- webnet
restart: always
sqlserver:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
- ACCEPT_EULA=Y
- MSSQL_SA_PASSWORD=${DB_PASSWORD}
- MSSQL_PID=Standard
ports:
- "1433:1433"
volumes:
- sqldata:C:data
networks:
- webnet
restart: always
volumes:
sqldata:
networks:
webnet:
driver: nat
Docker Compose Commands
Start all services defined in docker-compose.yml in detached mode:
docker-compose up -d
Build images before starting (forces rebuild even if image exists):
docker-compose up -d --build
Stop and remove containers, networks, and the default volume:
docker-compose down
Stop and remove everything including named volumes (destroys data):
docker-compose down -v
View logs for all services (follow mode):
docker-compose logs -f
View logs for a specific service:
docker-compose logs -f iis
List running services and their status:
docker-compose ps
Scale a service to multiple replicas (requires Swarm or a load balancer for traffic distribution):
docker-compose up -d --scale iis=3
Execute a command inside a running service container:
docker-compose exec iis powershell
Restart a single service without restarting the whole stack:
docker-compose restart iis
Compose Networking on Windows
By default, Docker Compose creates a single NAT network for the stack and attaches all services to it. Services can reach each other using their service name as a hostname — Docker’s embedded DNS resolves service names to container IPs within the same network. For example, the IIS container can reach SQL Server at the hostname sqlserver on port 1433.
To define multiple networks and control which services are connected to which:
networks:
frontend:
driver: nat
backend:
driver: nat
services:
iis:
networks:
- frontend
- backend
sqlserver:
networks:
- backend
This isolates SQL Server to the backend network — it is only reachable from services that are also on the backend network, not directly from the external frontend.
Docker Compose with Hyper-V Isolation
Docker Compose does not have a built-in isolation field in the Compose specification. To run Compose services with Hyper-V isolation, you must set the isolation parameter in the service definition using Compose’s deploy.resources extensions or pass it via the security_opt workaround. The cleanest supported approach on standalone Docker (not Swarm) is to configure the Docker daemon’s default isolation mode:
# C:ProgramDatadockerconfigdaemon.json
{
"exec-opts": ["isolation=hyperv"]
}
Restart Docker after editing daemon.json:
Restart-Service docker
With this configuration all containers started by Docker Compose will use Hyper-V isolation by default. Verify the isolation mode after bringing up the stack:
docker inspect --format "{{.HostConfig.Isolation}}" compose_iis_1
Production Considerations
In production, Docker Compose on a single Windows Server host is suitable for small deployments. For multi-host orchestration, consider Docker Swarm or Kubernetes with Windows nodes. Several practices improve reliability:
Always set restart policies (restart: always or restart: unless-stopped) for services that should survive host reboots. Use health checks to allow dependent services to wait for readiness:
services:
sqlserver:
healthcheck:
test: ["CMD", "sqlcmd", "-S", "localhost", "-U", "sa", "-P", "${DB_PASSWORD}", "-Q", "SELECT 1"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
Pin image versions precisely (ltsc2022-specific tags) to prevent unexpected updates from breaking the stack. Store the docker-compose.yml and .env.example in source control, but never commit the .env file with real credentials.
Conclusion
Docker Compose on Windows Server 2022 streamlines multi-container Windows application management. With a single YAML file you can define services, networks, volumes, environment variables, and build contexts, then bring the entire stack up or down with one command. The combination of Windows container base images, NAT networking, and environment file support makes Compose a practical tool for deploying and managing Windows-native containerized workloads in both development and production environments.