Operating Systems

Installing Docker & Docker Compose

Updated December 2025
14 min read
19.5K views

Docker has revolutionized application deployment by containerizing applications and their dependencies into portable, lightweight packages. This comprehensive guide walks you through installing Docker and Docker Compose on major Linux distributions, configuring the environment, and getting started with containerization.

1

What is Docker?

Docker is a platform for developing, shipping, and running applications in isolated containers.

What Are Containers?

Lightweight, standalone packages that include everything needed to run an application: code, runtime, system tools, libraries, and settings.

Containers vs VMs

Containers share the host OS kernel, making them much lighter than VMs. They start in seconds and use minimal resources.

Why Use Docker?

Benefits

  • Consistency: Works the same everywhere
  • Isolation: Apps don't interfere with each other
  • Efficiency: Uses less resources than VMs
  • Speed: Start/stop in seconds
  • Portability: Run anywhere Docker is installed
  • Scalability: Easy to replicate and scale

Common Use Cases

  • • Microservices architecture
  • • Development environments
  • • CI/CD pipelines
  • • Application deployment
  • • Testing & QA
  • • Multi-tenant applications
System Requirements: Docker requires a 64-bit Linux kernel (3.10+), at least 2GB RAM, and root/sudo access. Most modern VPS plans support Docker out of the box.
2

Installing on Ubuntu/Debian

Official Docker installation for Ubuntu 20.04+, 22.04, 24.04 and Debian 11, 12.

Step 1: Remove Old Versions

# Remove any old Docker installations
sudo apt remove docker docker-engine docker.io containerd runc

# Clean up old packages
sudo apt autoremove -y

Step 2: Set Up Repository

# Update package index
sudo apt update

# Install prerequisites
sudo apt install -y ca-certificates curl gnupg lsb-release

# Add Docker's official GPG key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Set up the repository (Ubuntu)
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# For Debian, use this instead:
# echo \
#   "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
#   $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Step 3: Install Docker Engine

# Update package index
sudo apt update

# Install Docker Engine, CLI, containerd, and plugins
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Verify installation
sudo docker --version
sudo docker run hello-world
Success! If you see the "Hello from Docker!" message, Docker is installed and working correctly.

Quick Installation Script (Alternative)

For a faster one-liner installation:

# Official convenience script (use on fresh servers)
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Clean up
rm get-docker.sh
Note: The convenience script is only recommended for development/testing. For production, use the manual repository method above.
3

Installing on CentOS/RHEL

Installation instructions for CentOS 8/9, RHEL 8/9, Rocky Linux, and AlmaLinux.

Step 1: Remove Old Versions

# Remove old Docker installations
sudo yum remove docker docker-client docker-client-latest docker-common \
    docker-latest docker-latest-logrotate docker-logrotate docker-engine

Step 2: Set Up Repository

# Install required packages
sudo yum install -y yum-utils

# Add Docker repository
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

Step 3: Install Docker Engine

# Install Docker Engine
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Start Docker service
sudo systemctl start docker
sudo systemctl enable docker

# Verify installation
sudo docker --version
sudo docker run hello-world

For RHEL 9 / Rocky Linux 9

If you encounter issues, you may need to disable Podman first:

# Remove conflicting Podman packages
sudo yum remove podman buildah

# Then proceed with Docker installation
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
4

Installing Docker Compose

Docker Compose lets you define and run multi-container applications using YAML configuration files.

Compose V2 (Plugin Method - Recommended)

If you followed the installation steps above, Docker Compose v2 is already installed as a plugin. Verify:

# Check Docker Compose version (v2)
docker compose version

# Should output something like:
# Docker Compose version v2.24.0
Note: Docker Compose v2 uses the command docker compose (without hyphen), replacing the old docker-compose (with hyphen).

Compose V1 (Standalone Binary - Legacy)

If you need the older standalone version:

# Download Docker Compose v1
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" \
    -o /usr/local/bin/docker-compose

# Make it executable
sudo chmod +x /usr/local/bin/docker-compose

# Verify installation
docker-compose --version

Example docker-compose.yml

Here's a simple example to test Docker Compose:

# Create a test directory
mkdir ~/docker-compose-test
cd ~/docker-compose-test

# Create docker-compose.yml
cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: example
    volumes:
      - db-data:/var/lib/postgresql/data

volumes:
  db-data:
EOF

# Create HTML directory
mkdir html
echo "

Hello from Docker Compose!

" > html/index.html # Start the stack docker compose up -d # Check status docker compose ps # Test it curl http://localhost:8080 # Stop and remove docker compose down
Congratulations! You now have both Docker and Docker Compose installed and working.
5

Post-Installation Configuration

Run Docker Without Sudo

By default, Docker requires sudo. To allow your user to run Docker commands:

# Create docker group (if it doesn't exist)
sudo groupadd docker

# Add your user to the docker group
sudo usermod -aG docker $USER

# Apply group membership (log out and back in, or use):
newgrp docker

# Test it (without sudo)
docker run hello-world
Security Note: Users in the docker group have effective root privileges. Only add trusted users to this group. For production servers, consider keeping sudo requirement.

Configure Docker to Start on Boot

# Enable Docker service
sudo systemctl enable docker.service
sudo systemctl enable containerd.service

# Verify it's enabled
sudo systemctl is-enabled docker

Configure Docker Logging

Prevent logs from filling your disk:

# Create daemon configuration
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null << 'EOF'
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
EOF

# Restart Docker to apply changes
sudo systemctl restart docker

Set Up Docker Completion (Optional)

Enable bash completion for Docker commands:

# Install bash completion
sudo apt install bash-completion  # Ubuntu/Debian
# sudo yum install bash-completion  # CentOS/RHEL

# Download Docker completion
sudo curl -L https://raw.githubusercontent.com/docker/cli/master/contrib/completion/bash/docker \
    -o /etc/bash_completion.d/docker

# Reload bash (or logout/login)
source ~/.bashrc

Configure Storage Driver (Optional)

Check your current storage driver:

# Check storage driver
docker info | grep "Storage Driver"

# Most modern systems use overlay2 (default and recommended)
6

Running Your First Container

Basic Container Operations

# Pull an image from Docker Hub
docker pull nginx:alpine

# Run a container
docker run -d --name my-nginx -p 8080:80 nginx:alpine

# Explanation:
# -d = detached mode (run in background)
# --name = give container a friendly name
# -p 8080:80 = map host port 8080 to container port 80

# Check running containers
docker ps

# Test the web server
curl http://localhost:8080

# View container logs
docker logs my-nginx

# Stop the container
docker stop my-nginx

# Start it again
docker start my-nginx

# Remove the container
docker rm -f my-nginx

Interactive Container Example

# Run an interactive Ubuntu container
docker run -it ubuntu:22.04 bash

# You're now inside the container!
# Run commands:
apt update
apt install curl -y
curl https://ipinfo.io

# Exit the container
exit

Real-World Example: WordPress

# Create a WordPress site with one command
docker run -d \
  --name wordpress \
  -p 8080:80 \
  -e WORDPRESS_DB_HOST=mysql \
  -e WORDPRESS_DB_USER=wordpress \
  -e WORDPRESS_DB_PASSWORD=secret \
  -e WORDPRESS_DB_NAME=wordpress \
  --link mysql:mysql \
  wordpress:latest

# Create MySQL container first
docker run -d \
  --name mysql \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -e MYSQL_DATABASE=wordpress \
  -e MYSQL_USER=wordpress \
  -e MYSQL_PASSWORD=secret \
  mysql:8.0

# Better: Use Docker Compose instead (see Section 4)

Running a Web Server with Custom Content

# Create a directory for website files
mkdir -p ~/my-website
cd ~/my-website

# Create a simple HTML file
cat > index.html << 'EOF'


My Docker Site

  

Hello from Docker!

This website is running in a container.

EOF # Run Nginx with volume mount docker run -d \ --name my-website \ -p 8080:80 \ -v $(pwd):/usr/share/nginx/html:ro \ nginx:alpine # Visit http://your-server-ip:8080 # Edit index.html and refresh - changes appear instantly!
Pro Tip: Use Docker Compose for multi-container applications. It's much cleaner than linking containers manually.
7

Docker Management Basics

Essential Docker Commands

# Container Management
docker ps                    # List running containers
docker ps -a                 # List all containers
docker stop CONTAINER        # Stop a container
docker start CONTAINER       # Start a stopped container
docker restart CONTAINER     # Restart a container
docker rm CONTAINER          # Remove a container
docker rm -f CONTAINER       # Force remove (even if running)

# Image Management
docker images                # List images
docker pull IMAGE            # Download an image
docker rmi IMAGE             # Remove an image
docker build -t NAME .       # Build image from Dockerfile
docker tag IMAGE NEW_NAME    # Tag an image

# System Information
docker info                  # System-wide information
docker version               # Docker version
docker stats                 # Live resource usage
docker system df             # Disk usage

# Logs and Debugging
docker logs CONTAINER        # View container logs
docker logs -f CONTAINER     # Follow log output
docker exec -it CONTAINER bash   # Execute command in container
docker inspect CONTAINER     # Detailed container info

# Cleanup
docker system prune          # Remove unused data
docker system prune -a       # Remove all unused images
docker volume prune          # Remove unused volumes

Docker Compose Commands

# Basic Operations
docker compose up -d         # Start services in background
docker compose down          # Stop and remove containers
docker compose restart       # Restart services
docker compose ps            # List containers
docker compose logs -f       # Follow logs

# Service Management
docker compose start SERVICE     # Start specific service
docker compose stop SERVICE      # Stop specific service
docker compose restart SERVICE   # Restart specific service

# Maintenance
docker compose pull          # Pull latest images
docker compose build         # Rebuild images
docker compose exec SERVICE bash   # Execute command

Monitoring Resource Usage

# Live stats for all containers
docker stats

# Stats for specific container
docker stats my-nginx

# Check disk usage
docker system df

# Detailed disk usage
docker system df -v

Cleaning Up Docker

# Remove stopped containers
docker container prune

# Remove unused images
docker image prune -a

# Remove unused volumes
docker volume prune

# Remove everything unused (safe)
docker system prune

# Nuclear option - remove EVERYTHING (be careful!)
docker system prune -a --volumes
Warning: docker system prune -a --volumes will delete ALL stopped containers, unused images, and volumes. Make sure you have backups!
8

Security & Best Practices

Essential Security Practices

Use Official Images

Always prefer official images from Docker Hub. Check image sources and scan for vulnerabilities.

Don't Run as Root

Create non-root users in Dockerfiles. Use USER directive to drop privileges.

Manage Secrets Properly

Never hardcode passwords in Dockerfiles. Use Docker secrets or environment files (.env).

Keep Images Updated

Regularly rebuild and update images to include security patches.

Minimize Image Size

Use alpine variants, multi-stage builds, and .dockerignore files.

Use Named Volumes

Named volumes are easier to backup and migrate than bind mounts.

Resource Limits

Prevent containers from consuming all system resources:

# Limit memory and CPU
docker run -d \
  --name limited-nginx \
  --memory="512m" \
  --cpus="0.5" \
  nginx:alpine

# In docker-compose.yml:
services:
  web:
    image: nginx:alpine
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

Firewall Configuration

Docker modifies iptables rules. Configure UFW properly:

# Allow Docker to manage iptables
# Edit /etc/default/ufw
sudo nano /etc/default/ufw
# Set: DEFAULT_FORWARD_POLICY="ACCEPT"

# Reload UFW
sudo ufw reload

# Allow specific ports
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Backup Strategies

# Backup container data
docker run --rm \
  --volumes-from CONTAINER \
  -v $(pwd):/backup \
  ubuntu tar czf /backup/backup.tar.gz /data

# Backup volumes
docker run --rm \
  -v VOLUME_NAME:/data \
  -v $(pwd):/backup \
  ubuntu tar czf /backup/volume-backup.tar.gz /data

# Export container as image
docker commit CONTAINER my-backup:latest
docker save -o backup.tar my-backup:latest
Learn More: Visit docs.docker.com for comprehensive documentation, tutorials, and best practices.