Linux 6 min read

How to Install Docker on Ubuntu: A Complete Beginner's Guide

Suresh Suresh

Docker has revolutionized the way developers build, ship, and run applications. If you’re working with Ubuntu and want to get started with containerization, this comprehensive guide will walk you through every step of installing Docker, configuring it properly, and running your first containers.

What Is Docker and Why Should You Use It?

Docker is an open-source platform that enables developers to package applications and their dependencies into lightweight, portable containers. Unlike traditional virtual machines, containers share the host operating system’s kernel, making them significantly faster to start and more efficient with system resources.

Here’s why Docker has become an essential tool for developers and system administrators:

  • Consistency: Docker ensures your application runs the same way in development, testing, and production environments. No more “it works on my machine” problems.
  • Isolation: Each container runs in its own isolated environment, preventing conflicts between applications and their dependencies.
  • Portability: Docker containers can run on any system that supports Docker, whether it’s your laptop, a cloud server, or a Raspberry Pi.
  • Efficiency: Containers are lightweight and share the host OS kernel, using far fewer resources than traditional virtual machines.
  • Scalability: Docker makes it easy to scale applications horizontally by spinning up additional containers as needed.
  • Version Control: Docker images can be versioned and stored in registries, making it easy to roll back to previous versions if something goes wrong.

Prerequisites

Before you begin, make sure you have:

  • Ubuntu 22.04 (Jammy Jellyfish) or Ubuntu 24.04 (Noble Numbat) — either desktop or server edition
  • A user account with sudo privileges
  • A stable internet connection for downloading packages
  • At least 4 GB of RAM and 20 GB of free disk space (recommended)

You should also be comfortable using the terminal, as all installation steps are performed via the command line.

Step 1: Remove Old Docker Versions

Before installing Docker CE (Community Edition), it’s important to remove any older versions that might already be installed on your system. Older versions were sometimes called docker, docker.io, or docker-engine.

sudo apt-get remove docker docker-engine docker.io containerd runc

Don’t worry if this command reports that none of these packages are installed — that just means you’re starting fresh.

Step 2: Update Your System

Always start by updating your package index and upgrading existing packages to their latest versions:

sudo apt-get update
sudo apt-get upgrade -y

Step 3: Install Required Dependencies

Docker requires a few packages to allow apt to use repositories over HTTPS:

sudo apt-get install -y \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

Step 4: Add Docker’s Official GPG Key

To ensure the integrity of the packages you download, add Docker’s official GPG key:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

Step 5: Set Up the Docker Repository

Add the Docker repository to your system’s software sources:

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

Update the package index again to include Docker’s repository:

sudo apt-get update

Step 6: Install Docker CE

Now install Docker Community Edition along with the Docker CLI, containerd, and Docker plugins:

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

This installs the latest stable version of Docker. The installation process will also start the Docker daemon automatically.

Step 7: Post-Installation Steps

Add Your User to the Docker Group

By default, Docker commands require sudo privileges. To run Docker commands without sudo, add your user to the docker group:

sudo usermod -aG docker $USER

Important: You need to log out and log back in for this change to take effect. Alternatively, you can use the following command to apply the changes immediately in your current session:

newgrp docker

Enable Docker to Start on Boot

Docker should start automatically on boot, but you can verify and enable this with:

sudo systemctl enable docker
sudo systemctl enable containerd

Check Docker Service Status

Verify that the Docker service is running:

sudo systemctl status docker

You should see output indicating that the Docker service is active (running).

Step 8: Verify Your Installation

The best way to verify Docker is working correctly is to run the hello-world container:

docker run hello-world

If everything is set up correctly, you’ll see a message confirming that Docker is installed and working. This command downloads a test image from Docker Hub, creates a container from it, runs it, and displays a confirmation message.

You can also check the installed Docker version:

docker version

And get detailed system information:

docker info

Installing Docker Compose

Docker Compose is a tool for defining and running multi-container Docker applications. With the docker-compose-plugin package installed in Step 6, you already have Docker Compose v2 available as a Docker plugin.

Verify the installation:

docker compose version

If you need the standalone docker-compose command (v1 compatibility), you can install it separately:

sudo apt-get install docker-compose-plugin

With Docker Compose v2, you use docker compose (with a space) instead of the older docker-compose (with a hyphen).

Example Docker Compose File

Here’s a simple docker-compose.yml file that runs a web server with a database:

version: '3.8'
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secretpassword
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Run it with:

docker compose up -d

Essential Docker Commands

Here are the most important Docker commands you’ll use regularly:

Container Management

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

# List running containers
docker ps

# List all containers (including stopped)
docker ps -a

# Stop a container
docker stop my-nginx

# Start a stopped container
docker start my-nginx

# Restart a container
docker restart my-nginx

# Remove a stopped container
docker rm my-nginx

# Force remove a running container
docker rm -f my-nginx

# View container logs
docker logs my-nginx

# Execute a command inside a running container
docker exec -it my-nginx /bin/sh

Image Management

# Pull an image from Docker Hub
docker pull ubuntu:24.04

# List downloaded images
docker images

# Remove an image
docker rmi ubuntu:24.04

# Remove all unused images
docker image prune -a

# Search for images on Docker Hub
docker search nginx

System Cleanup

# Remove all stopped containers, unused networks, and dangling images
docker system prune

# Remove everything including unused volumes
docker system prune -a --volumes

# Check disk usage
docker system df

Creating Your First Dockerfile

A Dockerfile is a text file that contains instructions for building a Docker image. Let’s create a simple Node.js application container.

First, create a project directory:

mkdir my-docker-app && cd my-docker-app

Create a simple app.js file:

cat > app.js << 'EOF'
const http = require('http');
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello from Docker!\n');
});

server.listen(port, '0.0.0.0', () => {
  console.log(`Server running at http://0.0.0.0:${port}/`);
});
EOF

Now create the Dockerfile:

# Use the official Node.js 22 Alpine image as the base
FROM node:22-alpine

# Set the working directory inside the container
WORKDIR /app

# Copy application files
COPY app.js .

# Expose port 3000
EXPOSE 3000

# Define the command to run the application
CMD ["node", "app.js"]

Build the image:

docker build -t my-node-app .

Run a container from your image:

docker run -d --name my-app -p 3000:3000 my-node-app

Visit http://localhost:3000 in your browser to see your application running inside a Docker container!

Useful Tips and Best Practices

1. Use Official Images

Always start with official Docker Hub images when possible. They’re maintained, regularly updated, and scanned for vulnerabilities.

2. Use Alpine-Based Images

Alpine Linux images are much smaller than their Ubuntu or Debian counterparts. For example, node:22-alpine is roughly 50 MB compared to node:22 at over 300 MB.

3. Use .dockerignore

Create a .dockerignore file in your project to exclude unnecessary files from the build context, similar to .gitignore:

node_modules
.git
.env
*.md
docker-compose*.yml

4. Don’t Run as Root

For security, create a non-root user in your Dockerfile:

RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

5. Use Multi-Stage Builds

Multi-stage builds help keep your final image small by separating build dependencies from runtime dependencies:

# Build stage
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# Production stage
FROM node:22-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
CMD ["node", "app.js"]

6. Keep Layers Minimal

Combine related commands into single RUN instructions to reduce the number of image layers:

RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    rm -rf /var/lib/apt/lists/*

7. Tag Your Images

Always tag your images with meaningful version numbers instead of relying on the latest tag:

docker build -t my-app:1.0.0 .
docker build -t my-app:1.0.1 .

8. Use Docker Volumes for Persistent Data

Never store important data inside a container. Use volumes to persist data:

docker volume create my-data
docker run -v my-data:/app/data my-app

Troubleshooting Common Issues

Permission denied errors: Make sure your user is in the docker group and you’ve logged out and back in.

Cannot connect to Docker daemon: Ensure the Docker service is running with sudo systemctl start docker.

Port already in use: Check if another service is using the port with sudo lsof -i :PORT and either stop it or use a different port mapping.

Disk space issues: Run docker system prune -a to clean up unused images, containers, and volumes.

Conclusion and Next Steps

You’ve successfully installed Docker on Ubuntu, learned the essential commands, and created your first Dockerfile. Docker is a powerful tool that opens up a world of possibilities for development and deployment workflows.

Here are some recommended next steps to continue your Docker journey:

  1. Explore Docker Hub — Browse the vast library of official and community images
  2. Learn Docker Compose — Master multi-container applications for more complex setups
  3. Study Docker networking — Understand bridge, host, and overlay networks
  4. Try Docker Swarm or Kubernetes — Scale your containers across multiple machines
  5. Set up a CI/CD pipeline — Automate building and deploying Docker images with GitHub Actions
  6. Learn about container security — Implement best practices for securing your containers

Docker is an essential skill for modern software development, and the fundamentals you’ve learned here will serve as a solid foundation for building and deploying containerized applications. Happy containerizing!

Suresh

Written by Suresh

A passionate technology enthusiast, blogger, and self-taught developer. I write about Linux, Open Source, Cloud Computing, and emerging technologies to help students and beginners learn tech for free.