Most deployment tutorials assume you are already on Linux or macOS. But if your daily machine runs Windows, you have likely hit the gap between it works on my laptop
and it works on the server.
WSL2 closes that gap — it gives you a real Linux kernel inside Windows, so your local Docker containers behave exactly like they will in production.
This guide covers the full workflow: setting up WSL2 and Docker on Windows, structuring a project for deployment, and using DeployHQ to ship changes from your Git repository to a remote Linux server — automatically.
flowchart LR
Dev["Windows + WSL2"] -->|git push| Git["GitHub / GitLab"]
Git -->|webhook| DHQ["DeployHQ"]
DHQ -->|SSH + files| Prod["Linux VPS"]
DHQ -->|SSH commands| Prod
Why WSL2 for deployment workflows
If you develop on Windows and deploy to Linux servers, you have probably run into at least one of these problems:
- Path differences: Windows uses backslashes and drive letters (
C:\Users\), Linux uses forward slashes (/home/). Build scripts and Docker volumes break when they cross this boundary. - Shell incompatibilities: Bash scripts that run perfectly on the server fail in PowerShell or CMD.
- File permission mismatches: Linux file permissions (chmod, chown) do not exist on NTFS, causing issues with Docker volume mounts and deployment scripts.
- Line ending conflicts: Windows uses
\r\n, Linux uses\n. A single wrong line ending can break a shell script or a Dockerfile.
WSL2 solves all of these by running a real Linux distribution (not an emulation layer) inside a lightweight VM managed by Windows. Docker Desktop integrates with WSL2 directly, so containers run on a real Linux kernel — identical to your production server.
Step 1 — Install WSL2 and Ubuntu
Open PowerShell as Administrator and run:
wsl --install -d Ubuntu-24.04
This installs WSL2 (the default since Windows 10 version 2004) and Ubuntu 24.04 LTS. Restart your machine when prompted.
After reboot, Ubuntu will launch and ask you to create a Linux username and password. These are separate from your Windows credentials.
Verify the installation:
wsl --list --verbose
You should see Ubuntu-24.04 running on WSL version 2.
Already have WSL1? Upgrade with
wsl --set-version Ubuntu-24.04 2. WSL1 does not support Docker.
Step 2 — Install Docker Desktop with the WSL2 backend
Download and install Docker Desktop for Windows. During setup, ensure Use WSL 2 based engine is checked (it is the default).
After installation, open Docker Desktop and go to Settings > Resources > WSL Integration. Enable integration with your Ubuntu-24.04 distribution.
Verify from your WSL2 terminal:
docker --version
docker compose version
Both commands should work without sudo. Docker Desktop handles the daemon — you do not need to install Docker Engine inside WSL2 separately.
Performance tip
Store your project files inside the WSL2 filesystem (~/projects/), not on the Windows mount (/mnt/c/). File operations on /mnt/c/ are significantly slower due to the cross-filesystem translation layer.
mkdir -p ~/projects
cd ~/projects
Step 3 — Set up Git and SSH keys
Your WSL2 environment has its own Git configuration and SSH keys, separate from Windows. Configure them inside WSL2:
git config --global user.name "Your Name"
git config --global user.email "your@email.com"
Generate an SSH key for connecting to both your Git provider and your deployment server:
ssh-keygen -t ed25519 -C "your@email.com"
cat ~/.ssh/id_ed25519.pub
Add this public key to:
Step 4 — Create a sample Docker Compose project
Let's create a minimal project to demonstrate the full workflow. This example uses Nginx serving a static site, but the pattern works for any Docker-based application.
cd ~/projects
mkdir my-app && cd my-app
git init
Create docker-compose.yml:
services:
web:
image: nginx:alpine
ports:
- "127.0.0.1:8080:80"
volumes:
- ./public:/usr/share/nginx/html:ro
restart: unless-stopped
Create a simple page:
mkdir public
echo '<h1>Deployed with DeployHQ from WSL2</h1>' > public/index.html
Create .gitignore:
.env
Test locally:
docker compose up -d
curl http://localhost:8080
You should see your HTML. Stop it with docker compose down.
Commit and push:
git add .
git commit -m "Initial project setup"
git remote add origin git@github.com:your-username/my-app.git
git push -u origin main
Step 5 — Set up DeployHQ
DeployHQ connects your Git repository to your server and deploys changes automatically — or on your approval. Here is how to wire it up:
Create a new project in DeployHQ and connect your Git repository. DeployHQ supports GitHub, GitLab, Bitbucket, and any self-hosted Git server.
Add your server as a deployment target. Choose SSH/SFTP and enter your server's IP, SSH user, and deployment path (e.g.,
/home/deploy/my-app).Configure SSH commands to manage Docker containers on each deployment:
| Timing | Command | Purpose |
|---|---|---|
| Before upload | cd /home/deploy/my-app && docker compose down |
Stop running containers |
| After upload | cd /home/deploy/my-app && docker compose up -d --remove-orphans |
Start updated containers |
DeployHQ runs SSH commands from the user's
$HOMEby default, so thecdprefix is required. See the deployment command examples for more patterns.
- Enable automatic deployments (optional): Under project settings, enable auto-deploy so every push to
maintriggers a deployment without manual approval.
Step 6 — Deploy and verify
From your WSL2 terminal, make a change and push:
echo '<h1>Updated from WSL2!</h1><p>Deployed automatically.</p>' > public/index.html
git add .
git commit -m "Update landing page"
git push
DeployHQ will:
- Detect the new commit via webhook
- Upload changed files to your server
- Run the SSH commands to restart Docker containers
Check the deployment log in your DeployHQ dashboard to confirm success.
Step 7 — Edit with VS Code from Windows
One of the best parts of WSL2: you can edit files inside the Linux filesystem using VS Code on Windows. Install the WSL extension, then from your WSL2 terminal:
cd ~/projects/my-app
code .
VS Code opens on Windows but operates inside WSL2 — file access, terminal, Git, and Docker commands all run natively in Linux. Your workflow becomes:
- Edit in VS Code on Windows
- Test with
docker compose upin the integrated WSL2 terminal - Commit and push from the same terminal
- DeployHQ deploys to your Linux server automatically
No context switching. No path translation issues. No works on my machine
surprises.
Going further: real-world project patterns
Environment-specific configuration
Use separate Compose files for local development and production:
# Local development (with hot reload, debug ports)
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
# Production uses the base file only
# DeployHQ deploys docker-compose.yml to the server
Using DeployHQ build pipelines
If your project needs a build step (compiling assets, running tests), DeployHQ build pipelines can run commands before deploying. For example:
npm install && npm run build
This runs on DeployHQ's build servers, so your production server only receives the compiled output.
Docker image builds with DeployHQ
For projects that build custom Docker images, DeployHQ's Docker build feature can build and push images to Docker Hub, GitHub Container Registry, or other registries — then deploy a docker compose pull && docker compose up -d on your server.
Rolling back
If a deployment breaks something, open DeployHQ's deployment history and click Redeploy this version on the last working deployment. The SSH commands will restart the containers with the previous configuration.
Troubleshooting
Docker commands not available in WSL2 Open Docker Desktop > Settings > Resources > WSL Integration and ensure your Ubuntu distro is enabled. Then restart your WSL2 terminal.
Slow file access in Docker volumes
You are likely mounting from /mnt/c/. Move your project to ~/projects/ inside WSL2. The performance difference is substantial.
SSH key not working with DeployHQ or your server
Make sure you generated the key inside WSL2 (not Windows). Check permissions: chmod 600 ~/.ssh/id_ed25519. Test with ssh -T git@github.com or ssh deploy@your-server-ip.
Line ending issues in Git Configure Git inside WSL2 to keep Linux line endings:
git config --global core.autocrlf input
This ensures files stay with \n endings even if you occasionally edit them from Windows.
DeployHQ deployment times out
Docker image pulls can be slow on the first deployment. Increase the SSH command timeout in DeployHQ's server settings, or pre-pull images on the server with docker compose pull before the first deploy.
Frequently asked questions
Can I use WSL2 without Docker Desktop?
Yes. You can install Docker Engine directly inside your WSL2 Ubuntu distribution using the official Linux install steps. This avoids Docker Desktop entirely and is free for all team sizes. The trade-off is that you lose the GUI, automatic updates, and the seamless cross-distro integration that Docker Desktop provides. The deployment workflow with DeployHQ works exactly the same either way — it only cares about what you push to Git.
Does DeployHQ run on Windows or inside WSL2?
Neither. DeployHQ is a hosted service — it runs in the cloud. You interact with it through your browser or via Git webhooks. Your local environment (Windows, WSL2, macOS, Linux) only matters for writing code and pushing commits. DeployHQ connects to your Git provider and your remote server independently.
Is WSL2 fast enough for Docker development?
For containers and builds, WSL2 performs at near-native Linux speed. The one bottleneck is cross-filesystem access — reading files from /mnt/c/ (the Windows drive) inside a container is significantly slower than reading from the native Linux filesystem (~/). Keep your projects inside WSL2's home directory and performance will not be an issue.
Can I deploy to multiple servers from the same project?
Yes. DeployHQ supports multiple servers per project. You can deploy the same Git repository to a staging server and a production server with different SSH commands for each. For example, staging could auto-deploy on every push, while production requires manual approval.
What if my team uses a mix of Windows, macOS, and Linux?
That is one of the main advantages of this workflow. Docker Compose files are cross-platform, Git is cross-platform, and DeployHQ does not care what OS pushed the commit. Team members on macOS or Linux skip the WSL2 step and use Docker natively — the rest of the workflow (Git push → DeployHQ → server) is identical.
Do I need WSL2 if I only deploy static sites or PHP apps (no Docker)?
No. WSL2 and Docker are optional. DeployHQ can deploy any Git repository to any server over SSH/SFTP — no containers needed. WSL2 becomes valuable when your production stack uses Docker, because it lets you run the same containers locally on Windows that you will run on the server. For static sites or traditional PHP deployments, DeployHQ works directly without any local Docker setup.
Ready to bridge your Windows development environment with production Linux servers? Sign up for DeployHQ and connect your first project in minutes.
For questions or help, reach out to support@deployhq.com or find us on X (@deployhq).