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.
Docker is a platform for developing, shipping, and running applications in isolated containers.
Lightweight, standalone packages that include everything needed to run an application: code, runtime, system tools, libraries, and settings.
Containers share the host OS kernel, making them much lighter than VMs. They start in seconds and use minimal resources.
Official Docker installation for Ubuntu 20.04+, 22.04, 24.04 and Debian 11, 12.
# Remove any old Docker installations
sudo apt remove docker docker-engine docker.io containerd runc
# Clean up old packages
sudo apt autoremove -y
# 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
# 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
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
Installation instructions for CentOS 8/9, RHEL 8/9, Rocky Linux, and AlmaLinux.
# Remove old Docker installations
sudo yum remove docker docker-client docker-client-latest docker-common \
docker-latest docker-latest-logrotate docker-logrotate docker-engine
# 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
# 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
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
Docker Compose lets you define and run multi-container applications using YAML configuration files.
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
docker compose (without hyphen), replacing the old docker-compose (with hyphen).
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
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
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
# Enable Docker service
sudo systemctl enable docker.service
sudo systemctl enable containerd.service
# Verify it's enabled
sudo systemctl is-enabled docker
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
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
Check your current storage driver:
# Check storage driver
docker info | grep "Storage Driver"
# Most modern systems use overlay2 (default and recommended)
# 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
# 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
# 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)
# 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!
# 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
# 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
# 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
# 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
docker system prune -a --volumes will delete ALL stopped containers, unused images, and volumes. Make sure you have backups!
Always prefer official images from Docker Hub. Check image sources and scan for vulnerabilities.
Create non-root users in Dockerfiles. Use USER directive to drop privileges.
Never hardcode passwords in Dockerfiles. Use Docker secrets or environment files (.env).
Regularly rebuild and update images to include security patches.
Use alpine variants, multi-stage builds, and .dockerignore files.
Named volumes are easier to backup and migrate than bind mounts.
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
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 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
Set up Nginx with SSL certificates
Database server installation and configuration
Secure your server with best practices
Initial VPS configuration and setup
Our team can help you containerize your applications and optimize your Docker deployment.