← Back to GuidesGUIDESelf-Hosting & Homelab

Install Docker on macOS, Windows (WSL2), and Linux: One Guide, Three Paths

about 17 hours ago
❤️ 0 likes
💬 0 comments
windowsmacosdockerself-hostinglinux
Install Docker on macOS, Windows (WSL2), and Linux: One Guide, Three Paths

Almost every guide on this site starts the same way: "make sure Docker is installed." This is the post that earns that line. One install, three operating systems, and a single command at the end that proves it worked. No prior containers knowledge needed, and nothing here assumes you have used Docker before.

The end state is the same on every OS: a working Docker Engine and a green docker run hello-world. How you get there differs. On macOS and Windows you install Docker Desktop, an app that runs the engine inside a small Linux VM for you. On Linux you install the engine natively, straight onto the machine. Pick your section below and skip the other two.

Tip

Key takeaways macOS and Windows: install Docker Desktop. It bundles the engine, the CLI, and Compose behind one app.Windows specifically: use the WSL2 backend, and run your docker commands from inside a WSL2 Linux distro.Linux: install Docker Engine from Docker's own apt repository, not the old docker.io package.On Linux, add yourself to the docker group so you can drop sudo. That group is root-equivalent, so treat it with respect.You are done when docker run hello-world prints "Hello from Docker!" That output looks the same on all three, apart from one line that names your CPU.

Prerequisites

  • A machine you can install software on, with admin or sudo rights.
  • A few GB of free disk and RAM (Docker Desktop asks for at least 4 GB on macOS, 8 GB on Windows).
  • A terminal. On macOS that is Terminal or iTerm, on Windows it is PowerShell plus your WSL2 shell, on Linux it is your normal shell.

macOS: Docker Desktop

On an Apple Silicon or Intel Mac, Docker Desktop is the path. It runs the Linux engine inside a lightweight VM and gives you the docker CLI, Compose, and a menu-bar app.

1. Check requirements. You need a currently supported macOS (the current release and the two before it) and at least 4 GB of RAM. On Apple Silicon, Rosetta 2 is recommended but no longer strictly required.

2. Download the right disk image. From Docker's official macOS install page, grab the build that matches your chip: the Apple Silicon (ARM64) Docker.dmg for M1 and later, or the Intel (AMD64) one for older Macs. Installing the wrong architecture is the most common first mistake.

3. Install it. Open the .dmg, drag the Docker icon into your Applications folder, then launch Docker from Applications. Accept the Docker Subscription Service Agreement, keep the recommended settings, and enter your password when prompted so it can finish setting up.

4. Wait for the engine. A whale icon appears in your menu bar. While it is animating, the engine is still starting. Once it settles and the Docker menu says it is running, you are ready.

5. Verify. Open a terminal and run:

Bash
1docker --version2docker run hello-world

You should see a version line followed by the "Hello from Docker!" message shown later in this guide. If the whale icon is not steady yet, give it a few more seconds and try again.

Info

Docker Desktop is not the only option on macOS. Alternatives like OrbStack and Colima also give you a real Docker Engine and the same docker CLI. Every command in this series works the same against them. If you are new, start with Docker Desktop; it is the path the official docs assume.

Windows: Docker Desktop with the WSL2 backend

On Windows, Docker Desktop runs on top of WSL2 (the Windows Subsystem for Linux, version 2). This is the modern, faster backend, and it is what you want.

1. Check requirements. Docker lists 64-bit Windows 10 (22H2, build 19045) or Windows 11 (23H2, build 22631) or newer, a 64-bit CPU with SLAT, 8 GB of RAM, and hardware virtualization enabled in your BIOS or UEFI. If virtualization is off, containers will not start, so enable it now.

2. Install WSL2. Open PowerShell as Administrator and run:

PowerShell
1wsl --install

That command installs WSL2 and a default Ubuntu distribution. If WSL is already present, update it and confirm the version instead:

PowerShell
1wsl --update2wsl --version

You want WSL version 2.1.5 or later. Reboot if it asks you to.

3. Download and run Docker Desktop. Get Docker Desktop Installer.exe for your architecture (x86_64 for most machines) from Docker's official Windows install page. Run it, and on the configuration screen make sure "Use WSL 2 instead of Hyper-V" is selected. Finish the wizard and let it authorize.

4. Start it. Search for Docker in the Start menu, open Docker Desktop, and accept the agreement. Give the engine a moment to come up.

5. Verify from inside WSL2. This is the step people miss. Open your WSL2 Linux shell (for example, launch "Ubuntu" from the Start menu), not plain PowerShell, and run:

Bash
1docker --version2docker run hello-world

Warning

Run `docker` from inside your WSL2 distro, not from PowerShell. With the WSL2 backend, Docker Desktop wires the docker command into your Linux distributions. Working from the WSL2 shell is where your project files, paths, and performance all line up. Running from PowerShell can work, but the Linux shell is the intended home.

Linux: Docker Engine (the native path)

On Linux there is no Desktop VM in the middle. You install Docker Engine directly, and it is the leanest, fastest option. The steps below are the classic .list form of Docker's official apt-repository method on Ubuntu 24.04 LTS (the current docs also show a newer deb822 .sources variant; both install the same engine). Every command and its output here was captured on a real Ubuntu 24.04.5 LTS system (a fresh VM).

Warning

Do not `apt install docker.io`. Ubuntu's built-in docker.io package is older and misses Compose v2 and buildx. Use Docker's own repository, below, to get the current engine and plugins.

1. Add Docker's official apt repository. First the prerequisites and the signing key:

Bash
1sudo apt-get update2sudo apt-get install -y ca-certificates curl3sudo install -m 0755 -d /etc/apt/keyrings4sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc5sudo chmod a+r /etc/apt/keyrings/docker.asc

Then add the repository. This one-liner fills in your architecture and Ubuntu codename automatically, so it is correct on both amd64 servers and arm64 machines:

Bash
1echo \2  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \3  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \4  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

On the test machine that wrote:

Plain Text
1deb [arch=arm64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable

2. Install the engine and plugins.

Bash
1sudo apt-get update2sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

3. Confirm the versions and that the service is running. Docker Engine installs as a systemd service that starts on boot:

Bash
1docker --version2docker compose version3systemctl is-enabled docker4systemctl is-active docker

Captured output:

Plain Text
1Docker version 29.8.0, build 88096ef2Docker Compose version v5.5.13enabled4active

4. Verify.

Bash
1sudo docker run hello-world

You will see the "Hello from Docker!" message below. Note the sudo: right after install, only root can talk to the Docker socket. The next section fixes that.

Run Docker without sudo (Linux post-install)

Typing sudo before every docker command gets old fast. Add your user to the docker group so the CLI can reach the daemon socket directly. This is one of Docker's official Linux post-install steps:

Bash
1sudo groupadd docker          # usually already exists2sudo usermod -aG docker $USER

Group membership is only picked up in a new login session. Either log out and back in, or start a fresh group session in place:

Bash
1newgrp docker

Now docker works without sudo. On the test machine, running hello-world as the normal user succeeded, printing the usual message, including:

Plain Text
1Share images, automate workflows, and more with a free Docker ID:2 https://hub.docker.com/

Warning

The `docker` group is root-equivalent. Anyone in it can start a container that mounts the whole host filesystem, which is effectively root access. Only add trusted users, and on a shared server consider rootless Docker (next) instead.

Optional: rootless Docker (Linux)

Rootless mode runs the daemon as your user, not root, which shrinks the blast radius if a container is compromised. Install the extras and run Docker's setup tool as your normal user (not with sudo):

Bash
1sudo apt-get install -y uidmap docker-ce-rootless-extras2dockerd-rootless-setuptool.sh install

Two real gotchas showed up during testing, both worth knowing:

Info

Rootless refuses to install while rootful Docker is running. The tool aborts with "rootful Docker is running and accessible" if the system daemon still holds /var/run/docker.sock. Stop it first with sudo systemctl disable --now docker.service docker.socket, then run the setup tool again. It also needs subuid/subgid ranges. If the tool complains about missing system requirements, your user has no entry in /etc/subuid and /etc/subgid. A normally created Ubuntu user already has these; if yours does not, add them (echo "$USER:100000:65536" | sudo tee -a /etc/subuid /etc/subgid) and rerun.

Once it finishes it creates a rootless CLI context and prints two environment lines to add to your shell profile. After starting the user service, docker run hello-world runs entirely as your user, and docker info reports rootless under its security options.

What a working install looks like

On every OS, success looks essentially like this. This is the real output of docker run hello-world, trimmed after the four numbered steps:

Plain Text
1Hello from Docker!2This message shows that your installation appears to be working correctly.3 4To generate this message, Docker took the following steps:5 1. The Docker client contacted the Docker daemon.6 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.7    (arm64v8)8 3. The Docker daemon created a new container from that image which runs the9    executable that produces the output you are currently reading.10 4. The Docker daemon streamed that output to the Docker client, which sent it11    to your terminal.

The (arm64v8) line just names the host CPU architecture. On an Intel or amd64 machine it reads (amd64) instead, and the rest is the same.

Those four lines are worth reading once, because they describe the whole system in miniature: a client (the docker command), a daemon (the engine), an image pulled from a registry (Docker Hub), and a container created from that image. That is the mental model the rest of this series builds on.

That registry is also the fun part. Docker Hub is the default public one, and it holds thousands of ready to run images: databases like Postgres, Redis, and MySQL, tools like nginx and Grafana, and whole self-hosted apps. Most of them are a single docker run away, which is what makes Docker so useful once it is installed.

Common gotchas, by OS

macOS: "Cannot connect to the Docker daemon"

The engine is not up yet. Check the whale icon in the menu bar; if it is still animating, wait for it to settle, then retry. If it never starts, quit and reopen Docker Desktop.

Windows: containers will not start

Almost always virtualization is disabled in BIOS/UEFI, or WSL2 is out of date. Enable virtualization, then run wsl --update and reboot.

Windows: docker not found in PowerShell

Run it from your WSL2 Linux shell instead. That is where the WSL2 backend exposes the command.

Linux: "permission denied while trying to connect to the Docker daemon socket"

You are not in the docker group yet, or you have not started a new session. Run newgrp docker or log out and back in.

Linux: apt cannot find docker-ce

The Docker repository was not added correctly. Recheck the keyring and the docker.list file from the Linux section, then run sudo apt-get update again.

Where to go next

You have a working engine. The natural next step is to actually drive it: start containers, look inside them, and clean them up.

  • Next in this series: Run Your First Containers, where we use docker run, ps, logs, exec, stop, and rm to build the real mental model of images versus containers.

Verified on 2026-09-10. The Linux path was run end to end on a real Ubuntu 24.04.5 LTS arm64 system (a fresh VM): the classic apt-repository install, the captured versions (Docker Engine 29.8.0, Compose v5.5.1, containerd 2.3.5), the systemd service showing enabled and active, `docker run hello-world`, the non-root `docker` group step, and rootless mode (including the two gotchas above). The macOS verification output was confirmed against the OrbStack engine on Apple Silicon (the same Docker Engine that Docker Desktop ships, wrapped in a different app), not Docker Desktop itself; the Docker Desktop screens follow Docker's official macOS docs. The Windows and WSL2 steps follow Docker's official Windows docs and were not captured on Windows hardware in this run.

Join the discussion on Install Docker on macOS, Windows (WSL2), and Linux: One Guide, Three Paths

Likes, comments, and replies are available for authenticated readers with verified email addresses.

Comments (0)

Loading discussion...

Related guides