Applies to: the Docker Compose plugin (docker compose, v5.5 with Docker Engine 29.8) on Ubuntu, Debian, AlmaLinux and Rocky Linux
Docker Compose starts and connects several containers from one file, compose.yaml. Instead of long docker run commands, you describe your app once and start everything with one command. We tested the example below with Docker Compose v5.5.1 on Docker Engine 29.8.1.
Install
Current Docker packages include Compose as a plugin: check with docker compose version. Note the space: docker-compose with a dash is the old standalone command. To install Docker with the plugin, see install Docker on Debian and Ubuntu.
A first compose.yaml
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
restart: unless-stopped
mkdir html && echo "hello from compose" > html/index.html docker compose up -d curl http://localhost:8080
That printed hello from compose in our test.
Everyday commands
docker compose ps # what is running docker compose logs -f web # follow a service's log docker compose pull # download newer images docker compose up -d # apply changes and restart what changed docker compose restart web docker compose down # stop and remove the containers (volumes stay)
Run them in the folder that contains compose.yaml.
An app with a database
services:
app:
image: ghcr.io/example/app:latest
environment:
DB_HOST: db
DB_PASSWORD: ${DB_PASSWORD}
depends_on:
- db
db:
image: mariadb:11.4
environment:
MARIADB_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/mysql
volumes:
db-data:
Services reach each other by service name (db). Put secrets in a .env file next to compose.yaml (DB_PASSWORD=...) and keep it out of version control. Named volumes such as db-data keep data when containers are recreated; back them up.
A real example: install n8n with Docker Compose and HTTPS. Need a server for containers? A KVM VPS runs Docker with full root access.
