Skip to content

✨ Local Docker environment with Apache, PHP and MySQL. Perfect for classic PHP projects, allows you to quickly launch a complete setup without local dependencies. Supports persistent volumes, custom configurations and .htaccess files. Great alternative to MAMP/XAMP.

Notifications You must be signed in to change notification settings

Areasettantotto/docker-apache-php-mysql

Repository files navigation

docker-apache-php-mysql — development starter

This repository is a minimal example to get a PHP + Apache + MariaDB (MySQL-compatible) development stack running with Docker Compose. It's intended for local development, demos, or as a starting point for small projects.

This README documents the project structure, how to run the stack, database initialization behavior, and tips for debugging (Composer, Xdebug, phpMyAdmin).

Project structure (quick analysis)

  • Dockerfile — builds the PHP/Apache image. It installs common PHP extensions, Composer and Xdebug (via PECL) during the image build.
  • docker-compose.yml — defines three main services:
    • apache: the PHP+Apache webserver container, mounts the project into /var/www/html.
    • db: MariaDB server, uses a named volume db-data for persistence and mounts ./mysql to /docker-entrypoint-initdb.d for initialization scripts.
    • phpmyadmin: optional phpMyAdmin service to manage the database from the browser.
  • mysql/ — place one or more .sql files here (for example dump.sql) to be automatically executed on the first initialization of the DB volume.
  • config/ — lightweight PHP config: env.php loads .env into $_ENV, db.php creates a PDO connection.
  • php.ini — runtime PHP configuration copied into the container.
  • logs/ — recommended to contain php_errors.log so PHP can write runtime errors to a persisted file.
  • .env.example — example environment variables; copy to .env and edit for local values.

Using this repository instead of MAMP

This project can act as a drop-in replacement for MAMP when developing PHP applications locally. Instead of installing Apache/PHP/MySQL on your machine, you run everything in containers. Benefits and caveats:

  • Benefits:

    • Reproducible environment across machines and team members.
    • No global PHP/Apache/MySQL installation required on the host.
    • Easy to change PHP version or add extensions by editing the Dockerfile.
    • Clean teardown: remove volumes to return to a fresh state.
  • Caveats:

    • Containers run in an isolated environment; when you need to connect to services on the host (e.g., MAMP databases), use host.docker.internal on macOS.
    • Port conflicts: ensure APACHE_PORT and PHPMYADMIN_PORT in .env do not collide with locally running services.
    • File permissions may require attention — prefer running Composer as your host user via the --user flag shown earlier.

Quick note: if you prefer to keep using MAMP for the database, set DB_HOST=host.docker.internal and the proper port in .env so the containerized PHP connects to your MAMP database.

Quick start

  1. Copy environment variables:
cp .env.example .env
# edit .env to set any values you need (ports, database name, passwords)
  1. Build and start the stack:
docker compose up -d --build
  1. Visit your app at http://localhost:<APACHE_PORT> (default 8080) and phpMyAdmin at http://localhost:<PHPMYADMIN_PORT> (default 8081).

Notes:

  • If mysql/ contains a SQL dump and the DB volume is empty, MariaDB will automatically run the scripts and import the dump on first startup.
  • If the DB volume already contains data, initialization scripts are skipped. See "Database import" below for re-import options.

Environment variables (.env)

Important variables are included in .env.example. Typical development values:

APACHE_PORT=8080
PHPMYADMIN_PORT=8081
MYSQL_ROOT_PASSWORD=root
MYSQL_DATABASE=my_db
MYSQL_USER=root
MYSQL_PASSWORD=root
DB_HOST=db

Keep .env out of version control (do not commit sensitive values). If you need to ship sample values, update .env.example instead.

Composer

Composer is available inside the PHP container. Run:

docker compose run --rm --user $(id -u):$(id -g) apache composer install

or

docker compose exec apache composer install

Use the first command to ensure installed files are owned by your host user.

Xdebug

Xdebug is installed at image build time. To avoid double-loading the extension, do not include zend_extension=xdebug.so in a mounted ini if the image already enables Xdebug. Recommended approach:

  • Mount a configuration-only file with options (no zend_extension) via docker-compose.
  • Alternatively, remove docker-php-ext-enable xdebug from the Dockerfile and use a mounted ini that includes zend_extension to enable Xdebug only when desired.

Example .docker/xdebug.ini (config-only):

xdebug.mode=develop,debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003

Mount as:

services:
   apache:
      volumes:
         - ./.docker/xdebug.ini:/usr/local/etc/php/conf.d/zz-xdebug.ini:ro

Verify inside the container:

docker compose exec apache php -v
docker compose exec apache php --ri xdebug || true

Database import / initialization

  • Put SQL files (e.g. dump.sql) into the mysql/ folder. On first initialization (empty db-data volume), MariaDB executes all scripts in /docker-entrypoint-initdb.d in alphabetical order.
  • Best practice: prepend the dump with a header to create and select the database explicitly:
CREATE DATABASE IF NOT EXISTS `my_db` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE `my_db`;
  • Non-destructive re-import (recommended for development): run a manual import using docker compose exec:
docker compose exec db mysql -uroot -p"${MYSQL_ROOT_PASSWORD}" -e "DROP DATABASE IF EXISTS my_db; CREATE DATABASE my_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
docker compose exec db bash -lc "mysql -uroot -p\"${MYSQL_ROOT_PASSWORD}\" my_db < /docker-entrypoint-initdb.d/dump.sql"
  • Destructive fresh import: remove the volume then bring the stack up so entrypoint runs init scripts:
docker compose down -v
docker compose up -d --build

phpMyAdmin

phpMyAdmin is included and configured to connect to the db service using credentials from .env. Access it at http://localhost:<PHPMYADMIN_PORT>. Use root credentials from .env to create databases or import dumps via the web UI if desired.

Troubleshooting

  • Dump not imported: likely the db-data volume is not empty. Either remove the volume (destructive) or import manually.
  • Connection refused to external DB (MAMP): ensure host/port are reachable from the container (host.docker.internal on macOS). You may need to add extra_hosts to docker-compose.yml for some Docker setups.
  • "Cannot load Xdebug - it was already loaded": avoid loading the extension twice. Mount only configuration options or change the Dockerfile to enable Xdebug only when the ini is present.

Files of interest (quick map)

  • Dockerfile — builds the PHP image; installs Composer and Xdebug.
  • docker-compose.yml — service definitions, mounts, and the db-data volume.
  • mysql/ — initial SQL scripts/dumps for DB bootstrap.
  • config/env.php — loads .env into PHP runtime.
  • config/db.php — PDO connection wrapper used by the app.
  • php.ini — configuration for PHP runtime.

Next improvements (suggestions)

  • Add a db-init helper service and scripts/import-dump.sh to allow safe, repeatable imports without deleting volumes.
  • Provide an example .docker/xdebug.ini in the repo and add it to .gitignore.
  • Add a small README.local.md with step-by-step developer onboarding.

If you want, I can commit this change now and push it to main.

About

✨ Local Docker environment with Apache, PHP and MySQL. Perfect for classic PHP projects, allows you to quickly launch a complete setup without local dependencies. Supports persistent volumes, custom configurations and .htaccess files. Great alternative to MAMP/XAMP.

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published