The full stack development based on Docker for Symfony Rest API and JS Framework

In this article I will show you how to build full stack environment for PHP and JS developers. The first step is to install docker and docker compose as described here, after successful installation install docker-compose following. Now we are ready to build our full stack setup for both side developers. We will build our stack from starting a presentation of a docker-compose.yml file which will be the recipe from which images we will build our own.
version: '2'
        image: mysql:5.7
        command: --default-authentication-plugin=mysql_native_password
        restart: always
        container_name: mysql
            - ./mysql:/var/lib/mysql
            context: php7.3-fpm
                TIMEZONE: ${TIMEZONE}
            - ${BACKEND_FOLDER}:/var/www/symfony
        container_name: php
        build: nginx
        container_name: nginx
            - 8080:80
            - php
            - ./logs/nginx/:/var/log/nginx
            context: node
        container_name: node
            - 4200:4200
            - 3000:3000
        tty: true
            - ${FRONTEND_FOLDER}:/app
        image: phpmyadmin/phpmyadmin
        container_name: phpmyadmin
            MYSQL_USERNAME: root
            PMA_HOST: mysql

            - mysql
            - 8081:80

Each docker-compose.yml file must have in first line version, in my case it's 2, current version is 3, but for our simple setup we don’t need version 3. Next we define our services, which are images of apps, which we will use in our environment. Images can be found on docker hub with description of image’s environment variables, which we can or must use in docker-compose.yml. In docker-compose.yml file we can use variables, which are defined as ${VARIABLE_NAME} and they are located in the next important file named .env. Below is an example of .env file, which we will use.

# NGINX Web Server


# Timezone
Now I explain some basic key features of docker-compose files syntax:
  • image – name of image which we will find on docker hub,
  • build – image will be created on the base of Dockerfile, then will be run
  • command – here we put commands, which are required or can be used with image,
  • volumes – is responsible for persisting(storing) data between each run of container,
  • volumes_from – gives access to other container data,
  • ports – is responsible for communicating with image from outside of our container, simple rule: outer_world_port:container_port,
  • links – it handles that one container can see other container by it’s service name.

As we now know the basic of docker-compose file and .env file we will create a folder for both this files. Let’s we called it docker. Next step on building our custom build is to create specific Dockerfiles , for nginx and php services defined in docker-compose.yml. In the folder docker create file called docker-compose.yml and copy there the content of above explained docker-compose file. After this create .env file, but to see it you must enable to showing hidden files and put inside the variables, which are used in docker-compose.yml files. On the same level, on which is located our docker-compose.yml file and .env file let’s create folders called nginx and php7.3-fpm. In nginx folder create files:

  • Dockerfile - is a text document that contains all the commands a user could call on the command line to assemble an image. It must start from uppercase letter. Content of it:
FROM debian:buster-slim

RUN apt-get update && apt-get install -y \

ADD nginx.conf /etc/nginx/
ADD symfony.conf /etc/nginx/sites-available/

RUN ln -s /etc/nginx/sites-available/symfony.conf /etc/nginx/sites-enabled/symfony
RUN rm /etc/nginx/sites-enabled/default

RUN echo "upstream php-upstream { server php:9000; }" > /etc/nginx/conf.d/upstream.conf

RUN usermod -u 1000 www-data

CMD ["nginx"]

  • nginx.conf - nginx configuration file:
user www-data;
worker_processes 4;
pid /run/;

events {
  worker_connections 2048;
  multi_accept on;
  use epoll;

http {
  server_tokens off;
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  keepalive_timeout 15;
  types_hash_max_size 2048;
  include /etc/nginx/mime.types;
  default_type application/octet-stream;
  access_log off;
  error_log off;
  gzip on;
  gzip_disable "msie6";
  include /etc/nginx/conf.d/*.conf;
  include /etc/nginx/sites-enabled/*;
  open_file_cache max=100;

daemon off;
  • symfony.conf – nginx virtual host configuration for Symfony 3.x:
server {
    server_name symfony.dew;
    root /var/www/symfony/web;

    location / {
        try_files $uri @rewriteapp;

    location @rewriteapp {
        rewrite ^(.*)$ /app_dev.php/$1 last;

    location ~ ^/(app|app_dev|app_acceptance|config)\.php(/|$) {
        fastcgi_pass php-upstream;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS off;

    error_log /var/log/nginx/symfony_error.log;
    access_log /var/log/nginx/symfony_access.log;
  • symfony.conf – nginx virtual host for Symfony 4.x:
server {
    server_name symfony.dew;
    root /var/www/symfony/public;

    location / {
        try_files $uri @rewriteapp;

    location @rewriteapp {
        rewrite ^(.*)$ /index.php/$1 last;

    location ~ ^/(index)\.php(/|$) {
        fastcgi_pass php-upstream;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS off;

    error_log /var/log/nginx/symfony_error.log;
    access_log /var/log/nginx/symfony_access.log;

In php7.3-fpm folder create files:

  • Dockerfile
FROM php:7.3-fpm

# php ini set memory limit
COPY "memory-limit-php.ini" "/usr/local/etc/php/conf.d/memory-limit-php.ini"

RUN apt-get update && apt-get install -y sudo \
    openssl \
    git \
    unzip \
    gnupg2 \
    apt-utils \
    zlib1g-dev \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    libicu-dev \
    libxml2-dev \
    libmcrypt-dev \
    libcurl4-openssl-dev \
    pkg-config \
    libssl-dev \
    bash \
    g++ \
    libzip-dev \

# Install Composer
RUN curl -sS | php -- --install-dir=/usr/local/bin --filename=composer
RUN composer --version

# Set timezone
RUN ln -snf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime && echo ${TIMEZONE} > /etc/timezone
RUN printf '[PHP]\ndate.timezone = "%s"\n', ${TIMEZONE} > /usr/local/etc/php/conf.d/tzone.ini
RUN "date"

# configure intl
RUN docker-php-ext-configure intl

# Type docker-php-ext-install to see available extensions
RUN docker-php-ext-install pdo pdo_mysql zip gd mbstring intl soap

# install apcu
RUN pecl install apcu \
    && docker-php-ext-enable apcu

RUN apt-get update && apt-get install -y \
        libfreetype6-dev \
        libjpeg62-turbo-dev \
        libpng-dev \
    && docker-php-ext-install -j$(nproc) iconv \
    && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd

RUN pecl install mongodb \
&& docker-php-ext-enable mongodb

RUN apt-get update || apt-get update \
    && apt-get install -y \
        librabbitmq-dev \
        libssh-dev \
    && docker-php-ext-install \
        bcmath \
        sockets \
    && pecl install amqp \
    && docker-php-ext-enable amqp

RUN chmod -R a+rw /var/www/

RUN adduser --disabled-password --home /home/user user
RUN addgroup user users
# Cleanup
RUN apt-get update && apt-get upgrade -y && apt-get autoremove -y

USER user

WORKDIR /var/www
  • memory-limit-php.ini

At the node folder has only one Dockerfile which content is:

FROM node:10

# for installing angular cli
RUN npm install -g @angular/cli

RUN mkdir app


At the end we must go a one level up from docker catalog, where we will create folders for backend and frontend. In backend folder we will see Symfony files and in frontend we will have files from some JS framework. Here is how it should look like:

Here is how it should look like the main folder structure:

Inside of docker folder we have:

Nginx catalog have 3 files:

Directory node has only one file:

last folder php7.3-fpm have:

In frontend folder we have to create a folder, which name is the project’s name, in my example it will be angular-app folder. Finally, we can type in our console command to build our container:
docker-compose build
then after successful build lets type
docker-compose up -d
the switch “-d” is for running our container in the background. Now our container is running and we can enter it by writing command:
docker exec –it –u user php bash
Now inside of the container we are logged in as user and our starting position is /var/www. Here we can use composer to create for example a new Symfony4 project by typing:
composer create-project symfony/website-skeleton symfony
After successful project creation we must create a default controller. For doing that enter the symfony folder and type:
bin/console make:controller
After this edit this controller and change path annotation to “/”. Now you are ready to write localhost:8080 in your internet browser and you will see the symfony starting page. When you type localhost:8081 you will see login screen into phpmyadmin. For entering the node server open a new console window and type in:
docker exec –it –u root node bash
Now you will be in location /app from which you can see our folder, which we called earlier angular-app. Now for creating an Angular app type:
ng new agular-app
For starting our angular app type:
ng serve --host
On red color I have marked important parameter --host without it your app will be no visible from outside of container Now type in browser localhost:4200 to see running Angular app. If you want to use React instead of Angular then you need only type npm start and type in browser localhost:3000

This site uses cookies. By continuing to browse the site you are agreeing to our use of cookies. click here to close