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.
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 --installThis single command enables the WSL2 feature and installs Ubuntu (the default distribution) in one step. You may see it downloading components — let it finish.
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.
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 UbuntuThis installs Ubuntu — one of the most popular Linux distributions — inside WSL2. It will download Ubuntu and then automatically open a new terminal window.
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
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 -vYou should see something like:
NAME STATE VERSION
* Ubuntu Stopped 2The 2 under VERSION confirms you're on WSL2. If it shows 1, upgrade it:
wsl --set-version Ubuntu 2If 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.confAdd these two lines:
[boot]
systemd=trueSave 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 --shutdownWait about 10 seconds, then reopen your Ubuntu terminal. Confirm systemd is running:
systemctl is-system-runningYou 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 -yWhat does this do?
aptis Ubuntu's package manager — it handles installing and updating software, similar to an app store but for the command lineupdaterefreshes the list of available packagesupgradeinstalls any available updates-yautomatically 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.shWhat's happening here?
curlis 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 $USERBreaking this down:
usermodmodifies a user account-aG dockeradds the user to thedockergroup$USERis a variable that automatically fills in your current username
Apply the group change to your current session immediately:
newgrp dockerWithout 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 dockerWhat this does:
systemctlis how you control systemd servicesenabletells Docker to start automatically every time WSL starts--nowalso 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.
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 ~/.bashrcUse 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-worldWhat 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 versionTo confirm the auto-start worked, fully restart WSL from PowerShell
(wsl --shutdown), reopen Ubuntu, and run:
docker psYou 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.
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:
- WSL by Microsoft (
ms-vscode-remote.remote-wsl)- This lets VS Code connect to your WSL2 Ubuntu environment
- 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 .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 FilesSelect 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 ContainerVS 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 --versionYou should see something like Python 3.12.x.
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:
| Component | What it does |
|---|---|
| WSL2 | Runs a real Ubuntu Linux environment inside Windows 11 |
| systemd | Manages background services (like Docker) the standard Linux way |
| Docker Engine | Runs inside Ubuntu, manages containers |
| VS Code + WSL extension | Lets you write code with a full editor while working in Linux |
| Dev Containers | Isolates 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 dockerTroubleshooting
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.
wsl -l -v shows no distributions.
WSL2 was installed but Ubuntu wasn't added yet. Run wsl --install -d Ubuntu in PowerShell as Administrator.
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.
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.
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.
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.
"Reopen in Container" popup doesn't appear.
Use Ctrl+Shift+P → type Dev Containers: Reopen in Container to trigger it manually.