Part 1/2 - Deploying Symfony 4 with rsync

We've covered setting up a basic LAMP and LEMP stack for Symfony 4, and seen how this involves working with environment variables. We've also covered the demo project we will be using for all of our Symfony 4 deployment examples. Now it's time to deploy Symfony 4.

To begin with, we will use rsync.

Our initial rsync deployment is as basic as can be, and likely wouldn't be suitable for a real world project. Consider this your starting point, and in the next two videos we will explore ways to make this process more robust, and ultimately, more real world.

In order to deploy our project, we are going to start by creating our first "build".

In reality, this Symfony project build is nothing more than running a composer install without the development dependencies. As we are going into production at this point, we should have no need for anything only required in development. This might be the local web server, or our test suite, or in the case of a fresh Symfony 4 installation, the symfony/dotenv package.

Our First Symfony 4 Build

Our first build is simple:

composer install --no-dev --optimize-autoloader

# if you encounter any issues, try:
export APP_ENV=prod composer install --no-dev --optimize-autoloader

The theory goes that we shouldn't need access to any development dependencies from our production environment (--no-dev), and so anything in the composer.json file under require-dev won't be downloaded.

We covered optimize-autoloader [in this video.][8]

Ok, so is everything good and ready to go?

Well, let's try our deploy and find out.

rsync --exclude '.git' --exclude=.env --exclude=var -avzh \
  . \

Note: As has been covered during the LAMP and LEMP tutorials, I am uploading as root user. In reality you would not do this. Please adapt accordingly.

This shouldn't take too long, depending on your upload speed. Symfony 4 is slimmer than Symfony 3.

Notice that we have excluded the .git and var directories as before.

We have already configured the var directory with the correct permissions.

New is the exclusion of the local .env file, by adding --exclude=.env to the command.

At present the Symfony deployment guide is really vague about the .env file.

Here's some extra info I found whilst reading the docs for the [DotEnv component][9]:

You should never store a .env file in your code repository as it might contain sensitive information; create a .env.dist file with sensible defaults instead.

Symfony Dotenv should only be used in development/testing/staging environments. For production environments, use "real" environment variables.

This is why we spent the time adding in environment variables to our Apache / nginx configurations before hand.

Are We There Yet?

Amazingly, we aren't far off at this point.

There's three further steps we need to take:

  1. Sort out permissions
  2. Kick start the database
  3. Clear and warmup the Symfony cache

Sorting out the permissions issues should be a one liner:

# from your server
sudo chown -R www-data:www-data /var/www/

This recursively changes the owning user and group of each file and folder to the user www-data, and the group www-data.

Whether using Apache or nginx, on Ubuntu our web server user will be www-data, so this should give the required permissions for access.

Next, sorting out the database is specific to this project.

We need to run three commands:

# from your server
cd /var/www/

php bin/console doctrine:database:create
php bin/console doctrine:schema:create
php bin/console doctrine:fixtures:load

And like in Symfony 2 or Symfony 3, clearing and warming the cache is required:

php bin/console cache:clear --no-warmup
php bin/console cache:warmup

And that's it.

This should feel very similar to a Symfony 2 or Symfony 3 project deploy. The primary difference is in the use of environment variables. Also, there are a few ways this approach is less likely to give you errors or problems - particularly around the php bin/console doctrine:... commands.

Overall though, not hugely different to what you may already know and use.

Why This Approach Is Too Basic

The problem in this approach is in our rsync command.

We're copying all the files and folders from our local computer, right over the top of any existing files and folders on the server.

This becomes a problem beyond the very first time we run this command.

Any subsequent runs are going to affect the files and folders being actively used by Apache or nginx to serve real visitors.

This means if a file is being accessed by someone whilst we are also updating that file, they may encounter very odd errors. Refreshing their page may hopefully fix it. But worse, any new files and folders are going to have the wrong permissions. This is less obvious, especially on subsequent deploys.

If you'd like to read more on this then I've covered this already in this video write up under the section "Is rsync Risky?".

In this instance, I'm going to consider our deployment done. But in the next two videos we will improve on this process to remove this problem.

Code For This Video

Get the code for this video.