Introduction
If you are a developer on Windows who wants to use Docker without installing Docker Desktop, you are in the right place. In this guide, you will learn how to install Docker Engine inside WSL (Windows Subsystem for Linux) using MobaXterm, test it with a real Node.js application, and manage your containers like a pro — all from the command line.
By the end of this article, you will:
- Understand what WSL and MobaXterm are and why they work great together
- Have Docker Engine installed and running inside Ubuntu on WSL
- Test Docker with the official hello-world image
- Build and run a real Node.js web app inside a Docker container
- Know how to start, stop, and clean up Docker containers
💡 Who is this guide for? Developers who are comfortable with the command line but are new to Docker on WSL. No prior Docker experience required.
1. What Are WSL and MobaXterm?
WSL — Windows Subsystem for Linux
WSL is a feature built into Windows 10 and 11 that lets you run a real Linux environment directly on your Windows machine — no virtual machine, no dual boot. You get a full Ubuntu terminal that shares your file system and network with Windows.
Think of WSL as a thin Linux layer that sits underneath your Windows desktop. It is fast, lightweight, and perfect for running developer tools like Docker, Node.js, Python, and more.
MobaXterm — A Better Terminal for WSL
MobaXterm is a powerful terminal application for Windows that includes built-in SSH, X11 forwarding, and — most importantly — direct access to your WSL sessions. It gives you a much better development experience than the default Windows Terminal for WSL work.
When you open a WSL tab in MobaXterm, you are working inside your Ubuntu environment. That is where all our Docker commands will run.
⚠️ Important Note About WSL and systemd: By default, WSL does not use systemd (the Linux service manager). This means
sudo systemctl start dockermay not work. Instead, we usesudo service docker start. This guide uses the correct command throughout.
2. Prerequisites
Before we begin, make sure you have the following:
- Windows 10 (version 2004 or later) or Windows 11
- WSL 2 installed with Ubuntu (Ubuntu 20.04 or 22.04 recommended)
- MobaXterm installed — download free from mobaxterm.mobatek.net
- A stable internet connection for downloading packages
To verify WSL is installed, open PowerShell and run:
wsl --list --verbose
You should see your Ubuntu distro listed with Version 2. If not, run wsl --set-version Ubuntu 2 to upgrade.
3. Opening Your WSL Session in MobaXterm
Launch MobaXterm and start a WSL session:
- Open MobaXterm from your Windows Start menu
- Click on Sessions → New Session
- Select WSL from the session types
- Choose your Ubuntu distribution from the dropdown
- Click OK — you now have a Linux terminal open!
Your prompt should look something like this:
sospeter@DESKTOP-ABC123:~$
All commands in this guide are run inside this MobaXterm WSL terminal.
4. Installing Docker Engine on WSL
We will install Docker Engine using the official Docker apt repository. Follow each step carefully.
Step 1: Add Docker's Official GPG Key
First, update your package list and install the required dependencies:
sudo apt update
sudo apt install ca-certificates curl -y
Then create the directory for Docker's GPG key and download it:
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
Step 2: Add the Docker Repository
Now add Docker's official package repository to your Ubuntu apt sources:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
Step 3: Install Docker Packages
Install Docker Engine along with the CLI, containerd runtime, and the Compose plugin:
sudo apt install docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin -y
This may take a few minutes depending on your internet speed.
Step 4: Start Docker
In WSL, we start Docker using the service command:
sudo service docker start
To verify Docker is running:
sudo service docker status
You should see output that includes Docker is running.
🔁 Auto-start tip: Add
sudo service docker start > /dev/null 2>&1to your~/.bashrcfile so Docker starts automatically every time you open MobaXterm.
Step 5: Add Your User to the Docker Group (Optional but Recommended)
By default, Docker commands require sudo. To run Docker without it:
sudo usermod -aG docker $USER
# Apply the group change (or close and reopen your terminal)
newgrp docker
5. Verifying Docker with hello-world
Let us confirm Docker is working with the official test image:
sudo docker run hello-world
You should see output like this:
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from Docker Hub.
3. The Docker daemon created a new container from that image.
4. The Docker daemon streamed that output to the Docker client.
If you see that — congratulations! 🎉 Docker is installed and working correctly on your WSL.
6. Building and Running a Real Node.js App
The hello-world image is a good sanity check, but let us go further and run a real web application inside Docker.
Step 1: Create a Project Folder
mkdir ~/docker-test && cd ~/docker-test
Step 2: Create the Application File
Create a file called app.js:
nano app.js
Paste the following code:
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from Docker on WSL! 🐳\n');
});
server.listen(3000, () => {
console.log('Server running on port 3000');
});
Save and exit with Ctrl + X, then Y, then Enter.
Step 3: Create the Dockerfile
nano Dockerfile
Paste the following:
# Use the official Node.js Alpine image (small and fast)
FROM node:18-alpine
# Set the working directory inside the container
WORKDIR /app
# Copy our application file into the container
COPY app.js .
# Tell Docker our app listens on port 3000
EXPOSE 3000
# Command to run when the container starts
CMD ["node", "app.js"]
Step 4: Build the Docker Image
sudo docker build -t wsl-test-app .
The -t flag gives the image a name (tag). The . tells Docker to look for the Dockerfile in the current directory.
Step 5: Run the Container
sudo docker run -d -p 3000:3000 --name my-test-app wsl-test-app
What each flag does:
| Flag | Meaning |
|---|---|
-d |
Run in the background (detached mode) |
-p 3000:3000 |
Map port 3000 on your host to port 3000 in the container |
--name my-test-app |
Give the container a friendly name |
wsl-test-app |
The image name we just built |
Step 6: Test the Running App
curl http://localhost:3000
Expected output:
Hello from Docker on WSL! 🐳
You can also open http://localhost:3000 in your Windows browser and see the same result!
7. Managing Your Containers
| Command | What It Does |
|---|---|
docker ps |
List all running containers |
docker ps -a |
List all containers including stopped ones |
docker logs my-test-app |
View logs from a container |
docker stop my-test-app |
Stop a running container |
docker start my-test-app |
Start a stopped container |
docker rm my-test-app |
Delete a container |
docker images |
List all images on your machine |
docker rmi wsl-test-app |
Delete an image |
docker exec -it <name> sh |
Open a shell inside a running container |
Cleaning Up Your Test App
# Stop the running container
sudo docker stop my-test-app
# Remove the container
sudo docker rm my-test-app
# (Optional) Remove the image
sudo docker rmi wsl-test-app
Stopping Docker Engine
sudo service docker stop
8. Troubleshooting Common Issues
Cannot connect to the Docker daemon
Run sudo service docker start to start the Docker service.
Permission denied running Docker
Either prefix commands with sudo, or add yourself to the docker group (Section 4, Step 5).
Port already in use
Change the port mapping to -p 3001:3000 and visit localhost:3001 instead.
WSL using too much RAM
Create C:\Users\YourName\.wslconfig with:
[wsl2]
memory=4GB
processors=2
9. Quick Reference Cheat Sheet
# Docker service
sudo service docker start # Start Docker
sudo service docker stop # Stop Docker
sudo service docker status # Check status
# Images
sudo docker build -t name . # Build image from Dockerfile
sudo docker images # List images
sudo docker rmi image-name # Delete image
# Containers
sudo docker run -d -p 3000:3000 --name app image # Run container
sudo docker ps # See running containers
sudo docker ps -a # See all containers
sudo docker logs app # View logs
sudo docker stop app # Stop container
sudo docker rm app # Remove container
sudo docker exec -it app sh # Shell into container
Conclusion
You have successfully:
- ✅ Installed Docker Engine on WSL using the official apt repository
- ✅ Started and verified Docker is running with the hello-world image
- ✅ Built and deployed a real Node.js application inside a Docker container
- ✅ Learned how to manage, stop, and clean up containers
Docker on WSL is a powerful setup that gives you all the benefits of Linux containers without leaving your Windows machine. As you grow more comfortable, explore Docker Compose for multi-container applications, volume mounts for persistent data, and container networking for microservices architectures.
Happy coding and containerizing! 🐳
Found this helpful? Share it with fellow developers. Follow me on X for more backend, API, and DevOps content.
Top comments (0)