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

nicolasbonnici

Nicolas Bonnici

Posted on February 9, 2021

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

💖 💪 🙅 🚩
nicolasbonnici
Nicolas Bonnici

Posted on February 9, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related