
Editorial illustration generated for this article.
Setting up a local PHP and CMS development environment directly on your host machine can lead to dependency conflicts, mismatched PHP extensions and services that are difficult to maintain. Docker and Docker Compose solve much of this problem by packaging the web server, PHP runtime and MySQL database into isolated containers.
This guide walks through a local Drupal installation connected to MySQL with Docker Compose.
Prerequisites
Install Docker Desktop or Docker Engine on Linux, Docker Compose, and a terminal. Verify the installation:
docker --version
docker compose version
Step 1: Create the project directory
Create a dedicated directory for the project:
mkdir drupal-docker-local
cd drupal-docker-local
The Compose file below uses named volumes, so Docker manages persistent storage for the database and Drupal files.
Step 2: Create docker-compose.yml
Create docker-compose.yml in the project root:
services:
database:
image: mysql:8.0
container_name: drupal_mysql
restart: unless-stopped
environment:
MYSQL_DATABASE: drupal_db
MYSQL_USER: drupal_user
MYSQL_PASSWORD: drupal_password
MYSQL_ROOT_PASSWORD: root_secret_password
volumes:
- db_data:/var/lib/mysql
networks:
- drupal_network
drupal:
image: drupal:10-apache
container_name: drupal_web
restart: unless-stopped
depends_on:
- database
ports:
- "8080:80"
volumes:
- drupal_data:/var/www/html
networks:
- drupal_network
volumes:
drupal_data:
db_data:
networks:
drupal_network:
driver: bridge
The database service runs MySQL 8.0, while drupal runs Drupal with Apache and maps host port 8080 to container port 80. Both services share drupal_network, so they can find each other by service name. Named volumes preserve the database and Drupal files when containers are recreated.
These credentials are suitable only for a local example. Replace them and keep secrets out of source control for a shared or production-like environment.
Step 3: Launch and verify the containers
Start both services in the background:
docker compose up -d
docker compose ps
You should see drupal_web and drupal_mysql running. To inspect MySQL startup:
docker compose logs -f database
Press Ctrl + C to stop following the logs; this does not stop the container.
Step 4: Understand the Docker database hostname
On a native installation, an application often connects to MySQL through localhost or 127.0.0.1. That assumption is wrong from inside the Drupal container: each container has its own network namespace and loopback address.
Because both services share drupal_network, Docker’s internal DNS resolves the MySQL service by its Compose name. Drupal should therefore use:
database
The internal MySQL port remains 3306. The 8080:80 mapping is for your browser, not for Drupal’s database connection.
Step 5: Complete the Drupal installation
Open http://localhost:8080 and follow the installer:
- Choose a language and select Save and continue.
- Select the Standard installation profile.
- Choose MySQL, MariaDB, Percona Server, or equivalent.
- Under Advanced Options, enter:
- Database name: drupal_db
- Database username: drupal_user
- Database password: drupal_password
- Host: database
- Port: 3306
- Select Save and continue so Drupal can create its schema.
- Enter the site name, administrator email, username and password.
Do not use localhost or 127.0.0.1 for the database host. After the installer finishes, Drupal redirects you to the new site dashboard.
Useful maintenance commands
# Stop containers without removing data
docker compose stop
# Start stopped containers
docker compose start
# Remove containers but keep named volumes
docker compose down
# Follow Drupal logs
docker compose logs -f drupal
# Open a shell inside the Drupal container
docker compose exec drupal bash
To remove the containers and named volumes, use this only when you intentionally want to delete the local database and Drupal files:
docker compose down -v
Conclusion
Docker Compose gives Drupal and MySQL a repeatable local environment without installing every dependency directly on the host. The most important networking detail is simple: from Drupal, use the Compose service name database, not localhost.
Once the setup works, commit the Compose file and document the required commands for the team. That small investment makes onboarding, troubleshooting and rebuilding the local environment much easier.