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
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
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
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
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
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;
}
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;
}
./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;
}
}
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"
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
How to use
To use the stack simply go onto the ./docker folder and run
docker-compose up --build
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
Latest comments (5)
Hi, great article! Struggling with Docker for a while and looking for sources so thanks.
Now, few questions
This is my first time I saw anything of Symfony, quite a mess :D :)
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"
Stay tune but the version used here are clearly outdated.
Link for wait-for-it: github.com/vishnubob/wait-for-it
Hi!
Nice article, just a few notes/questions:
M
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.