How To Deploy from Windows Using WSL2, Docker, and DeployHQ

Devops & Infrastructure, Docker, Tips & Tricks, and Tutorials

How To Deploy from Windows Using WSL2, Docker, and DeployHQ

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:

  1. Your GitHub or GitLab account
  2. Your remote server's ~/.ssh/authorized_keys file

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:

  1. Create a new project in DeployHQ and connect your Git repository. DeployHQ supports GitHub, GitLab, Bitbucket, and any self-hosted Git server.

  2. 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).

  3. 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 $HOME by default, so the cd prefix is required. See the deployment command examples for more patterns.

  1. Enable automatic deployments (optional): Under project settings, enable auto-deploy so every push to main triggers 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:

  1. Detect the new commit via webhook
  2. Upload changed files to your server
  3. 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:

  1. Edit in VS Code on Windows
  2. Test with docker compose up in the integrated WSL2 terminal
  3. Commit and push from the same terminal
  4. 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).