Search by

heimrichhannot / deployer-recipes

digitales@heimrich-hannot.de

A Heimrich & Hannot Contao project

Package info

github.com/heimrichhannot/deployer-recipes

pkg:composer/heimrichhannot/deployer-recipes

Statistics

Installs: 1 016

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

2.0.0 2026-09-29 13:12 UTC

README

Deployer recipes used at Heimrich & Hannot GmbH.

Requirements

  • PHP 8.3 or later in the environment you run dep in (e.g. your ddev web container)

Deployer is bundled with this package (see Bundled Deployer), so its dependencies never conflict with your project's.

Projects that cannot use PHP 8.3 yet can stay on version 1.15 of this package, which uses Deployer 7:

composer require --dev heimrichhannot/deployer-recipes:~1.15.0

Note

Deployer 8 rewrote its TYPO3 recipe (own deploy task, optional rsync, different shared and writable directories). Check your deploy.php against the upstream recipe when upgrading a TYPO3 project.

Install

composer require --dev heimrichhannot/deployer-recipes

This installs Deployer as vendor/bin/dep:

php vendor/bin/dep deploy production

Do not require deployer/deployer alongside this package; the two conflict. When upgrading from a version that used it, remove it first:

composer remove --dev deployer/deployer

Bundled Deployer

This package ships the official Deployer phar, verified against the Deployer sign key. The bundled version is recorded in composer.json under extra.deployer.version; vendor/bin/dep --version prints it. extra.deployer.recipes-major names the major version of this package that the default branch releases.

A scheduled workflow bundles new Deployer releases:

Deployer release Release of this package
patch (8.0.5 → 8.0.6) patch, released automatically
minor (8.0.x → 8.1.0) minor, released automatically
major (8 → 9) new major, prepared as a pull request

If the default branch has commits that are not part of the latest release, patch and minor updates arrive as a pull request instead, so the version number can be chosen by hand. Releases are tagged as plain M.m.p (e.g. 2.0.1); other tags don't create a GitHub release and are ignored by the update workflow.

The recipes refuse to run under a Deployer major version other than the bundled one. If you see "requires Deployer 8, but was loaded by Deployer …", run vendor/bin/dep instead of a globally installed dep.

Usage with Contao 4.13+

Create a deploy.php file in your Contao project root directory and customize the following content according to your needs.

<?php # deploy.php

namespace Deployer;

date_default_timezone_set('Europe/Berlin');

import(__DIR__ . '/vendor/heimrichhannot/deployer-recipes/autoload.php');
recipe('contao');

set('rsync_src', __DIR__);

host('www.example.org')
    ->setPort(22)
    ->setRemoteUser('www_data')
    ->set('public_url', 'https://www.example.org')
    ->set('http_user', 'www_data')
    ->set('public_dir', 'public')
    ->set('deploy_path', '/usr/www/users/{{remote_user}}/contao/2026/production')
    ->set('bin/php', 'php84')
    ->set('release_name', static fn (): string => date('y-m-d_H-i-s'))
    /** In case ACL is unavailable, use chmod instead */
    // ->set('writable_mode', 'chmod')
;

set('project_files', [
    'config',
    'contao',
    // 'files/examplefolder', 
    'files/themes',
    'src',
    # 'templates',
    'composer.json',
    'composer.lock',
]);

set('shared_dirs', [
    'assets/images',
    'contao-manager',
    # 'files/maildrum',
    # 'files/media',
    # 'files/social-feed',
    '{{public_path}}/share',
    'var/backups',
    'var/job-attachments',
    'var/logs',
]);

set('shared_files', [
    'config/parameters.yaml',
    '{{public_path}}/.htaccess',
    'system/config/localconfig.php',
    '.env',
    '.env.local',
]);
/** @example Add project-specific files */
add('project_files', [
    'config/routes.yaml',
    'translations',
]);

/** @example Remove values from any variable */
remove('project_files', [
   'files/themes',
   'templates'
]);

/** @example Add project-specific files to exclude from deploy */
add('exclude', [
    '.githooks',
]);

/** @example Add a shared .htpasswd or any other file */
add('shared_files', [
    '{{public_path}}/.htpasswd'
]);

/** @example Ask confirmation before running migrations */
set('ask_confirm_migrate', true);

/** @example Do not create backup on migration */
set('create_db_backup', false);

/** @example Reload PHP-FPM after deployment */
set('reload_php_fcgi', true);

/** @example Don't automatically deploy contao-manager */
set('contao_manager_deploy', false);

/** @example Disable confirmation input when going live */
set('confirm_prod', false);

/** @example Add yarn build task before deploying */
before('deploy', 'ddev:yp');

/** @example Deploy `files/themes`, which are shared and not updated by default */
after('deploy:shared', 'deploy:themes');

/** @example Create symlinks on deployment */
add('symlinks', [
    '{{public_dir}}/example' => '../relative/path/to/target',
]);

/** @example Adjust the number of stored releases */
set('keep_releases', 10);

Setup of multiple hosts or environments

You may set up multiple hosts or environments by using the host() function multiple times. If you do not specify selectors (like labels) when running your deployer commands, you will be asked to choose which hosts to run that command for.

If you want to set common variables for all hosts, use the provided proxy function broadcast(), to call any number of methods on all previously defined hosts.

Important

Make sure to use labels to differentiate between environments when defining multiple hosts.

host('stage')
    ->set('public_url', 'https://stage.example.org')
    ->setLabels(['env' => 'stage'])
;

host('production')
    ->set('public_url', 'https://www.example.org')
    ->setLabels(['env' => 'prod'])
;

broadcast()
    ->setHostname('www.example.org')
    ->setPort(22)
    ->setRemoteUser('www_data')
    ->set('http_user', 'www_data')
    ->set('public_dir', 'public')
    ->set('deploy_path', '/usr/www/users/{{remote_user}}/docroot/{{alias}}')
    ->set('bin/php', 'php82')
    ->set('bin/composer', 'composer')
    ->set('release_name', static fn (): string => date('y-m-d_H-i-s'))
;

Alternatively, you may iterate over all hosts:

foreach (getHosts() as $host) {
    $host
        ->setHostname('www.example.org')
        ->setPort(22)
        ->setRemoteUser('www_data')
        ->set('http_user', 'www_data')
        ->set('public_dir', 'public')
        ->set('deploy_path', '/usr/www/users/{{remote_user}}/docroot/{{alias}}')
        ->set('bin/php', 'php82')
        ->set('bin/composer', 'composer')
        ->set('release_name', static fn (): string => date('y-m-d_H-i-s'))
    ;
}

getHosts() is a shorthand for Deployer::get()->hosts.

Note

This documentation might change in the future as there might be a better way to achieve this. Keep yourself posted.

The alias placeholder

Depending on your setup, you may want to automatically place different environments on the same host in respective directories. You can use the {{alias}} placeholder to differentiate between the hosts' aliases as environment names.

For example:

host('stage') // <- this is the alias
    ->setRemoteUser('www_data')
    ->set('deploy_path', '/usr/www/users/{{remote_user}}/docroot/{{alias}}')
; // will be evaluated to /usr/www/users/www_data/docroot/stage

Utility Commands

Clear the cache on the remote server

dep cache:clear

Clear opcache

dep opcache:clear

If the automatic request fails, for example because the website is protected by HTTP Basic Authentication, the task prints the temporary opcache-clear URL so it can be opened in an authenticated browser. It then asks whether the temporary file should be deleted.

Deploy assets only (encore build folder)

dep deploy:assets

Database actions

Action Command
Clone remote database to local
dep db:pull
Push local database to remote
dep db:push
Export remote database
dep db:export:remote
Export local database
dep db:export:local
Import database on remote
dep db:import:remote
Import database locally
dep db:import:local

You may alternatively use its alias dep db:clone for dep db:pull.

Exclude tables from db:pull

By default, dep db:pull with mysql dump mode excludes volatile Contao tables such as logs, search indexes and queues from the downloaded database dump if they exist in the remote database.

You can configure the excluded tables in your deployment script:

set('db_pull_excluded_tables', [
    'tl_log',
    'tl_search',
    'tl_search_index',
]);

To disable table exclusions, set an empty list:

set('db_pull_excluded_tables', []);

What to do when mysql or mysqldump is unavailable

You can change the pull and push commands to use the contao:backup commands instead of mysql and mysqldump:

set('db_dump_mode', 'contao');

Note

This will only work if your local and remote databases are compatible.

Contao-Manager automated Deployment

Contao-Manager is set to deploy automatically by default. If you prefer to disable this automatic deployment, you can configure the following variable in your deployment script:

set('contao_manager_deploy', false);

Contao-Manager will download the latest version of the Contao-Manager phar file and deploy it to {{deploy_path}}/shared/{{public_dir}}/contao-manager.phar.php. After that, it will be symlinked to {{release_or_current_path}}/{{public_dir}}/contao-manager.phar.php.

If it already exists, it will perform a self-update.

Conditional Deployment

Automated deployment of Contao-Manager will not proceed if there is a file named contao-manager.phar.php present in your shared_files.

An example in which automated deployment is skipped:

add('shared_files', [
    '{{public_path}}/contao-manager.phar.php',
]);

This way, if you don't want the remote host to automatically fetch Contao-Manager from the internet, you can set up your shared files accordingly and don't need to touch contao_manager_deploy.

Sourcing Contao-Manager from a different location

If you want to change the source URL of contao-manager.phar, e.g., if you host your own Contao-Manager mirror, you can set the following variable:

// this is the default value
set('contao_manager_source', 'https://download.contao.org/contao-manager/stable/contao-manager.phar');

Adding Symlinks

You can add symlinks to your deployment by using the symlinks configuration variable.

add('symlinks', [
    'path/to/link' => '../relative/path/to/target',
    '{{public_dir}}/example' => '../relative/path/to/another/target',
]);

The link path is relative to the {{release_or_current_path}} directory.

To regenerate symlinks after deployment, you can use the following command:

dep deploy:symlinks

Work in Progress

These templates are still work in progress and not yet fully implemented. Use with caution or not at all.

/** WIP: Deploy an htaccess file which will be renamed to .htaccess */
set('htaccess_filename', '.htaccess.prod');
after('deploy:shared', 'deploy:htaccess');