DEV Community

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

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

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

Oldest comments (5)

Collapse
 
mmarton profile image
mmarton

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

Collapse
 
nicolasbonnici profile image
Nicolas Bonnici

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.

Collapse
 
alexchitoraga profile image
Alexandru Chitoraga

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

Collapse
 
sjiamnocna profile image
Šimon Janča

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 :)

Collapse
 
nicolasbonnici profile image
Nicolas Bonnici • Edited

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.