Docker is great for running single containers. But real‑world applications often need multiple services – a web server, a database, a cache, and maybe a queue worker. Managing them individually with docker run commands gets messy quickly.

Docker Compose solves this. You define all your services in a single YAML file, then start everything with one command. This guide covers installation and common use cases.

What Is Docker Compose?

Docker Compose is a tool for defining and running multi‑container Docker applications. You write a docker‑compose.yml file that describes your services, networks, and volumes. Then you run docker compose up to start everything.

Compose is useful for:

  • Local development environments
  • Staging and testing setups
  • Small production applications
  • CI/CD pipelines

Step 1: Install Docker

Docker Compose requires Docker. If you don't have Docker installed:

sudo apt update
sudo apt install docker.io -y
sudo systemctl start docker
sudo systemctl enable docker

Add your user to the docker group to run commands without sudo:

sudo usermod -aG docker $USER

Log out and log back in for the changes to take effect.

Step 2: Install Docker Compose

On Ubuntu 24.04, Docker Compose is available in the official repositories:

sudo apt install docker-compose -y

Verify the installation:

docker-compose --version

If you're using a newer system, the plugin version might be installed as docker compose (without the hyphen). Both work.

Step 3: Your First docker‑compose.yml

Create a new directory and a docker‑compose.yml file:

mkdir myapp
cd myapp
nano docker-compose.yml

Add this example that runs a simple web application with Redis:

version: '3.8'

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
    networks:
      - app-network

  redis:
    image: redis:alpine
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

This defines two services: an Nginx web server and a Redis cache. They communicate via the app-network network.

Step 4: Start the Application

Start all services:

docker-compose up -d

The -d flag runs containers in the background (detached mode).

Check the status:

docker-compose ps

You should see both services running. Visit http://your_server_ip:8080 to see the Nginx welcome page.

To stop everything:

docker-compose down

Step 5: Add a Database Service

Here's a more realistic example with MySQL:

version: '3.8'

services:
  wordpress:
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wordpress_data:/var/www/html
    depends_on:
      - db

  db:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
      MYSQL_ROOT_PASSWORD: rootpassword
    volumes:
      - db_data:/var/lib/mysql

volumes:
  wordpress_data:
  db_data:

This launches a full WordPress stack with MySQL. Visit http://your_server_ip:8080 to run the WordPress installer.

Step 6: Common Docker Compose Commands

Start services:

docker-compose up -d

Stop services:

docker-compose stop

Stop and remove containers:

docker-compose down

View logs:

docker-compose logs -f

Run a command in a service:

docker-compose exec web bash

Rebuild services after code changes:

docker-compose up -d --build

Step 7: Use Docker Compose with a Custom Dockerfile

Instead of using pre‑built images, you can build your own:

version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pg_data:/var/lib/postgresql/data

volumes:
  pg_data:

Place a Dockerfile in the same directory, and Compose will build it automatically.

Troubleshooting

Port already in use – Change the host port in the ports section (e.g., "8081:80").

Permission denied – Add your user to the docker group and log out/back in.

Container crashes – Check logs with docker-compose logs SERVICE_NAME.

Volume permission issues – Some containers run as root. Use user: "1000:1000" in the service definition.

Next Steps

Docker Compose simplifies local development and small‑scale deployments. Start with simple stacks, then add services like Redis, Elasticsearch, or queue workers as your needs grow.

For production, consider using Docker Swarm or Kubernetes for orchestration.

Need a VPS to practice on? Check our recommended VPS providers.