If you’re looking to streamline the process of setting up an Apache, MariaDB, and PHP environment for your web development projects, you’re in the right place.
Docker Compose provides a convenient way to define and manage multi-container applications, allowing you to create, configure, and deploy your LAMP stack in minutes.
However, suppose you still prefer to take the traditional approach and install the LAMP stack from the native packages for the distro you are using. In that case, our tutorials for Ubuntu, Debian, Rocky Linux, and AlmaLinux will help you do it effortlessly.
By the end of this guide, you’ll have a fully functional LAMP stack running in a Docker environment, ready to power your web applications.
You’ll also gain a solid understanding of Docker Compose and its capabilities, empowering you to manage your containerized applications in the future efficiently. So let’s dive in!
Prerequisites
Of course, having Docker and Docker Compose installed is required to deploy a containerized LAMP stack. So, if you donโt already have Docker installed, any of the following guides may be helpful:
- How to Install Docker on Ubuntu 22.04
- How to Install Docker on Debian 11 (Bullseye)
- How to Install Docker on AlmaLinux / Rocky Linux
- How to Install Docker on Fedora
- How to Install Docker on Raspberry Pi
The other essential component is Docker Compose. Remember, it is provided separately from Docker. Therefore, you must Install Docker before adding Docker Compose; otherwise, Compose will not function.
Installing it is pretty simple, even if it is not already on your Linux system. Type the following two commands:
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-linux-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
Code language: JavaScript (javascript)
Create Project’s Structure
Docker Compose allows you to build and run stacks of multiple containers. In other words, it is a tool for defining and running multi-container Docker applications.
To use it, you must first create a โdocker-compose.ymlโ file that configures the containers for your application. Then, you can use a single command such as โdocker-compose up -d
โ to start all the containers and link them together.
Let’s create the directory structure to house the files required to set up Apache, MariaDB, PHP, and phpMyAdmin with Docker Compose. The final version should look like the one shown below, and below we’ll explain what each file and directory represents.
We use an arbitrary name for the main directory, such as โlamp.โ It will store all the files required for the setup, so letโs create it.
mkdir lamp
Then we make three subdirectories inside it: โapache_docker,โ “php_docker,” and โwww.โ
mkdir lamp/{apache_docker,php_docker,www}
- The “apache_docker” directory contains the file (Dockerfile) which builds the Apache container, as well as the additional configuration for the Apache server (“apache-vhost.conf“), providing the integration of the web server with PHP and adding a virtual host.
- The “php_docker” directory contains the file “Dockerfile,” which builds the PHP container and adds additional modules.
- Finally, the “www” directory is intended to store the PHP scripts that the application we are developing is expected to execute.
It is important to note that we chose all these directory names arbitrarily. But, of course, you are free to use different ones.
Set Up Apache, MariaDB, PHP, and phpMyAdmin with Docker Compose
It’s time to create our deployment file describing all the services in our containerized LAMP stack. First, create a file named “docker-compose.yaml” inside the “lamp” directory with your preferred text editor:
cd lamp
vim docker-compose.yaml
Code language: CSS (css)
Add the following content to it:
version: "3.8"
services:
# PHP Service
php:
build: './php_docker/'
volumes:
- ./www/:/var/www/html/
# Apache Service
apache:
build: './apache_docker/'
depends_on:
- php
ports:
- "80:80"
volumes:
- ./www/:/var/www/html/
# MariaDB Service
mariadb:
image: mariadb:10.11
environment:
MYSQL_ROOT_PASSWORD: your_password
volumes:
- mysqldata:/var/lib/mysql
# phpMyAdmin Service
phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
ports:
- 8080:80
environment:
PMA_HOST: mariadb
depends_on:
- mariadb
# Volumes
volumes:
mysqldata:
Code language: PHP (php)
Save and close the file. Donโt be worried if something in its contents is unclear to you. Weโll go through it in more detail below.
PHP Service
Weโll begin with PHP, the first service in our โdocker-compose.yamlโ file. The key point here is the โbuildโ directive, which points to the โphp_dockerโ directory, where the default “Dockerfile” is located.
As you can see, there is no path to a Docker image here. This is because we will be building our own, the instructions for which can be found in the โDockerfileโ file.
You may be asking why we need to build our own Docker image for PHP instead of using one already available on Docker Hub. The answer is simple: the official image includes limited preinstalled PHP extensions. Unfortunately, they are, in most cases, insufficient for the applications we aim to develop.
Therefore, we will create a new Docker image based on the official PHP 8.2 one, but additionally, we will compile and include some of the most often-used PHP extensions, such as MySQL, GD, ZIP, XML, and so on.
So, create a file named โDockerfileโ inside the โphp_dockerโ directory with your preferred text editor and add the following content to it:
vim php_docker/Dockerfile
FROM php:8.2-fpm
# Installing dependencies for building the PHP modules
RUN apt update && \
apt install -y zip libzip-dev libpng-dev libicu-dev libxml2-dev
# Installing additional PHP modules
RUN docker-php-ext-install mysqli pdo pdo_mysql gd zip intl xml
# Cleaning APT cache
RUN apt clean
Code language: PHP (php)
Save and close the file. Of course, as you guessed, if you need more PHP extensions, you can include them in the file.
The “volumes” directive from the “php” service part in “docker-compose.yaml” specifies where the app’s PHP files are. As you know, Docker containers are temporary, and any data are expected to be lost when the container is deleted. Fortunately, the Docker volumes provide a mechanism to persist data created inside a container.
So, our local “www” directory points to “/var/www/html” inside the PHP container, where PHP will look for executable PHP scripts. In other words, we map a folder on the host filesystem (outside of the container context) to within the running container.
Next, let’s create an โindex.phpโ file into it, which will just be used for testing.
vim www/index.php
Add the single line shown below, then save and exit the file.
<?php phpinfo(); ?>
Code language: HTML, XML (xml)
The โdepends_onโ directive instructs our PHP container to wait until the MariaDB service has been started. We do this because we expect PHP to try to connect to the database; thus, it must first be operational.
Apache Service
Things are similar here. We use the most recent Docker image and expose the containerโs port 80 to port 80 of our local Linux system.
Let’s first create our “apache-vhost.conf” file, which sets the root directory containing the PHP files for our application to be the container “/var/www/html,” which, as we already know, we have mapped to our local one “www.”
In addition, we load the modules we need in Apache so that the web server can proxy the requests, in this case, to the PHP container.
So, inside the โapache_dockerโ directory, create a file named โapache-vhost.confโ and paste the following content into it:
vim apache_docker/apache-vhost.conf
ServerName localhost
LoadModule deflate_module /usr/local/apache2/modules/mod_deflate.so
LoadModule proxy_module /usr/local/apache2/modules/mod_proxy.so
LoadModule proxy_fcgi_module /usr/local/apache2/modules/mod_proxy_fcgi.so
<VirtualHost *:80>
# Proxy .php requests to port 9000 of the PHP container
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php:9000/var/www/html/$1
DocumentRoot /var/www/html/
<Directory /var/www/html/>
DirectoryIndex index.php
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# Send Apache logs to stdout and stderr
CustomLog /proc/self/fd/1 common
ErrorLog /proc/self/fd/2
</VirtualHost>
Code language: PHP (php)
Save and exit the file.
Now, again inside the “apache_docker” directory, let’s create the “Docker” file that will build our Apache image and import into it the “apache-vhost.conf” file we just created.
vim apache_docker/Dockerfile
FROM httpd:2.4-alpine
RUN apk update; apk upgrade;
# Copy Apache virtual host file to proxy .php requests to PHP container
COPY apache-vhost.conf /usr/local/apache2/conf/apache-vhost.conf
RUN echo "Include /usr/local/apache2/conf/apache-vhost.conf" \
>> /usr/local/apache2/conf/httpd.conf
Code language: PHP (php)
Again, save and exit the file.
MariaDB Service
Our MariaDB serverโs Docker Compose configuration is simple. All that needs to be done is replace the โMYSQL_ROOT_PASSWORDโ directive, โyour_password,โ with the one you choose. As the name implies, this is the password for the MariaDB root account.
The โvolumesโ directive ensures that we will not lose the data in our database during container restarts. Thatโs all we need for our MariaDB container.
phpMyAdmin Service
The final container in our Docker Compose deployment is phpMyAdmin. Since it is not required for the LAMP stack to function, it dramatically simplifies MariaDB administration, which is why we include it in our deployment.
We specify phpMyAdmin to be accessible on port 8080 because we have already exposed port 80 to the Apache container on our local Linux system.
The โPMA_HOST: mariadbโ directive tells the phpMyAdmin container which database to connect to, in this case, our MariaDB container.
Start and Run the LAMP Stack with Docker Compose
Finally, we can run Apache, MariaDB, PHP, and phpMyAdmin using Docker Compose. To do this, execute the below-given command from the “lamp” directory where our “docker-compose.yaml” file is located.
Start and run the containers in the background:
docker-compose up -d
The images will start downloading, and the PHP and Apache Docker images will be built during the process.
The entire procedure will take a few minutes, depending on your internet connection speed. In the end, you should see a screen similar to the one below, informing you that all containers have been successfully started.
The initial delay of the containers’ start will only be the first time because Docker must download images from the Internet and then build some of them. After that, all subsequent runs will take seconds since they will be already available locally on your Linux system.
Finally, you can open your browser and navigate to “http://localhost.” The โindex.phpโ file we prepared in the โwwwโ directory will greet you.
You can also reach your containerized phpMyAdmin instance at “http://localhost:8080” and use the username “root” and password that you set in the “docker-compose.yaml” file to connect to and manage the MariaDB server.
It’s time to congratulate yourself on a well-done job! So let’s quickly walk through the essential Docker Compose commands for managing your containerized LAMP stack.
Basic Docker Compose Commands
The basic Docker Compose commands you can use in practice are shown below with examples. Remember to execute them from the directory containing the โdocker-compose.yamlโ file.
To view a list of all the containers that are currently running in your LAMP deployment, type:
docker-compose ps
To stop all docker containers that are running in the background, use the command as shown below:
docker-compose stop
Of course, you can stop just one of the containers in your LAMP stack rather than all of them. Run โdocker-compose stopโ followed by the service name to do so. Notice not the container name but the service name!
For example, to stop the Apache container, execute the following:
docker-compose stop apache
Similarly, you can rerun it later by executing โdocker-compose start apache.โ
Similarly, from your project directory (โlampโ), type the command below to start up your application:
docker-compose start
The “docker-compose logs” command displays log output from services. For example, to view the Apache container logs:
docker-compose logs apache
Additionally, if you want to aggregate the logs of every container in your LAMP stack and track whatโs happening in them in real-time, type:
docker-compose logs -f
The following command stops and removes containers and networks created by the โdocker-compose up -dโ command:
docker-compose down
Additionally, if you want to stop and remove containers as well as their associated Docker images, use the following command:
docker-compose down --rmi all
In addition, if you want an in-depth introduction to Docker Compose, check out our comprehensive guide.
Conclusion
Congratulations! You have mastered quickly deploying Apache, MariaDB, and PHP using Docker Compose. With the knowledge and skills you have gained from our guide, you are well-equipped to streamline your web development workflow and accelerate your project deployment process.
The benefits of using Docker Compose for your LAMP stack deployment are numerous. First, it provides isolation and portability, ensuring your applications run consistently across different environments.
It also enables scalability and easy scaling of individual services within your stack, allowing you to handle increased traffic and demand seamlessly. Furthermore, the modular nature of Docker Compose makes it effortless to add or remove services from your stack as your application evolves.
However, if you decide to go with Nginx instead of Apache and choose the LEMP (Nginx, Apache, MySQL/MariaDB) stack, we’ve got you covered in our detailed guide.
We hope our guide has been valuable in demystifying deploying a LAMP stack using Docker Compose. Now, armed with this knowledge, you can confidently embark on your projects and easily deploy your applications.
Happy coding and happy deploying!