Introduction

I just clean installed my OS, and was gonna setup my development system and thought: might as well make a blog out of it. We're gonna use docker compose on this guide.

Prerequisites

  • Docker
  • Mac / Windows 11 / Linux

Structure

Folder
- docker-compose.yml
- Dockerfile
- yourfiles ...

docker-compose.yml is a config file allows you to define the services, networks, and volumes required to run your application in a declarative way.

Dockerfile is a text document that contains instructions for building a Docker image.

Single Project Example

The directory should look similar to this.

Project1
- docker-compose.yml
- php81.Dockerfile
- index.php
- info.php
...

php81.Dockerfile

FROM php:8.1-apache

ENV APACHE_DOCUMENT_ROOT /var/www/html

RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

RUN docker-php-ext-install \
mysqli pdo_mysql bcmath exif

RUN curl -sSL https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions -o - | sh -s \
gd zip

RUN a2enmod rewrite

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

It means that use docker image php:8.1-apache, edit apache's document root, move the ini-development file to make the php.ini (when hosting use ini-production), install php extensions, enable mod rewrite, install composer.

You can change APACHE_DOCUMENT_ROOT to /var/www/html/public if you're using something like Laravel.

You can add php extensions using docker-php-ext-install or using docker-php-extension-installer if the extension needs dependencies not local to the image. Or just only use the latter.

The example above uses the ones that I use and the common extensions, Modify it to your needs. Some extensions are pre-enabled and it depends on the image so please check phpinfo or php -m.

docker-compose.yml

1version: '3.8'
2
3services:
4  php81:
5    build:
6      context: .
7      dockerfile: php81.Dockerfile
8    extra_hosts:
9      - 'host.docker.internal:host-gateway'
10    ports:
11      - 80:80
12    restart: always
13    volumes:
14      - .:/var/www/html
15    networks:
16      - my_net
17
18  db:
19    image: mysql/mysql-server:8.0
20    command: --default-authentication-plugin=mysql_native_password
21    volumes:
22      - ./mysql:/var/lib/mysql
23    environment:
24        MYSQL_ROOT_HOST: '%'
25        MYSQL_ROOT_PASSWORD: mleopassword
26    ports:
27      - 3306:3306
28    restart: always
29    networks:
30      - my_net
31
32  phpmyadmin:
33    image: phpmyadmin
34    restart: always
35    ports:
36      - 8080:80
37    networks:
38      - my_net
39
40networks:
41  my_net:
42    name: dockernet

It means that make services named php81, db, phpmyadmin that uses the same network. php81 builds using our php81.Dockerfile. db builds using the image mysql/mysql-server:8.0, and so on.

If you are using Windows use backslash (\), and forwardslash (/) when using Linux/Mac. So in Windows it will look something like this C:\project:var/www/html you only need to edit the left side of colon (:), since the right side is the container's.

To Change MYSQL Password, edit MYSQL_ROOT_PASSWORD value.

info.php

<?php
  phpinfo();
>

index.php

<?php
  $host = "host.docker.internal";
  $user = "root";
  $pass = "mleopassword";
  $port = 3306;

  $conn = new mysqli($host, $user, $pass, "", $port);

  if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
  }

  echo "Connected successfully";

  $conn->close();
?>

On terminal run the command docker compose up -d in your project directory

You can access the project in your browser using localhost

Check PHP info localhost/info.php

Access phpMyAdmin using localhost:8080

How to Enable Directory Indexing

If you we're using WAMP or XAMPP before, you might have been used on enabled indexing which they defaulted. So, if you want to enable directory listing follow this.

php81.Dockerfile

1FROM php:8.1-apache
2
3ENV APACHE_DOCUMENT_ROOT /var/www/html
4
5RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
6RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
7RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
8
9RUN sed -i 's/Options -Indexes/Options +Indexes/' /etc/apache2/conf-available/docker-php.conf
10
11RUN docker-php-ext-install \
12mysqli pdo_mysql bcmath exif
13
14RUN curl -sSL https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions -o - | sh -s \
15gd zip
16
17RUN a2enmod rewrite
18
19RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

Edit php81.Dockerfile and add this. This line enables directory indexing.

On your terminal run docker compose up -d --build

Go to your browser localhost to see if it reflect changes (should look like image below)

Docker Apache Mysql PHP Directory Indexing

Multiple PHP Versions

So you are wondering how to do setup multiple versions of php using docker? Just add a new service. (Or make a Dockerfile per project).

The directory should be similar to this.

Projects
- docker-compose.yml
- php81.Dockerfile
- php56.Dockerfile
...

docker-compose.yml

1version: '3.8'
2
3services:
4  php81:
5    build:
6      context: .
7      dockerfile: php81.Dockerfile
8    ports:
9      - 8081:80
10    restart: always
11    volumes:
12      - .:/var/www/html
13    networks:
14      - my_net
15
16  php56:
17    build:
18      context: .
19      dockerfile: php56.Dockerfile
20    ports:
21      - 8056:80
22    restart: always
23    volumes:
24      - .:/var/www/html
25    networks:
26      - my_net
27
28  db:
29    image: mysql/mysql-server:8.0
30    command: --default-authentication-plugin=mysql_native_password
31    volumes:
32      - ./mysql:/var/lib/mysql
33    environment:
34        MYSQL_ROOT_HOST: '%'
35        MYSQL_ROOT_PASSWORD: mleopassword
36    ports:
37      - 3316:3306
38    restart: always
39    networks:
40      - my_net
41
42  phpmyadmin:
43    image: phpmyadmin
44    restart: always
45    ports:
46      - 8082:80
47    networks:
48      - my_net
49
50networks:
51  my_net:
52    name: dockernet

php56.Dockerfile

1FROM php:5.6-apache
2
3ENV APACHE_DOCUMENT_ROOT /var/www/html
4
5RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
6RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
7RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
8
9RUN sed -i 's/Options -Indexes/Options +Indexes/' /etc/apache2/conf-available/docker-php.conf

Run the command docker compose up -d

PHP 8.1 localhost:8081

PHP 5.6 localhost:8056

Final Thoughts

Remember to check ports if you are using many containers. Play with it and learn. GLHF.