DEV Community

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

Posted on • Updated on

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

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


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


version: '3.8'

    container_name: db
    image: postgres:12
    restart: always
        POSTGRES_PASSWORD: password
        POSTGRES_DB: testdb
        - 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.


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


FROM php:8.0-fpm

COPY /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 

Enter fullscreen mode Exit fullscreen mode

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


    container_name: php-fpm
      context: ./php-fpm
      - db
      - APP_ENV=${APP_ENV}
      - ./../src/:/var/www
Enter fullscreen mode Exit fullscreen mode


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


FROM nginx:alpine

WORKDIR /var/www

CMD ["nginx"]

EXPOSE 80 443
Enter fullscreen mode Exit fullscreen mode

Add nginx configurations


user  nginx;
worker_processes  4;
daemon off;

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

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.


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


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.


    container_name: nginx
      context: ./nginx
      - ./../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
      - php-fpm
      - "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.


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:

Discussion (3)

mmarton profile image


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,


nicolasbonnici profile image
nicolasbonnici Author

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.

alexchitoraga profile image
Alexandru Chitoraga

Link for wait-for-it: