The easy way to install Symfony with Docker

oumaima neffati
6 min readSep 12, 2023

--

Welcome to my first article !

I’m Oumaima, a software engineer with a passion for sharing knowledge, always eager to learn more .. until now I don’t know much but I’ll be sharing anyway :)

The picture might make it seem like we’re about to feed Symfony to our friendly dolphin, but don’t worry it’s not the case :)

I’m just sharing with you my super method to install Symfony 6.x with Docker.

Just so you know, this isn’t the only way, it’s one approach among many. While I’ll be using Composer and Nginx, Symfony provides other methods such as using the Symfony console and the internal Symfony server mentioned in the documentation.

Let’s dive in!

1/ Create your docker-compose.yml setup

To begin our Symfony adventure, we’ll start by creating a docker-compose.yml file. This file will orchestrate the deployment of our Symfony 6.x application. All we need are three essential components: PHP 8.x, a web server (Nginx in our case but you can use Apache as well), and a database MYSQL (which we'll simply call 'db' in our Docker setup).

#docker-compose.yml
version: "3.8"

services:
php:
build: ./docker/php
volumes:
- ./app:/var/www/html
networks:
- symfony

nginx:
build: ./docker/nginx
ports:
- "80:80"
volumes:
- ./app:/var/www/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
networks:
- symfony

db:
image: mysql:8.0.33
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: symfony
MYSQL_USER: symfony
MYSQL_PASSWORD: secret
networks:
- symfony

networks:
symfony:

In this docker-compose.yml file, we define three crucial services: php, nginx, and db. Let’s break down their roles:

php: Well, of course, we won’t be building a Symfony project without PHP! ;)

We’ll be using the php:8.x-fpm image, for Symfony 6.3 you can use 8.1 or higher.

nginx: We employ the official Nginx image, exposing port 80.

db: For the database, we use the mysql:8.x image and configure it by setting environment variables for the MySQL root password, database name, user, and password which will be defined in our .env file

The networks section introduces a custom network named symfony. This network enables seamless communication between our services.

With our Docker composition in place, we’re ready to move on to the next step.

2/ Create your PHP Dockerfile

For organization purposes, we’ll start by creating a directory structure. Inside a directory called “docker,” create another directory named “php.” In this “php” directory, we’ll define our Dockerfile for PHP. This Dockerfile, located at /docker/php, is where we'll handle PHP extension installation.

Here’s the content of the Dockerfile:

#docker/php
FROM php:8.2-fpm-buster

RUN apt-get update && apt-get install -y \
gnupg \
g++ \
procps \
openssl \
git \
unzip \
zlib1g-dev \
libzip-dev \
libfreetype6-dev \
libpng-dev \
libjpeg-dev \
libicu-dev \
libonig-dev \
libxslt1-dev \
acl \
&& echo 'alias sf="php bin/console"' >> ~/.bashrc

RUN docker-php-ext-configure gd --with-jpeg --with-freetype

RUN docker-php-ext-install \
pdo pdo_mysql zip xsl gd intl opcache exif mbstring

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

WORKDIR /var/www/symfony

In this Dockerfile, we:

  • Use the php:8.2-fpm-buster as our base image.
  • Update the package list and install various dependencies required for Symfony and PHP extensions.
  • Configure and install PHP extensions necessary for Symfony, such as pdo, pdo_mysql, zip, xsl, gd, intl, opcache, exif, and mbstring.
  • Set up an alias for Symfony’s console command, making it more convenient to run Symfony console commands.
  • Install Composer to manage PHP dependencies.

We can also add an instruction to change the configuration of php.ini as well by adding :

COPY php.ini /usr/local/etc/php/conf.d/docker-php-config.ini

in the Dockerfile and to create in the php directory a php.ini with your custom configuration.

With these Dockerfile instructions, we’re ready to build our PHP is ready to run !

3/ Create your Nginx configuration

Inside the docker directory, create a nginx directory. In this nginx directory, create an nginx.conf file with the following content:

#docker/nginx/nginx.conf
user nginx;
worker_processes auto;

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;
client_max_body_size 0;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;

keepalive_timeout 65;

gzip on;

include /etc/nginx/conf.d/*.conf;
}

This nginx.conf file sets up Nginx configurations, including user, worker processes, error logging, event handling, HTTP configurations, and more.

Still inside the docker/nginx directory, create a Dockerfile with the following content:

#docker/nginx/Dockerfile
FROM nginx:1.21-alpine

COPY nginx.conf /etc/nginx/
COPY templates /etc/nginx/templates/
RUN echo "upstream php-upstream { server php:9000; }" > /etc/nginx/conf.d/upstream.conf

EXPOSE 80
EXPOSE 443

Don’t worry, you’re not the only one who thinks Dockerfiles are written in an alien language at first!

So, let me break down what I’ve learned from this Dockerfile:

we’re using the official Nginx Alpine image as our base. We copy our custom nginx.conf to Nginx's configuration directory and create an upstream configuration to point to the PHP-FPM service, ensuring our services are in sync.

Than, Create a directory named templates inside the docker/nginx directory. I choose to name it templates, if you’re feeling adventurous, go ahead and name it “toto,” but be sure to adjust your Dockerfile accordingly otherwise nothing will work :( .

Inside the templates directory, create a default.conf.template file with the following content:

#docker/nginx/templates/default.conf.template
server {
listen 80;
server_name localhost;
root /var/www/symfony/public;

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

location ~ ^/index\.php(/|$) {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Max-Age' 1728000 always;
add_header 'Content-Type' 'text/plain; charset=utf-8' always;
add_header 'Content-Length' 0 always;
return 204;
}
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

fastcgi_pass php:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
internal;
}
location ~ \.php$ {
return 404;
}

error_log /dev/stdout info;
access_log /var/log/nginx/project_access.log;
}

This default.conf.template file configures Nginx to serve your Symfony application. It sets up the routes and handles PHP requests via FastCGI.

Your Docker directory structure should now look like this :

4/ Create your .env file

At the same level of your docker-compose.yml create .env

#.env
COMPOSE_PROJECT_NAME=symfony
MYSQL_ROOT_PASSWORD=root
MYSQL_DATABASE=symfony
MYSQL_USER=user
MYSQL_PASSWORD=root

You see I used a very strong password for my project :D but please, don’t follow my lead and use these credentials in a production environment..

5/ Start your Docker

Now that everything is set up, navigate to the root directory (where your docker-compose.yml is located) in your terminal, and execute the following command to start your Docker containers. This command will also rebuild the containers if necessary:

docker-compose up --build

6/ Install the Symfony project

To install the Symfony project within your Docker environment, access the PHP container using the following command:

docker-compose exec php bash

Inside the container PHP, use Composer to create a new Symfony project. Here, we’ll create a Symfony project named symfony

composer create-project symfony/skeleton:"6.3.*" symfony

Ensure that your docker directory and docker-compose.yml are located within your project directory. Your project structure should resemble this:

With these steps completed, your Symfony project is now up and running within a Dockerized environment.

Now go to http://localhost:80 and voilà enjoy !!

--

--