Guides / Containers & Runtime

How to Install & Set Up Docker Engine

Install Docker Engine on Linux from the official APT repository, understand images vs. containers, build and run your first Dockerfile, and wire up networking, volumes, and Compose.

Updated 202610-step setupDownload Docker Engine →

Prerequisites

  • ✓A 64-bit Ubuntu/Debian host (or another supported Linux distribution) — Docker Desktop covers macOS/Windows separately
  • ✓sudo privileges; remove any distro-packaged docker.io or podman-docker package first to avoid conflicts
  • ✓A few hundred MB of free disk under /var/lib/docker — images and layers live there by default

Images, containers, and the daemon — the mental model

An image is a read-only, layered filesystem plus metadata (entrypoint, exposed ports, env defaults) — think of it as a class. A container is a running (or stopped) instance of that image with its own writable layer on top — think of it as an object. Every docker run creates a new container from an existing image without ever modifying the image itself.

Under the hood, the docker CLI talks to the dockerd daemon over a local socket; dockerd delegates the actual container lifecycle to containerd, which in turn uses runc to do the low-level OS work (namespaces, cgroups) that actually isolates the process. You install all three together — the docker-ce, docker-ce-cli, and containerd.io packages below — because they're one release train.

Add Docker's official APT repository

terminal
sudo apt-get update
sudo apt-get install -y ca-certificates curl
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
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

Install the Docker packages

terminal
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
!

docker-buildx-plugin and docker-compose-plugin add the `docker build` (BuildKit) and `docker compose` subcommands — both are expected to already be there on any modern install, so don't skip them.

Install on RHEL, CentOS Stream, or Fedora (official RPM repo)

Same package set, same daemon, just swap the repo URL's distro segment (centos, fedora, rhel) to match your host.

terminal
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker

Run Docker without sudo (optional)

terminal
sudo usermod -aG docker $USER
newgrp docker
!

Adding your user to the docker group grants root-equivalent access to the host. Only do this on machines you trust.

Verify the installation

terminal
docker --version
docker run hello-world

Build and run your own image

Pulling someone else's image is only half the picture — the other half is writing a Dockerfile that describes how to build yours. Each instruction adds a cached layer, so ordering matters: put the things that change least often (installing dependencies) before the things that change most often (your source code) to keep rebuilds fast.

Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
build, run, and check it
docker build -t my-app:latest .
docker run -d --name my-app -p 3000:3000 my-app:latest
docker ps
docker logs -f my-app

Networking basics

  • •bridge (default) — every container gets a private IP on a virtual bridge network; -p HOST:CONTAINER publishes a port to the host so the outside world can reach it.
  • •host — the container shares the host's network namespace directly (no port mapping needed, but no isolation either); Linux-only.
  • •none — no networking at all, for fully isolated jobs.
  • •docker network create mynet plus --network mynet lets multiple containers reach each other by container name — the basis for anything multi-service before you reach for Compose.

Persisting data with volumes

A container's writable layer disappears the moment you docker rm it, so anything that needs to survive — a database's data directory, uploaded files — belongs in a volume, not the container filesystem.

named volume (Docker manages the storage location)
docker volume create app-data
docker run -d -v app-data:/var/lib/data my-app:latest
bind mount (you control the host path — handy for local dev)
docker run -d -v "$(pwd)/data:/var/lib/data" my-app:latest

Running multiple services with Compose

Once an app is more than one container — say a web service plus a database — Docker Compose lets you describe the whole stack in one YAML file and bring it up or down as a unit.

compose.yaml
services:
  web:
    build: .
    ports: ["3000:3000"]
    depends_on: [db]
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example
    volumes: ["db-data:/var/lib/postgresql/data"]
volumes:
  db-data:
start and stop the stack
docker compose up -d
docker compose down

Documentation & Knowledge Base

Official DocumentationDocker Documentation →Knowledge Base & CommunityDocker Community Forums →
Download Docker Engine— all versions & official links→

Related Guides

PodmanInstall guide →containerdInstall guide →KubernetesInstall guide →

Need Docker Engine deployed and managed for you?

We're OpenStack Dev — we design, deploy, and operate production DevOps infrastructure.

Get in TouchAll Install Guides