The Deployer recipe is part of Deployer 7 and is intended to work for Contao 4.13 and higher.
If not done yet, install Deployer in your project as described in the docs:
composer require --dev deployer/deployer
Verify that you are running Deployer in the minimum version 7.0 by running vendor/bin/dep --version
.
Once done, you can create a deploy.php
file in your project:
touch deploy.php
There are two ways to deploy your project to the remote site. The default approach to deploy files in Deployer is to check out the Git repository with the current project on the remote server.
To get started with Deployer, use the following file contents for the deploy.php
in your project root:
// deploy.php
namespace Deployer;
import('recipe/contao.php');
host('example.org')
->set('remote_user', 'foobar')
->set('deploy_path', '/var/www/{{remote_user}}/html/{{hostname}}')
->set('bin/php', 'php8.1')
->set('bin/composer', '{{bin/php}} /var/www/{{remote_user}}/composer.phar')
;
set('repository', 'git@github.com:acme/example.org.git');
set('keep_releases', 10);
after('deploy:failed', 'deploy:unlock');
Make sure to adjust the host configuration (see the Documentation) and repository URL as required.
The deployment with Git repo has some downsides, though. First, you always need to have your local files committed and
pushed. Second, in case your SSH environments do not support agent forwarding, your remote site needs to have
read-access on the Git repository, which requires storing the HTTPS credentials or configuring SSH. Therefore, another
favored approach is to use rsync
instead of Git to deploy the project.
To use rsync
instead of a Git checkout, we need to override the deploy:update_code
task:
// deploy.php
/* Your existing config from "Option 1" */
// Not needed anymore
//-set('repository', 'git@github.com:acme/example.org.git');
desc('Upload project files');
task('deploy:update_code', function () {
foreach([
'config',
'contao',
'public/layout',
'public/favicon.ico',
'src',
'.env',
'composer.json',
'composer.lock',
] as $src) {
upload($src, '{{release_path}}/', ['options' => ['--recursive', '--relative']]);
}
});
For the sake of completeness, instead of defining every(!) file and folder in upload()
, you can also use the rsync
task. The rsync
task implies an exclude strategy rather than an include strategy. You can find an example and the
contao-rsync.php
recipe here: nutshell-framework/deployer-recipes
As you know from the Contao documentation, you have to set the document root of the server to /public
(or
/web
in older versions) of the project. The idea of Deployer is to provide updates with the shortest possible downtime,
and to realize this, Deployer utilizes rolling symlink releases. Consequently, you have to set the document root of your
vHost to/current/public
(or /current/web
respectively). A full example for the document root might look like
/var/www/foobar/html/example.org/current/public
.
By default, Contao uses the /public
folder of the project as the document root. If your Contao
installation is still using the legacy /web
folder as public directory, please explicitly set it in the composer.json
of the project:
{
"extra": {
"public-dir": "web"
}
}
Often you have some additional build tasks tailored to your project. You can quickly add those tasks to the deployment process:
// deploy.php
/* Your existing config */
// Task to build the assets, i.e., run `yarn run build` on the local machine
desc('Build assets')
task('encore:compile', function () {
runLocally('yarn run build');
});
// Define that the assets should be generated before the project is going to be deployed
before('deploy', 'encore:compile');
You are now all set to run vendor/bin/dep deploy
.
You can use one or many recipes in your project, and you are free to extract logic for your projects into own recipes. Here is a collection of Deployer recipes that might give you an inspiration (and can use as a start for your own recipes):
You can also provide a task to download the Contao Manager on each deploy:
// deploy.php
/* Your existing deploy.php */
before('deploy:publish', 'contao:manager:download');
// Optionally lock the Contao Manager if you don't use the UI
after('contao:manager:download', 'contao:manager:lock');
As Deployer is using a symlink for the document root (as read above), issues might occur with internal caches like the OPCode Caching. Read more here.
To check what caches are in place, you can check the Symfony toolbar (lower right corner) which should show a green tick (✅) for OPCache.
For the caches being in place, this is an example to clear the caches:
// deploy.php
// Add this recipe
require 'contrib/cachetool.php';
host('www.example.com')
// Add this option, change {{hostname}} to the actual URL when the hostname does not match the URL.
->set('cachetool_args', '--web=SymfonyHttpClient --web-path=./{{public_path}} --web-url=https://{{hostname}}')
;
after('deploy:success', 'cachetool:clear:opcache');
// or
after('deploy:success', 'cachetool:clear:apcu');
Deployer only activates the new build when the deployment is without errors. However, when a deployment fails, you might find your deployment in a locked state and the Contao installation in maintenance mode. Therefore, you can unlock the deployment (to allow follow-up deployments) automatically and disable the Contao maintenance mode after failed deployments:
// deploy.php
after('deploy:failed', 'deploy:unlock');
after('deploy:failed', 'contao:maintenance:disable');