Deep Dive on Docker Compose – Deploying WordPress

Bits Lovers
Written by Bits Lovers on
Deep Dive on Docker Compose – Deploying WordPress

Let’s talk about running multiple Docker containers together. Specifically, I’ll show you how to spin up a WordPress site with a database backing it, using Docker Compose.

If you’ve worked with Docker before, you know you can manage individual containers through the command line. It works fine for one or two containers. But once you have several services talking to each other, running them separately gets old fast. You’d need to remember the right flags for each container, start them in the correct order, and keep track of networking between them. That’s the problem Compose tries to solve.

How Docker Compose Works

Docker Compose lets you describe an entire application stack in a single YAML file. Instead of running a long docker command with a dozen flags, you write the configuration once and let Compose handle the rest.

Here’s a quick example of what a typical application might look like:

Back end (API)
CMS (WordPress)
Web front-end
Database
Machine Learning Tasks
Logging
Reverse Proxy

Each of these would be its own container. Compose lets you define them all in one place and bring them up or tear them down together.

A Bit of History

Docker Compose started as an open-source project called Orchard, built by a company of the same name. Docker acquired Orchard in 2014 and eventually folded the tool into the official Docker ecosystem. The original version was written in Python and ran as a standalone binary. These days, docker compose (as a Docker CLI plugin) is the standard approach, though you’ll still see docker-compose (the hyphenated version) in older tutorials and documentation.

Installing Compose

If you have Docker Desktop, you’re already set. Compose comes bundled with it.

On Linux, you might need to install it separately. Grab the binary from the GitHub releases page:


curl -SL https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose

Make it executable:


chmod +x /usr/local/bin/docker-compose

To verify:


docker compose version

You should see something like Docker Compose version v2.24.0 or later.

Compose Files

Compose uses YAML files to define services. The default filename is docker-compose.yml, and if you use that name, you don’t need to specify it when running commands. If you use a different name, pass it with the -f flag.

The file structure has a few key sections at the root level:

version
services
volumes

The version key refers to the Compose file format itself, not to Docker Compose or Docker Engine versions. Check the official documentation if you need to verify compatibility between file format versions and your Docker installation.

Deploying WordPress with Docker Compose

Here’s a complete example. Create a file called docker-compose.yml with this content:


version: '3.9'

services:

  wordpress:
    image: wordpress
    restart: always
    ports:
      - 80:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - ./volumes/wp:/var/www/html

  db:
    image: mysql:8.0
    restart: always
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_ROOT_PASSWORD: '1'
    volumes:
      - ./volumes/db:/var/lib/mysql

Then create the directories for persistent storage:

mkdir -p volumes/wp volumes/db

A few things to notice here. The services section defines each container. I called them wordpress and db, but you can name them whatever makes sense. Those names become part of the container names, so Docker Compose will create containers called something like app_wordpress_1 and app_db_1 (the prefix comes from your project directory name).

The wordpress service uses the official WordPress image, which already includes Apache and PHP. The db service runs MySQL. Both have restart: always set, which means Docker will restart them if they crash or if you reboot the host.

Data persistence works through the volumes section. Even if you delete the containers, the data in ./volumes/wp and ./volumes/db stays on your host. This matters when you update container versions or recreate them.

Starting WordPress

From the directory where you saved docker-compose.yml, run:


docker compose up -d

The -d flag runs everything in the background so you get your terminal back.

Give it a minute. WordPress needs to initialize its database and start Apache. Once it’s ready, open your browser and go to http://localhost:80. You should see the WordPress setup screen.

Checking What’s Running

To see your active containers:


docker ps

You’ll see something like:

CONTAINER ID   IMAGE       COMMAND                  CREATED       STATUS      PORTS                               NAMES
45eb5c635989   wordpress   "docker-entrypoint.s…"   3 weeks ago   Up 5 days   0.0.0.0:80->80/tcp, :::80->80/tcp   app_wordpress_1
9c2028941a97   mysql:8.0   "docker-entrypoint.s…"   3 weeks ago   Up 5 days   3306/tcp, 33060/tcp                 app_db_1

To see processes running inside the containers:


docker compose top

This shows PID numbers from the Docker host perspective, not from inside the containers.

Managing the Stack

Here are the commands you’ll use most often.

Stop everything without deleting containers:


docker compose stop

Containers stop, but volumes and images stay. You can start again with docker compose start or docker compose restart.

Remove stopped containers and networks:


docker compose rm

This doesn’t touch volumes or images.

Stop and remove everything (containers, networks), but keep volumes:


docker compose down

To also remove volumes (this deletes your data):


docker compose down -v

Restart after changes:


docker compose restart

If you’ve edited the Compose file and want to apply those changes, use docker compose up -d again. For new containers or changes to image versions, you may need to run docker compose down followed by docker compose up -d.

What About the Port Mapping?

The ports section maps host ports to container ports. In our example, - 80:80 means traffic sent to port 80 on your host goes to port 80 inside the container. WordPress inside the container listens on port 80, so this makes sense.

If port 80 on your host was already in use, you could change it to something like - 8080:80 and access WordPress at http://localhost:8080.

A Note on MySQL Versions

This post originally used mysql:5.7. That version reached end of life in October 2023, so I switched the example to mysql:8.0 which is current. If you’re working with older applications that need MySQL 5.7, you can still use the old image, but be aware it’s not getting security updates anymore.

Where Docker Stores Data by Default

When you don’t specify a host path for a volume, Docker stores it in the default location. On Linux, that’s /var/lib/docker/volumes. Each named volume gets its own folder there. You can check with:


docker volume ls

Final Thoughts

Docker Compose isn’t complicated once you get past the YAML structure. The workflow I’ve described here covers the basics: defining services, persisting data, and managing the application lifecycle.

The real value shows up when you start adding more services. A typical web application might have a reverse proxy, a caching layer, a database, and multiple backend services. With all of them in one Compose file, you can bring everything up with a single command and know the dependencies are handled correctly.

Keep your Compose files in version control. They’re a form of documentation, and they make it much easier to recreate your environment on another machine or for a new team member.

Bits Lovers

Bits Lovers

Professional writer and blogger. Focus on Cloud Computing.

Comments

comments powered by Disqus