Install Docker and Docker Compose on Linux
Docker lets you run applications in isolated containers. Docker Compose lets you manage multiple containers at once — for example a web app, a database, and a cache — using a single file and a single command.
This guide covers installation on Ubuntu and Debian, fixing permissions so you don’t need to type sudo every time, and setting up a clean folder structure for your containers.
Requirements
- Ubuntu 20.04+ or Debian 11+
- A user account with sudo privileges
- An internet connection
Step 1 – Install Docker Engine
Add Docker’s official repository and install:
# Update and install dependencies
sudo apt update
sudo apt install -y ca-certificates curl gnupg
# 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
# Add Docker's repository
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
# Install Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginubuntu with debian in the repository URL above.Step 2 – Verify the Installation
docker --version
docker compose versionYou should see something like:
Docker version 26.x.x
Docker Compose version v2.x.xStep 3 – Fix Permissions (No More sudo)
By default, Docker requires root privileges. Add your user to the docker group to fix this:
sudo usermod -aG docker $USER
newgrp dockerVerify it works without sudo:
docker run hello-worldIf you see a welcome message without any errors — you’re all set.
Step 4 – Organize Your Containers
A clean folder structure makes managing many containers much easier, especially as your lab grows.
Recommended structure:
~/docker/
├── nginx/
│ ├── compose.yml
│ └── config/
├── nextcloud/
│ ├── compose.yml
│ └── data/
├── monitoring/
│ ├── compose.yml
│ └── prometheus.yml
└── databases/
├── compose.yml
└── init/Each service gets its own folder with its own compose.yml. This means you can start, stop, and manage each service independently without affecting the others.
Step 5 – Example compose.yml
Here is a simple example running Nginx:
# ~/docker/nginx/compose.yml
services:
nginx:
image: nginx:latest
container_name: my-nginx
ports:
- "8080:80"
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf:ro
- ./html:/usr/share/nginx/html:ro
restart: unless-stoppedStart the service:
cd ~/docker/nginx
docker compose up -dUseful Commands
| Command | What it does |
|---|---|
docker compose up -d |
Start containers in the background |
docker compose down |
Stop and remove containers |
docker compose restart |
Restart containers |
docker compose logs -f |
Follow live logs |
docker compose pull |
Pull the latest image |
docker ps |
List running containers |
docker ps -a |
List all containers including stopped |
docker stats |
Real-time CPU and memory usage |
docker system prune |
Clean up unused resources |
Tips
Use named volumes for persistent data:
volumes:
db-data:
services:
postgres:
image: postgres:16
volumes:
- db-data:/var/lib/postgresql/dataStore sensitive values in a .env file:
# ~/docker/databases/.env
POSTGRES_PASSWORD=yourpassword
POSTGRES_USER=admin# compose.yml reads .env automatically
services:
postgres:
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_USER: ${POSTGRES_USER}Add .env to .gitignore if you use Git — never push passwords to a repository.
Related Links
- Docker Documentation — official Docker docs
- Docker Compose Reference — full compose.yml reference
- Docker Hub — browse official container images