The perfect kit starter for a Symfony 4 project with Docker and PHP 7.2

Romaric Paul
Mar 16, 2018 · 6 min read

If you want to start a new project with Symfony 4 and Docker, this post is for you ! #OhYeah !

You can get this template directly here :

git clone https://github.com/romaricp/kit-starter-symfony-4-docker.git

or follow this tutorial. :)

First : Init your Docker

You have to install Docker on your local desktop.

  • Go to your project directory and create the `docker-compose.yml` file :
mkdir /your/path/project
cd /your/path/project
vim docker-compose.yml

and copy this inside :

version: '3'
services:
apache:
build: .docker/apache
container_name: sf4_apache
ports:
- 80:80
volumes:
- .docker/config/vhosts:/etc/apache2/sites-enabled
- .:/home/wwwroot/sf4
depends_on:
- php

mysql:
image: mysql:8
container_name: sf4_mysql
volumes:
- .docker/data/db:/var/lib/mysql
command:
- "--default-authentication-plugin=mysql_native_password"
- "--lower_case_table_names=1"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: sf4
MYSQL_USER: sf4
MYSQL_PASSWORD: sf4

php:
build: .docker/php
container_name: sf4_php
volumes:
- .:/home/wwwroot/sf4
environment:
- maildev_host=sf4_maildev
depends_on:
- maildev
- mysql

phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: sf4_phpmyadmin
environment:
PMA_HOST: mysql
PMA_PORT: 3306
ports:
- 8080:80
links:
- mysql

maildev:
image: djfarrelly/maildev
container_name: sf4_maildev
ports:
- 8001:80

The `docker-compose.yml` is where we have to list all containers than we need. After that we have to configure each container which use build property ;image property mean Docker will get automatically from hub.docker.com.

  • Create the docker directories to configure each container
mkdir -p .docker/apache
mkdir -p .docker/php
mkdir -p .docker/config/vhosts

Second : Setting apache2 with docker

Create the DockerFile

vim .docker/apache/Dockerfile

and copy this inside :

FROM debian:stretch

ENV HTTPD_PREFIX /usr/local/apache2
ENV PATH $HTTPD_PREFIX/bin:$PATH
RUN mkdir -p "$HTTPD_PREFIX" \
&& chown www-data:www-data "$HTTPD_PREFIX"
WORKDIR $HTTPD_PREFIX

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
apache2 curl \
&& rm -r /var/lib/apt/lists/*
RUN
a2enmod proxy_fcgi ssl rewrite proxy proxy_balancer proxy_http proxy_ajp
RUN sed -i '/Global configuration/a \
ServerName localhost \
' /etc/apache2/apache2.conf
EXPOSE 80 443
RUN rm -f /run/apache2/apache2.pid
CMD apachectl -DFOREGROUND -e info

Create the `httpd.conf` file

vim .docker/config/vhosts/sf4.conf

and copy this inside :

<VirtualHost *:80>

Define server_name sf4.local
Define basedocroot /home/wwwroot/sf4
Define docrootweb ${basedocroot}/public
Define logdir /var/log/apache2/

<FilesMatch .php$>
SetHandler "proxy:fcgi://sf4_php:9000"
</FilesMatch>

ServerName ${server_name}
DocumentRoot ${docrootweb}
ErrorLog ${logdir}/error.log
CustomLog ${logdir}/access.log Combined

RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

<Directory ${docrootweb}>
AllowOverride All
Require all granted
</Directory>

<Directory ${basedocroot}/var>
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
</Directory>

<Directory ${docrootweb}>
DirectoryIndex ${docrootweb}/index.php
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]

RewriteCond %{HTTP:Authorization} .
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]

RewriteRule ^ %{ENV:BASE}/index.php [L]
</IfModule>

<IfModule !mod_rewrite.c>
<IfModule mod_alias.c>
RedirectMatch 302 ^/$ /index.php/
</IfModule>
</IfModule>
</Directory>

Undefine server_name
Undefine basedocroot
Undefine docrootweb
Undefine logdir
</VirtualHost>

Third : Set up php7.2.3 with docker

Create the Dockerfile

vim .docker/php/Dockerfile

and copy this inside :

FROM php:7.2.3-fpm

RUN
apt-get update \
&& apt-get install -y --no-install-recommends vim curl debconf subversion git apt-transport-https apt-utils \
build-essential locales acl mailutils wget zip unzip \
gnupg gnupg1 gnupg2
RUN docker-php-ext-install pdo pdo_mysqlCOPY php.ini /etc/php/7.2.3/php.ini
COPY php-fpm-pool.conf /etc/php/7.2.3/pool.d/www.conf

RUN curl -sSk https://getcomposer.org/installer | php -- --disable-tls && \
mv composer.phar /usr/local/bin/composer

RUN groupadd dev -g 999
RUN useradd dev -g dev -d /home/dev -m

RUN rm -rf /var/lib/apt/lists/*
RUN
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && \
echo "fr_FR.UTF-8 UTF-8" >> /etc/locale.gen && \
locale-gen

WORKDIR /home/wwwroot/

EXPOSE
9000
CMD ["php-fpm"]

Create the php.ini

vim .docker/php/php.ini

and copy the official content of a php.ini of PHP7.2.3 : https://github.com/php/php-src/blob/PHP-7.2.3/php.ini-development

Create the php-fpm-pool.conf

vim .docker/php/php-fpm-pool.conf

and copy this inside :

; Start a new pool named 'www'.
; the variable $pool can we used in any directive and will be replaced by the
; pool name ('www' here)
[www]

; Unix user/group of processes
user = www-data
group = www-data

; The address on which to accept FastCGI requests.
listen = 0.0.0.0:9000

; Set listen(2) backlog.
listen.backlog = 1023

; Choose how the process manager will control the number of child processes.
pm = dynamic

; The number of child processes to be created when pm is set to 'static' and the
pm.max_children = 8

; The number of child processes created on startup.
; Note: Used only when pm is set to 'dynamic'
; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
pm.start_servers = 2

; The desired minimum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
pm.min_spare_servers = 1

; The desired maximum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
pm.max_spare_servers = 3

pm.status_path = /php-fpm-status
ping.path = /php-fpm-ping

; The timeout for serving a single request after which the worker process will be killed.
request_terminate_timeout = 5m

; Chdir to this directory at the start.
; Note: relative path can be used.
; Default Value: current directory or / when chroot
chdir = /

; Redirect worker stdout and stderr into main error log. If not set, stdout and
; stderr will be redirected to /dev/null according to FastCGI specs.
; Note: on highloaded environement, this can cause some delay in the page
; process time (several ms).
; Default Value: no
catch_workers_output = yes

One last thing !

Create the `.gitignore` file

vim .gitignore

and copy this inside :

###> docker ###
.docker/data/*
###< docker ###

So normaly you have something like that :

You can also download this part directly here :

https://github.com/romaricp/kit-starter-symfony-4-docker/commit/6d636fe5cc1d55fb09f0f8aa48fb29fda0e0e80a

Fourth : Let’s start Docker !

docker-compose build

At this moment, Docker will execute all configurations that we set up. When it’s done, you can launch your containers !

docker-compose up -d

Fourth bis : How Docker work ?

I will not explain how Docker because this is not the subject, but for keep going this post you have to understand two things :

  • Each container is one linux distribution with one component
  • Each container have one root access by default

So when you execute this :

docker exec -it -u sf4_mysql bash

You are right now in the mysql container as root user. You can explorer this container as you want ;)

Fifth : Symfony 4 here we are !

Now we know how use Docker, so let’s go to the PHP one and not as root, but as user : dev

docker exec -it -u dev sf4_php bash

Now you are inside the php container with dev user and we have to get Symfony. Just to test, launch a php -v in this container. ;)

So let’s go to your home :

cd /home/wwwroot/sf4

Installation of Symfony4 with composer

composer create-project symfony/skeleton my-temp-folder

When it’s done, we will get the project to the root path.

cp -Rf /home/wwwroot/sf4/my-temp-folder/. .
rm -Rf /home/wwwroot/sf4/my-temp-folder

Launch in your browser : localhost

Congratulation !! You can now easily start your new Symfony project. If you look inside the docker-compose.yml file you can see all acces as you need, for example the mysql access :

MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: sf4
MYSQL_USER: sf4
MYSQL_PASSWORD: sf4

Enjoy ! ;)

Romaric.

Romaric Paul

Written by

Developer Web and mainly Symfony framework addict — https://romaricp.github.io/

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade