This repository is a boilerplate for Symfony applications, to quickly configure development and production environments, with lifecycle workflows.
We use Docker & Docker-compose, to easily develop, test and deploy our application.
For databases, we are using MySQL here, but it can be easily adapted for MariaDB or Postgres.
To improve frontend development, we use Webpack-encore, configured to use SCSS and PReact. A ViteJS is configured to automatically reload the page, whenever a twig template is updated.
To automate testing and deployment, we use Github Actions workflows. Tests will be run in each pull request, and the application will be deployed each time the main
branch is updated.
For the production environment, we use Nginx to serve the application.
- Symfony 5 Boilerplate
- A Github repository
- A Docker registry (DockerHub could help)
- A private server, with Nginx and a webhooks handler
- Docker and Docker-compose installed locally and on your production server
In this repository, we use my personal registry docker.francois.poguet.com
, adapt it to use yours.
The .env
and docker-compose.yml
files are for the local development environment, so you can replace them to suit your local needs, with the .env.local
and docker-compose.override files .yml
.
For MySql and Node we use the official images, but for PHP and Nginx we use custom ones (in the ./docker/
directory). We add Composer and Symfony in the official PHP image and we add a default configuration for nginx (which you shouldn't need to change).
To be able to run the project, you need to create and push docker development images to your registry, they shouldn't change in the future. Production images will be built in the CI. Here we only have one development image, that of php.
To do this, you just need to run this command :
docker build -t docker.francois.poguet.com/symfony5-php-dev -f ./docker/php/Dockerfile.dev .
To configure databases, we use an init script (./Docker/MySQL/initdb.sql
), which creates both databases for development and testing, and the associated user. The script is executed when the MySQL data volume is first mounted (see the section about starting the server).
Remember to change the names of the databases, and the user credentials. You can add databases or users as you like.
The last step to run the server is to install the dependencies of Node and Symfony, in the associated containers. The commands are as follows:
docker-compose run php composer install
docker-compose run node npm install
We can now start the server, simply by starting the different containers, orchestrated by the docker-compose.yml
file, with this command :
You can use the -d
option to run in detached mode, to keep control of your terminal (but you won't be able to see the logs and potential errors).
docker-compose up
The Symfony application will run on localhost:8000 and PhpMyAdmin on localhost:8081.
You can change these ports as you want, you can also change the directory where MySQL data is stored ($HOME/docker-MySQL/sf5/
by default) but this one must be empty before initialization to avoid a lot of problems (in particular, the directory should not be the /var/lib/MySQL
used by the MySQL service).
Remember to change the MYSQL_ROOT_PASSWORD
to something more secure than root
.
To stop the server you just have to down the containers with the command :
docker-compose down
To run tests with phpunit
in a running PHP container, just run this command :
docker-compose exec php php ./bin/phpunit
If you just want to run tests without starting the server, use this one :
docker-compose run php php ./bin/phpunit
We use a .env.test
file to override the .env
for testing, for example to use a specific database (see here).
A workflow is configured to automatically run the tests in Github Actions, in each pull request (.github/workflows/test.yml
). It use a specific docker-compose
and .env
file, without development tools.
The PHP development image is pulled from your registry into the Github Actions server for testing, so be sure you pushed them.
The workflow uses Github Secrets to keep private your credentials for your docker registry, don't forget to populate them in your github repository.
To simplify commands through containers, I personally use Taskfile. You can install it here, and type task --list
to see the list of available tasks.
To deploy to production, you must build and push the PHP production image, which contains the built front-end assets and server code.
On your production server, you need the docker-compose.prod.yml
file, rename it to docker-compose.yml
to be detected automatically.
You also need your .env
file for the Symfony project.
As we only need a single database in production, we just need to set the environment variables directly in the docker-compose
and the database and user will be created on initialization. Again, use an empty directory for MySQL data.
If necessary, you can initialize the database(s) with a script, with the same method as above
The last file to have is the deploy.sh
script, which (re)starts the server with the latest version of the PHP production image.
If you want to manually stop the containers in production, you must use the -v
option (docker-compose down -v
) to stop the shared volume between the Nginx and PHP containers, otherwise the containers will not use the updated images.
To easily monitor the deployment of your project, this script uses webhooks to send logs to your Discord server, so you just need to adjust the variables at the top of the script for your project and your Discord server's webhook URL. See here how to set up a webhook in your discord server.
Success | Failure |
---|---|
![]() |
![]() |
A workflow is configured to automatically build and push production image in Github Actions, each time the main
branch is updated (.github/workflows/build.yml
).
Once the image is pushed, the action sends a webhook to your server telling it that it can run the deploy.sh
script to update the project.
Here too the workflow uses some Github secrets, don't forget them !
I personally use this tool to manage webhooks on my private server, with this configuration :
{
"id": "symfony-redeploy",
"execute-command": "/var/www/symfony5/deploy.sh",
"command-working-directory": "/var/www/symfony5/",
"trigger-rule": {
"and": [
{
"match": {
"type": "payload-hash-sha1",
"secret": "Your webhook secret",
"parameter": {
"source": "header",
"name": "X-Hub-Signature"
}
}
},
{
"match": {
"type": "value",
"value": "refs/heads/main",
"parameter": {
"source": "payload",
"name": "ref"
}
}
}
]
}
}
Currently, the production application is available on port 3001 on your server, but if you want to make it accessible from internet under a domain name, you need to serve it with Nginx, outside of the container. The only thing to do is to create a virtual host, proxying port 3001, as below.
You can find some documentation about Nginx installation and use here. Find out here how to install and configure SSL certificates with Certbot.
server {
server_name myproject.francois.poguet.com;
location / {
proxy_pass http://localhost:3001;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/myproject.francois.poguet.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/myproject.francois.poguet.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = myproject.francois.poguet.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name myproject.francois.poguet.com;
return 404; # managed by Certbot
}