"I decided to follow the path of rabbit hole, let's see how far this can take us" - AJ
Sharing, learning and knowing people all around the world. Let's code!
With Docker Compose I'm running three containers, each one with: Nginx, PHP (with composer, xdebug and configs) and MySql.
The purpose of this guide is to give some reference and help, don't feel tied to the same configs.
-
Clone the project [
optional
] -
Makefile [
optional
] -
Setting
php.dockerfile
Before doing anything install all prerequisites.
A simple and a fast way to get this environment.
Commands that maybe you will need use to build this environment.
Where your projects, backup and configs will be.
Automating your environment with a makefile.
Installing xdebug, compose, libs and setting configs.
Setting PHP-FPM for Nginx, generating our SSL certificate and setting it on our server.
Building our images in containers.
This environment was created on windows but all docker things will work on any SO. Just follow install instructions on documentation:
Check if all dependencies is installed by entering the following command's in your terminal:
docker-compose docker -v
[docker-compose
] will print all docker-compose commands and [docker -v
] will print docker version.
Optional tools:
- Git
Make (Chocolatey)
choco install make
Make (Ubuntu)
sudo apt-get -y install make
A simple and a fast way to you get this environment is to clone my project into a directory, open your terminal, navigate into project cloned directory and write some commands:
docker-compose build docker-compose up -d
Check localhost in your browser and voilá
- http -> 80
- https -> 443
- php -> 9000
- mysql -> 3306
Docker have a nice documentation (in my opinion) with all their commands, if what you want is not here, check the link.
docker exec [CONTAINER] nginx -s reload
docker run --rm -v $(pwd)/web/app:/app composer create-project laravel/laravel example-app
docker run --rm -v $(pwd)/web/app:/app composer update
docker-compose exec php php -m
docker-compose exec php php -a
docker exec -it mysql bash mysql -u"$MYSQL_ROOT_USER" -p"$MYSQL_ROOT_PASSWORD"
Before we start to configure our environment we need a directories tree. Here you can choose where your projects, backup's, servers and configs will be.
\---environmentProject | docker-compose.yml | Makefile | nginx.dockerfile | php.dockerfile | README.md | +---confs | +---Mysql_db | | backup.ibd | | | +---servers | | server.conf | | | \---ssl | localhost.crt | localhost.key | \---projects \---www index.php
Instead of typing complexes commands in your terminal, you can use a Makefile to simplifying.
Prerequisite to use a Makefile is to install [make
] command.
With [make
] installed, I don't recommend, but you can clone my repository and use my Makefile with some already defined shortcut commands. If you're going to use it, make sure that your containers are named with the same name as mine and remember, I'm using windows and some commands maybe will not work on another SO.
Command | Description |
---|---|
reload-nginx | Restart Nginx web server |
it-php | Interactive mode on php image |
start-ubuntu | Start a ubuntu:latest image and remove when works done |
gen-ssl | Gen Certificate authority (CA) for your browser and webserver |
start-laravel | Install laravel project via composer |
make help
Pre requisite of this section: make, clone my project and Windows 10 user.
Its time to we build our PHP container with xdebug, composer and configs inside a Dockerfile. Create the file inside follow path: /environmentProject/php.dockerfile
Inside the file we'll set our PHP 8.2 FPM version. To use it we need a tag that we can find on dockerhub. With tag in hands, our first line should be:
FROM php:8.2-fpm
Versions tag list here.
Following the version we need to install our core extensions:
RUN apt-get update && apt-get install -y \ libfreetype6-dev \ libjpeg62-turbo-dev \ libpng-dev \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) gd \ && docker-php-ext-install mysqli pdo pdo_mysql && docker-php-ext-enable pdo_mysql
Some extensions come by default. It depends on the PHP version you are using. Run docker run --rm php:8.2-fpm php -m
in the your terminar to see full extension list.
PECL extensions:
Its time to bring some extensions for performance and utility, to it we'll use PECL, a PHP extension repository.
Here we'll install xdebug
, libmencached
and zlib1g
. Lets add some more lines in our dockerfile:
RUN pecl install xdebug-3.0.4 \ && docker-php-ext-enable xdebug RUN apt-get install -y libmemcached-dev zlib1g-dev \ && pecl install memcached-3.1.5 \ && docker-php-ext-enable memcached
PECL extensions should be installed in series to fail properly if something went wrong. Otherwise errors are just skipped by PECL.
For packages we'll use composer with zip and unzip:
RUN apt-get install zip unzip \ && curl -sS https://getcomposer.org/installer -o composer-setup.php \ && php composer-setup.php --install-dir=/usr/local/bin --filename=composer \ && unlink composer-setup.php
Setting our timezone and activating opcache for performance of PHP:
RUN echo 'date.timezone="America/Sao_Paulo"' >> /usr/local/etc/php/conf.d/date.ini \ && echo 'opcache.enable=1' >> /usr/local/etc/php/conf.d/opcache.conf \ && echo 'opcache.validate_timestamps=1' >> /usr/local/etc/php/conf.d/opcache.conf \ && echo 'opcache.fast_shutdown=1' >> /usr/local/etc/php/conf.d/opcache
You can check the list of timezone supported by PHP here.
If you want to use PHP and Laravel with Nginx you need to configure FastCGI and a few other things. Let's break it into steps:
-
Gen SSL (
optional
)You can use my Makefile to gen a SSL with just
make gen-ssl
in terminal (in case of you are a windows user), or follow the steps of this GUIDE. -
Server
server.conf
Create
/environmentProject/confs/servers/server.conf
file.
Edit server.conf
, set a config that listen container port 80 and 443 (ssl port), set ssl_certificate
and ssl_certificate_key
with your SSL certificates location and pass all FastCGI configs for PHP-FPM. Example:
server { ############# Ports ################# listen 80; # listen 443 ssl; ##################################### root /var/www/projects/; ########## SSL CERTIFICATE ########## # ssl_certificate /var/www/ssl/localhost.crt; # ssl_certificate_key /var/www/ssl/localhost.key;
##################################### autoindex on;
########## FAST CGI CONFIG ########## location ~ \.php$ { fastcgi_index index.php; fastcgi_pass php:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
This should be enough to run your native PHP app. With Laravel your server.conf
should be like:
server { listen 80; server_name example.com; root /var/www/projects/example-app/public;
add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
location / { try_files $uri $uri/ /index.php?$query_string; }
location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ { fastcgi_index index.php; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; }
location ~ /\.(?!well-known).* { deny all; } }
Check Laravel documentation for more details.
It's time to bring all together using docker-compose.
I'll not get in details in this guide about versions, services, volumes, etc... but you can learn more in Docker Documentation.
Create /environmentProject/docker-compose.yml
file, edit it and lets start!
The first line of our docker-compose.yml
should be the version of docker-compose. Here we'll use the latest:
version: "3.9"
Following version
line let's build our containers. We'll set 3 (or 4) containers: Nginx, PHP, MySql and Node(NPM) (optional
). Let's break it into steps:
-
With this
volumes
setup, all principal configs can be made within your environment without the need of get in the container.services: web-server: image: nginx:1.21.1 container_name: webdev-nginx ports: - "80:80" - "443:443" networks: - web-dev volumes: - ./confs/servers/:/etc/nginx/conf.d/ - ./projects:/var/www/projects - ./confs/ssl/:/var/www/ssl
-
volumes
of PHP image need to be in the same directory of yourweb-server
projects.php: build: dockerfile: ./php.dockerfile context: . image: php:8.2-fpm container_name: webdev-php volumes: - "./projects:/var/www/projects" ports: - "9000:9000" networks: - web-dev
-
Here I'm creating a database on start for tests in the end. You can change MYSQL_USER and MYSQL_PASSWORD if you want.
db: image: mysql:8.0.26 container_name: webdev-mysql volumes: - ./confs/mysql_db:/var/lib/mysql command: --default-authentication-plugin=mysql_native_password environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: test_db MYSQL_USER: devuser MYSQL_PASSWORD: devpass ports: - "3306:3306" networks: - web-dev
-
If you want a live container for just NPM you can follow this step.
My recommendation is to use a Makefile for packages instead of making a live container for it. Using a Makefile you can create a command (like
make npm
) that will instance a container, let you use the interactive mode and when you done all your interaction with NPM on your project, you can leave and the container created will not exist anymore, this can provide you performance (taking into account that a container with Node has 900MB~1GB), but this will take a little bit more time than create a live container.node: image: node:lts container_name: webdev-node-npm volumes: - "./projects:/var/www" ports: - "9002:9002" networks: - web-dev tty: true
-
web-dev
bring all containers together in a network.networks: web-dev: driver: bridge
With all set up let's bring our environment to life.
In /environmentProject/
directory, build all images with:
docker-compose build
When its over, let's run all containers with:
docker-composer up -d
Get in your localhost and voilá!
With all running, you can test your MySql connection navigating to localhost/index.php. If all is okay you will receive a successfully message.
For laravel test, you will need to edit /example-app/.env
and set your connection with mysql. Example:
DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=test_db DB_USERNAME=devuser DB_PASSWORD=devpass
Save and exec follow commands:
docker exec (container_id) composer dump-autoload docker exec (container_id) php artisan migrate
If you don't receive any error message your connection is fine and you are ready to codding.