Docker lets you run applications in isolated containers, making deployment consistent and reproducible. This guide covers installation on Ubuntu/Debian.
Remove Old Docker Versions
sudo apt remove docker docker-engine docker.io containerd runc 2>/dev/null
Install Docker Engine
Add the Docker Repository
sudo apt update
sudo apt install ca-certificates curl gnupg -y
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
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 docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
Verify Installation
sudo docker run hello-world
Run Docker Without Sudo
sudo usermod -aG docker $USER
newgrp docker
docker run hello-world
Log out and back in for the group change to take full effect.
Essential Docker Commands
| Command | Description |
|---|---|
| docker pull nginx | Download an image |
| docker run -d -p 80:80 nginx | Run a container in the background |
| docker ps | List running containers |
| docker ps -a | List all containers |
| docker stop CONTAINER_ID | Stop a container |
| docker rm CONTAINER_ID | Remove a container |
| docker logs CONTAINER_ID | View container logs |
| docker exec -it CONTAINER_ID bash | Open a shell inside a container |
| docker images | List downloaded images |
| docker system prune -a | Remove all unused data |
Docker Compose
Docker Compose lets you define multi-container applications in a YAML file.
Nginx Example
Create a project directory and a docker-compose.yml:
mkdir ~/nginx-app && cd ~/nginx-app
nano docker-compose.yml
services:
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
restart: unless-stopped
mkdir html
echo "<h1>Hello from Docker!</h1>" > html/index.html
docker compose up -d
WordPress with MySQL Example
services:
db:
image: mysql:8.0
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: wordpress
MYSQL_USER: wpuser
MYSQL_PASSWORD: wppassword
restart: unless-stopped
wordpress:
image: wordpress:latest
depends_on:
- db
ports:
- "80:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: wppassword
volumes:
- wp_data:/var/www/html
restart: unless-stopped
volumes:
db_data:
wp_data:
Start with docker compose up -d and visit your VPS IP in a browser.
Docker Security Best Practices
- Run as non-root inside containers — use
USERdirective in Dockerfiles - Set resource limits to prevent containers from consuming all resources:
deploy: resources: limits: cpus: "1.0" memory: 512M - Use read-only filesystems where possible:
read_only: true - Create custom networks instead of using the default bridge:
networks: frontend: backend: - Enable Docker Content Trust:
export DOCKER_CONTENT_TRUST=1 - Keep images updated:
docker compose pull && docker compose up -d
Logging Configuration
Prevent logs from filling your disk by adding to /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Restart Docker:
sudo systemctl restart docker
Useful Compose Commands
| Command | Description |
|---|---|
| docker compose up -d | Start all services in background |
| docker compose down | Stop and remove all services |
| docker compose logs -f | Follow logs for all services |
| docker compose pull | Pull latest images |
| docker compose restart | Restart all services |