← Back to Notes

Setting Up a Development Environment with WSL2 and Docker on Windows 11

A complete beginner's guide to building a professional, isolated development environment on Windows 11 using WSL2, Docker Engine, VS Code, and Dev Containers — no prior Linux experience needed.

N
NOTE

This guide is written for complete beginners — no prior Linux or programming experience needed. It walks you through setting up a professional, isolated development environment on a Windows 11 laptop without affecting your main system.

What you'll end up with:

  • A real Linux (Ubuntu) environment running inside Windows
  • Docker Engine running natively inside that Linux environment
  • VS Code connected to Linux so you can write code like a professional developer
  • A fully isolated Python development container — your first dev environment

Before We Start: What Are We Actually Building?

Let's explain the key concepts before touching anything.

What is WSL2?

WSL2 stands for Windows Subsystem for Linux 2. It's a feature built into Windows 11 that lets you run a real Linux operating system (in our case, Ubuntu) directly inside Windows — no separate computer needed, no slow virtual machine. Think of it as a Linux computer living inside your Windows computer, sharing the same hardware but kept completely separate.

What is Docker?

Docker lets you create containers — isolated, lightweight environments where you can run software. Think of a container like a shipping container: everything the app needs is packed inside it, and when you're done, you can throw the whole container away without leaving a mess on your system.

For developers this means: if you want to try Python today and Node.js tomorrow, you spin up a container for each, use it, then delete it. Your main system stays completely clean.

Why install Docker inside WSL2 instead of using Docker Desktop?

Docker Desktop is a Windows application that adds a graphical interface on top of Docker. It works fine, but it runs extra background processes that use more memory and generate more heat — not ideal on a thin laptop. Installing Docker directly inside Linux (WSL2) is leaner, faster, and mirrors how Docker is used in the real world on servers. It also gives you more hands-on Linux experience.


Step 1: Install WSL2 and Ubuntu

Open PowerShell as Administrator

Click the Start menu, type PowerShell, right-click on Windows PowerShell, and select Run as administrator. A blue terminal window will open.

Run the WSL install command

wsl --install

This single command enables the WSL2 feature and installs Ubuntu (the default distribution) in one step. You may see it downloading components — let it finish.

N
NOTE

On current Windows 11, WSL2 is already the default version and wsl --install pulls in Ubuntu automatically — so you usually don't need a separate "install Ubuntu" command or a "set default version" command. The steps below show how to confirm this and what to do if your setup differs.

W
WARN

When the command finishes, it will ask you to restart your computer. Go ahead and reboot before continuing — WSL2 won't work correctly until you do.

Install Ubuntu explicitly (only if it wasn't installed automatically)

After rebooting, if Ubuntu didn't install on its own, open PowerShell as Administrator again and run:

wsl --install -d Ubuntu

This installs Ubuntu — one of the most popular Linux distributions — inside WSL2. It will download Ubuntu and then automatically open a new terminal window.

N
NOTE

What's a Linux distribution? Linux is an open-source operating system, and a "distribution" (or "distro") is a packaged version of it. Ubuntu is the most beginner-friendly one, maintained by a company called Canonical.

Create your Linux username and password

The Ubuntu terminal will ask you to create a username and password. This is your Linux account — separate from your Windows account.

  • The username should be lowercase, no spaces (e.g., john)
  • The password won't show any characters as you type — that's normal, it's a Linux security feature
  • Remember these credentials, you'll need them when running commands with sudo
N
NOTE

What is sudo? sudo stands for "superuser do." It's how you run commands with administrator privileges in Linux. You'll need to type your Linux password when prompted (and, as above, the characters won't appear as you type — that's expected).

Confirm Ubuntu is running on WSL2

Back in PowerShell, confirm Ubuntu is running on WSL version 2 (not the older version 1):

wsl -l -v

You should see something like:

  NAME      STATE           VERSION
* Ubuntu    Stopped         2

The 2 under VERSION confirms you're on WSL2. If it shows 1, upgrade it:

wsl --set-version Ubuntu 2

If you don't see Ubuntu listed yet, it may still be installing — wait a moment and try again.


Step 2: Enable systemd in WSL2

This is a small but important step that makes everything later cleaner. systemd is the standard system-and-service manager on modern Linux — it's what starts and manages background services like Docker. Recent versions of WSL2 support it, but it isn't always switched on by default.

Enabling it now means Docker can start automatically and be managed exactly the way it would be on a real Linux server — which is both simpler and more professionally realistic than the older workarounds.

Open your Ubuntu terminal (search for "Ubuntu" in the Start menu) and create/edit the WSL config file:

sudo nano /etc/wsl.conf

Add these two lines:

[boot]
systemd=true

Save and exit nano (Ctrl+O, Enter, then Ctrl+X).

Now fully restart WSL so the change takes effect. In PowerShell (not the Ubuntu terminal):

wsl --shutdown

Wait about 10 seconds, then reopen your Ubuntu terminal. Confirm systemd is running:

systemctl is-system-running

You should see running (or possibly degraded — that's fine too; it just means one unrelated service isn't happy, not that systemd failed).


Step 3: Update Ubuntu

Before installing anything on a Linux system, it's good practice to update the list of available software and upgrade any existing packages. In your Ubuntu terminal run:

sudo apt update && sudo apt upgrade -y
N
NOTE

What does this do?

  • apt is Ubuntu's package manager — it handles installing and updating software, similar to an app store but for the command line
  • update refreshes the list of available packages
  • upgrade installs any available updates
  • -y automatically answers "yes" to any prompts so you don't have to confirm each one
  • The && means "run the second command only if the first one succeeds"

This will take a minute or two. Let it finish before moving on.


Step 4: Install Docker Engine

Docker provides an official install script that handles everything automatically. Run these two commands inside your Ubuntu terminal:

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
N
NOTE

What's happening here?

  • curl is a tool for downloading files from the internet via the command line
  • The first command downloads Docker's official install script and saves it as get-docker.sh
  • The second command runs that script with administrator privileges, which installs Docker Engine, the Docker CLI, and the Compose plugin

This is the same official script used on real Linux servers — you're installing Docker exactly the way a professional would.

This will take a few minutes depending on your internet connection.


Step 5: Run Docker Without sudo

By default, Docker requires administrator privileges (sudo) to run every command. To fix this, we add your user account to the docker group — a group of users who are allowed to run Docker without sudo.

sudo usermod -aG docker $USER
N
NOTE

Breaking this down:

  • usermod modifies a user account
  • -aG docker adds the user to the docker group
  • $USER is a variable that automatically fills in your current username

Apply the group change to your current session immediately:

newgrp docker
N
NOTE

Without this step, you'd have to close and reopen your terminal for the group change to take effect. newgrp applies it to your current session instantly. (newgrp is part of the util-linux package that ships with Ubuntu by default — nothing extra to install.)


Step 6: Enable Docker to Start Automatically

Because you enabled systemd in Step 2, making Docker start on boot is now a single, standard command — the same one you'd use on any Linux server:

sudo systemctl enable --now docker
N
NOTE

What this does:

  • systemctl is how you control systemd services
  • enable tells Docker to start automatically every time WSL starts
  • --now also starts it right now, so you don't have to start it manually this first time

That's the entire auto-start setup. No editing shell config files, no password workarounds — systemd handles it properly.

T
TIP

On an older WSL build without systemd? If systemctl gave you an error back in Step 2 and you couldn't enable systemd, use this fallback instead. Start Docker automatically by adding it to your shell startup file, and allow it to start without a password:

# Auto-start Docker each time you open the terminal (fallback only)
echo 'sudo service docker start > /dev/null 2>&1' >> ~/.bashrc

# Allow starting the Docker service without a password prompt
echo "$USER ALL=(ALL) NOPASSWD: /usr/sbin/service docker start" | \
  sudo tee /etc/sudoers.d/docker-service

source ~/.bashrc

Use this only if systemd isn't available — with systemd enabled, the single systemctl enable --now docker command above is the correct approach and you should not add the .bashrc hack on top of it.


Step 7: Test Docker

Run the classic Docker test:

docker run hello-world
N
NOTE

What this does: Docker downloads a tiny test image called hello-world from the internet and runs it as a container. The container prints a success message and exits.

You should see a message that includes:

Hello from Docker!
This message shows that your installation was working correctly.

If you see that, Docker is working perfectly. Check the installed versions:

docker --version
docker compose version

To confirm the auto-start worked, fully restart WSL from PowerShell (wsl --shutdown), reopen Ubuntu, and run:

docker ps

You should see an empty table with column headers — no errors. This means Docker started automatically in the background.


Step 8: Connect VS Code to WSL2

VS Code is a free, powerful code editor made by Microsoft. It has built-in support for WSL2, which means you can open VS Code on Windows but have it edit files that live inside Linux — giving you the best of both worlds.

N
NOTE

If you don't have VS Code yet, download it from code.visualstudio.com and install it on Windows (not inside Ubuntu). Accept the default options during install.

Install the required extensions

Open VS Code on Windows, then press Ctrl+Shift+X to open the Extensions panel. Search for and install these two extensions:

  1. WSL by Microsoft (ms-vscode-remote.remote-wsl)
    • This lets VS Code connect to your WSL2 Ubuntu environment
  2. Dev Containers by Microsoft (ms-vscode-remote.remote-containers)
    • This lets VS Code open and work inside Docker containers

Open your projects folder in VS Code via WSL

In your Ubuntu terminal, create a folder for your projects and open it in VS Code:

mkdir ~/projects && cd ~/projects
code .
N
NOTE

What's ~? The tilde is shorthand for your home directory — /home/yourusername in Linux. This is where you should keep all your development work, since files stored here are inside the Linux filesystem (much faster for Docker) rather than on the Windows filesystem.

The very first time you run code . from WSL, VS Code automatically installs a small helper into Ubuntu — that's expected, and it only happens once.

VS Code will open a new window. Look at the bottom-left corner — you should see a green badge that says "WSL: Ubuntu". This confirms VS Code is connected to Linux.


Step 9: Create Your First Dev Container

This is where everything comes together. A Dev Container is a Docker container configured specifically for development — it has your language runtime and tools all running in isolation, and VS Code works directly inside it.

Create a test project

In your Ubuntu terminal:

mkdir ~/projects/test-app && cd ~/projects/test-app
code .

A new VS Code window opens, still showing the WSL: Ubuntu badge.

Add a Dev Container configuration

Press Ctrl+Shift+P to open the Command Palette (VS Code's search bar for commands). Type:

Dev Containers: Add Dev Container Configuration Files

Select it from the dropdown.

Choose a template

VS Code will show a list of pre-built development environments. Select Python 3.

You'll be asked a few follow-up questions:

  • Python version — choose 3.12 (or the latest shown)
  • Additional features — click OK without selecting anything (you can add features later)
  • Optional directories — click OK to accept the defaults

VS Code will create a hidden .devcontainer/ folder in your project containing a devcontainer.json file. This file describes your container — what language it uses, which VS Code extensions to install inside it, and so on.

Open the container

In the bottom-right corner of VS Code, a popup will appear: "Reopen in Container" — click it.

If you don't see the popup, press Ctrl+Shift+P and type:

Dev Containers: Reopen in Container

VS Code will now pull the Python 3 Docker image from the internet and build your container. The first time takes a few minutes — it's downloading everything it needs. You'll see "Connecting to Dev Container" in the bottom-left.

When it's done, the bottom-left badge will change to "Dev Container: Python 3".

Verify it's working

Open the integrated terminal inside VS Code with Ctrl+` (the backtick key, usually above Tab) and run:

python --version

You should see something like Python 3.12.x.

T
TIP

This Python is running inside the container — not on Windows, not on your Ubuntu host. If you delete this container, Python disappears with it and your system stays clean. That's the whole point: each project gets its own isolated environment that can't interfere with anything else.


You're Done!

Here's a summary of what you've built:

ComponentWhat it does
WSL2Runs a real Ubuntu Linux environment inside Windows 11
systemdManages background services (like Docker) the standard Linux way
Docker EngineRuns inside Ubuntu, manages containers
VS Code + WSL extensionLets you write code with a full editor while working in Linux
Dev ContainersIsolates each project in its own Docker container

Starting a new project in the future

Every time you start a new project, the workflow is:

mkdir ~/projects/project-name && cd ~/projects/project-name
code .

Then in VS Code: Ctrl+Shift+P → Dev Containers: Add Dev Container Configuration Files → pick your language → Reopen in Container.

That's it. A fresh, isolated environment every time.


Useful Docker Commands

# See currently running containers
docker ps

# See all containers including stopped ones
docker ps -a

# See downloaded images
docker images

# Stop a running container
docker stop <container-name>

# Remove a stopped container
docker rm <container-name>

# Clean up unused images and containers (frees disk space)
docker system prune

# Check the Docker service status (systemd)
systemctl status docker

Troubleshooting

!
BUG

systemctl gives "System has not been booted with systemd" back in Step 2. Your WSL build is older or the wsl.conf change didn't take. Confirm /etc/wsl.conf contains the [boot] / systemd=true lines exactly, run wsl --shutdown from PowerShell, wait ~10 seconds, and reopen Ubuntu. If it still fails, update WSL itself from PowerShell with wsl --update, then try again. If systemd genuinely isn't available, use the .bashrc fallback in Step 6.

!
BUG

wsl -l -v shows no distributions. WSL2 was installed but Ubuntu wasn't added yet. Run wsl --install -d Ubuntu in PowerShell as Administrator.

!
BUG

docker ps says "Cannot connect to the Docker daemon." Docker isn't running. With systemd enabled, start it with sudo systemctl start docker and make sure it's enabled on boot with sudo systemctl enable docker. If you just enabled systemd, make sure you ran wsl --shutdown and reopened the terminal.

!
BUG

docker still asks for sudo after adding yourself to the group. The group change hasn't applied to your session yet. Run newgrp docker, or close and reopen the Ubuntu terminal completely.

!
BUG

Docker container takes a long time to start the first time. That's normal — it's downloading the base image from the internet. Subsequent starts are much faster since the image is cached locally.

!
BUG

VS Code doesn't show "WSL: Ubuntu" in the bottom-left. Make sure you opened VS Code by running code . from inside the Ubuntu terminal, not by double-clicking VS Code on Windows.

!
BUG

"Reopen in Container" popup doesn't appear. Use Ctrl+Shift+P → type Dev Containers: Reopen in Container to trigger it manually.