Deployer es una herramienta de deploy para PHP escrita en PHP. Se instala globalmente o como dependencia de Composer y permite definir tareas de despliegue en un fichero deploy.php. Gestiona el sistema de releases y symlinks de forma automática, lo que hace que los rollbacks sean instantáneos.
Instalación
# Como dependencia de Composer (recomendado para proyectos)
composer require --dev deployer/deployer
# O como phar global
curl -LO https://deployer.org/deployer.phar
mv deployer.phar /usr/local/bin/dep
chmod +x /usr/local/bin/dep
Estructura de releases en el servidor
/var/www/mi-app/
??? current/ ? symlink al release activo
??? releases/
? ??? 1/ (release anterior)
? ??? 2/ (release actual, current apunta aquí)
??? shared/ ? ficheros compartidos entre releases
??? .env
??? storage/
Fichero deploy.php básico
<?php
namespace Deployer;
require 'recipe/common.php';
// Configuración del proyecto
set('application', 'mi-app');
set('repository', '[email protected]:mi-usuario/mi-app.git');
set('git_tty', false);
set('keep_releases', 5); // cuántos releases guardar para rollback
// Ficheros y directorios compartidos entre releases
set('shared_files', ['.env']);
set('shared_dirs', ['storage/logs', 'storage/uploads']);
set('writable_dirs', ['storage/logs', 'storage/uploads', 'bootstrap/cache']);
// Definición de hosts
host('produccion')
->setHostname('tu-servidor.com')
->setRemoteUser('deploy')
->setIdentityFile('~/.ssh/id_rsa')
->set('deploy_path', '/var/www/mi-app')
->set('branch', 'main');
host('staging')
->setHostname('staging.tu-servidor.com')
->setRemoteUser('deploy')
->set('deploy_path', '/var/www/mi-app-staging')
->set('branch', 'develop');
// Tareas personalizadas
task('composer:install', function () {
run('cd {{release_path}} && {{bin/composer}} install --no-dev --optimize-autoloader --no-interaction');
});
task('artisan:migrate', function () {
run('cd {{release_path}} && php artisan migrate --force');
});
task('php-fpm:reload', function () {
run('sudo systemctl reload php8.3-fpm');
});
// Pipeline de deploy: orden de ejecución
desc('Deploy de mi-app');
task('deploy', [
'deploy:info',
'deploy:setup',
'deploy:lock',
'deploy:release',
'deploy:update_code',
'deploy:shared',
'deploy:writable',
'composer:install',
'artisan:migrate',
'deploy:symlink',
'php-fpm:reload',
'deploy:unlock',
'deploy:cleanup',
'deploy:success',
]);
// En caso de fallo, desbloquear y hacer rollback
after('deploy:failed', 'deploy:unlock');
Ejecutar el deploy
# Deploy a producción
dep deploy produccion
# Deploy a staging
dep deploy staging
# Ver qué haría sin ejecutar nada
dep deploy produccion --dry-run
# Deploy con verbose (ver cada comando)
dep deploy produccion -vvv
Rollback en segundos
Deployer mantiene los últimos N releases (configurado con keep_releases). Un rollback solo cambia el symlink current al release anterior:
# Volver al release anterior
dep rollback produccion
# Ver los releases disponibles
dep releases produccion
Tareas custom con hooks
<?php
// Limpiar caché de OPcache tras desplegar
task('opcache:clear', function () {
run('php -r "if (function_exists("opcache_reset")) { opcache_reset(); echo "OPcache limpiadan"; }"');
});
after('deploy:symlink', 'opcache:clear');
// Notificar a Slack tras deploy exitoso
task('notify:slack', function () {
$host = currentHost()->getAlias();
$release = get('release_name');
$webhook = getenv('SLACK_WEBHOOK');
run("curl -s -X POST '$webhook' -d '{"text":"Deploy $release a $host completado"}'");
});
after('deploy:success', 'notify:slack');
// Crear enlace simbólico personalizado en shared
task('setup:env', function () {
if (!test('[ -f {{deploy_path}}/shared/.env ]')) {
run('cp {{release_path}}/.env.example {{deploy_path}}/shared/.env');
writeln('?? Recuerda editar /shared/.env con las credenciales de producción');
}
});
before('deploy:shared', 'setup:env');
Configuración por entorno
<?php
// Variables distintas por host
host('produccion')
->set('branch', 'main')
->set('deploy_path', '/var/www/prod')
->set('opcache_reset_file', '/var/www/prod/current/public/opcache_reset.php');
host('staging')
->set('branch', 'develop')
->set('deploy_path', '/var/www/staging')
->set('opcache_reset_file', '/var/www/staging/current/public/opcache_reset.php');
// Leer la variable en la tarea
task('opcache:http', function () {
$url = 'https://' . currentHost()->getHostname() . '/opcache_reset.php';
run("curl -s '$url'");
});
Ventajas sobre un deploy manual
- Cero downtime: el symlink se cambia solo cuando todo está listo; las peticiones siguen sirviendo el release anterior hasta ese momento.
- Rollback en segundos: volver al release anterior es cambiar un symlink, no redeployar.
- Reproducible: el mismo fichero
deploy.phpproduce siempre el mismo proceso. - Historial: cada release queda guardado con su timestamp para auditoría.
