Deploying a Symfony 4 application with Ansible
Hey! Did you tried to deploy your Symfony 4 app with Ansible and it didn’t work? I’ve already wrote about how to do this for Symfony 2 and 3. So, in this story, I’m going to tell you just the things you need to change. Please, read my previous Ansible story and then come back and continue reading.
Symfony 4 changes
Ok, this is not a “changelog”. I just want to to tell you the main change that is crashing your deployments: no more parameters.yml. Well, you can create the file and it will work, but you should use environment variables for, at least, infrastructure settings such as database credentials.
So, how is this working? When your environment is dev, the dotenv component should be working (require-dev). This will load a .env
file with your variables and the process should be almost like in Symfony 2 and 3. But, dotenv won’t be loaded in prod. This means: your webserver won’t know how to connect to your database, nor the console will know the environment, and so on. How should you fix that?
Solution 1: move dotenv from require-dev to require. This is not an antipattern, feel free to do it!
Solution 2.1: for an Apache webserver, you must load the variables in your VirtualHost configuration:
<VirtualHost *:80>
#...
#SetEnv APP_ENV prod
#SetEnv APP_SECRET <app-secret-id>
#SetEnv DATABASE_URL "mysql://username:p4ssw0rd@host:3306/database"
</VirtualHost>
For the console, you have two different approaches:
- 2.2a — Prepend the needed environment variables, such as
APP_ENV=prod bin/console command:execute
. - 2.2b — Load the environment variables from a file.
The 2.2b solution works like a .bashrc
file, exporting the needed variables. We are going to use this solution to fix our Ansible deployment.
Ansible configuration changes
Remember to read this story first. Have you read it? Ok, let’s continue.
First of all, the deploy.yml
file changes:
var/logs
is nowvar/log
- No need for
ansistrano_shared_files
(we won’t have a parameters file) - The
symfony_run_doctrine_migrations
should be false because it’s not using environment variables and it fails (at this moment!) - At the end of the file, add the
environment
section:
environment:
APP_ENV: "{{ sf_env }}"
BASE_URL: "{{ sf_base_url }}"
HOST: "{{ sf_host }}"
SCHEME: "{{ sf_scheme }}"
As you see, I won’t write here the database credentials, because they will be committed, and we don’t want our credentials on git, do we?
Let’s add those needed variables. For example, edit the group_vars/prod
file:
#...
sf_env: prod
sf_base_url: /
sf_host: project.com
sf_scheme: http
Then, check all your defined tasks and remove the SYMFONY_
environment variables because they are not working anymore.
Last step: database migrations. All this works like a charm, but we won’t have our database credentials for the console commands, and we definitely don’t want our credentials in the group vars files. So, go to your shared folder in your destination server and create a .env
file there. Write there the exporting lines, and remember to prepend them with the export
keyword. For example:
export DATABASE_URL=mysql://username:p4ssw0rd@127.0.0.1:3306/database
We just have to source that file and the execute the needed commands. This is my before-symlink-tasks-file.yml
file (remember to include it in your deploy.yml
file!):
---
- name: Run doctrine migrations
shell: chdir={{ansistrano_release_path.stdout}}
source {{ansistrano_shared_path}}/.env && {{symfony_php_path}} {{symfony_console_path}} doctrine:migrations:migrate --no-interaction
That’s all, enjoy your Symfony 4 project!