How to build a clean Docker Symfony 5.2 PHP8 PostgreSQL Nginx project
Nicolas Bonnici

Nicolas Bonnici @nicolasbonnici

Location:
Paris, France
Joined:
Aug 16, 2017

How to build a clean Docker Symfony 5.2 PHP8 PostgreSQL Nginx project

Publish Date: Feb 9 '21
33 5

Hey there today we gonna build a boilerplate project using Docker for symfony 5.2 with PHP8, PostgreSQL database engine and nginx as reverse-proxy.

Getting Started

First you need Docker and docker-compose, i am gonna use those versions:

$ docker -v && docker-compose -v
Docker version 19.03.8, build afacb8b7f0
docker-compose version 1.27.4, build 40524192
Enter fullscreen mode Exit fullscreen mode

PosgreSQL

Using docker-compose setup PostgreSQL is very easy we gonna use version 12 from postgres:12 Docker image.

./docker/docker-compose.yml

version: '3.8'

services:
  db:
    container_name: db
    image: postgres:12
    restart: always
    environment:
        POSTGRES_PASSWORD: password
        POSTGRES_DB: testdb
    ports:
        - 15432:5432
Enter fullscreen mode Exit fullscreen mode

And that's it, nothing more, here we just ensure the container will always restart and forward 15432 container port to 5432 local port.

PHP8

We gonna u_se and setup the "php:8.0-fpm" Docker image and setup the PostegreSQL PDO driver.

./docker/php-fpm/Dockerfile

FROM php:8.0-fpm

COPY wait-for-it.sh /usr/bin/wait-for-it

RUN chmod +x /usr/bin/wait-for-it

RUN apt-get update && \
    apt-get install -y --no-install-recommends libssl-dev zlib1g-dev curl git unzip netcat libxml2-dev libpq-dev libzip-dev && \
    pecl install apcu && \
    docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql && \
    docker-php-ext-install -j$(nproc) zip opcache intl pdo_pgsql pgsql && \
    docker-php-ext-enable apcu pdo_pgsql sodium && \
    apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

COPY --from=composer /usr/bin/composer /usr/bin/composer

WORKDIR /var/www

CMD composer i -o ; wait-for-it db:5432 -- bin/console doctrine:migrations:migrate ;  php-fpm 

EXPOSE 9000
Enter fullscreen mode Exit fullscreen mode

Then update docker-compose to connect and add a dependency to db container and expose our ./src folder

./docker/docker-compose.yml

  php-fpm:
    container_name: php-fpm
    build:
      context: ./php-fpm
    depends_on:
      - db
    environment:
      - APP_ENV=${APP_ENV}
      - APP_SECRET=${APP_SECRET}
      - DATABASE_URL=${DATABASE_URL}
    volumes:
      - ./../src/:/var/www
Enter fullscreen mode Exit fullscreen mode

Nginx

Then finally use nginx web server as reverse proxy to our php-fpm container.

./docker/nginx/Dockerfile

FROM nginx:alpine

WORKDIR /var/www

CMD ["nginx"]

EXPOSE 80 443
Enter fullscreen mode Exit fullscreen mode

Add nginx configurations

./docker/nginx/Dockerfile

user  nginx;
worker_processes  4;
daemon off;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    access_log  /var/log/nginx/access.log;
    #access_log /dev/stdout;
    #error_log /dev/stderr;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip  on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-available/*.conf;
}

Enter fullscreen mode Exit fullscreen mode

And configure default blocks, one for our php-fpm upstream and an other for the global project respectively on ./docker/nginx/conf.d/default.conf and ./docker/nginx/sites/default.conf.

./docker/nginx/conf.d/default.conf

upstream php-upstream {
    server php-fpm:9000;
}
Enter fullscreen mode Exit fullscreen mode

./docker/nginx/sites/default.conf

server {

    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    server_name localhost;
    root /var/www/public;
    index index.php index.html index.htm;

    location / {
         try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_pass php-upstream;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        #fixes timeouts
        fastcgi_read_timeout 600;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt/;
        log_not_found off;
    }
}

Enter fullscreen mode Exit fullscreen mode

The last step is to create a dependency on our php-fpm container in our docker-compose configuration.

./docker/docker-compose.yml

  nginx:
    container_name: nginx
    build:
      context: ./nginx
    volumes:
      - ./../src/:/var/www
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/sites/:/etc/nginx/sites-available
      - ./nginx/conf.d/:/etc/nginx/conf.d
      - ./logs:/var/log
    depends_on:
      - php-fpm
    ports:
      - "80:80"
      - "443:443"
Enter fullscreen mode Exit fullscreen mode

Symfony 5

With a very few configuration we built our stack, now to setup Symfony let create a "src" project root folder and use composer.

composer create-project symfony/skeleton ./src
Enter fullscreen mode Exit fullscreen mode

How to use

To use the stack simply go onto the ./docker folder and run

docker-compose up --build
Enter fullscreen mode Exit fullscreen mode

To go further

Use a CI such like Github Actions or Gitlab CI to build and deploy this project.

Conclusion

With a very few configuration, we built a solid Symfony5 project stack using Docker.

Thank you for reading, you can find this tutorial source code on github: https://github.com/nicolasbonnici/docker-php8-sf5-nginx-pqsql-boilerplate

Comments 5 total

  • mmarton
    mmartonFeb 14, 2021

    Hi!

    Nice article, just a few notes/questions:

    1. you named the nginix config file Dockerfile
    2. it was a bit misleading that you called your working directory src. At first i thought you only mapped the symfony's src folder into the php container.
    3. You map the whole project with vendor and possible node_modules into 2 containers. Wouldn't it be enough just to map the public dir to the nginx?
    4. what is the performance of the config above,

    M

    • Nicolas Bonnici
      Nicolas BonniciMar 5, 2021

      Hey there,

      Nope the actual ./docker/nginx/Dockerfile is a very simple docker container build conf from nginx:alpine image.

      I totally agree with you, i should rename this folder something like symfony for instance, you can submit a pull request if you want to.

      Nope actually no use of npm, and composer vendors directory his located under the folder the actual ./src folder.

      These is a development stack, not optimized or production ready, but the build time is very honorable.

  • Alexandru Chitoraga
    Alexandru ChitoragaAug 15, 2021

    Link for wait-for-it: github.com/vishnubob/wait-for-it

  • Šimon Janča
    Šimon JančaJun 25, 2022

    Hi, great article! Struggling with Docker for a while and looking for sources so thanks.

    Now, few questions

    • in docker-compose.yml the version number 3.8 tells me it's unsupported version, I'd use just integers like 3, that works
    • Nginx tells me it cannot access /var/log/nginx/error.log, so I'd put something like mkdir chmod and chown into the image
    • If the containers are up, so where I can access the application with browser on the host computer?
    • PHP tells me; doctrine don't support postgres driver but only ..., so I changed driver to pdo_psql instead in config/packages/doctrine.yaml

    This is my first time I saw anything of Symfony, quite a mess :D :)

    • Nicolas Bonnici
      Nicolas BonniciJun 25, 2022

      Hey there,

      Yup this is an old post must write a "How to build a clean Docker Symfony 6.2 PHP8.1 PostgreSQL 14 Nginx project" post ;)

      • Not according to docker-compose documentation docs.docker.com/compose/compose-fi...

      • Storing error logs under a container is a bad practice. You need to store them outside containers like so or somewhere else like an external service

      nginx:
      container_name: nginx
      build:
      context: ./nginx
      volumes:
      - ./../symfony/:/var/www
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/sites/:/etc/nginx/sites-available
      - ./nginx/conf.d/:/etc/nginx/conf.d
      - ./logs:/var/log
      depends_on:
      - php-fpm
      ports:
      - "8080:80"
      - "443:443"

      • Good if it's working, i usually use "pdo_pgsql" no problem with it

      Stay tune but the version used here are clearly outdated.

Add comment