Despliegue automático con Deployer.org para cualquier app

Deployer.org es una potente herramienta de despliegue escrita en PHP que automatiza el proceso de llevar tus aplicaciones a servidores.

Este manual te guiará a través del proceso, destacando los puntos clave y posibles desafíos, así como ejemplificando el despligue de dos apps ejemplo, una en WordPress y otra usando Laravel.

Ventajas de usar Deployer:

  • Automatización: Reduce tareas manuales y propensas a errores.
  • Despliegues Zero-Downtime: Mediante el uso de symlinks, tu sitio permanece online durante la actualización.
  • Rollbacks: Permite revertir a una versión anterior fácilmente si algo sale mal.
  • Recetas predefinidas: Incluye configuraciones base para frameworks populares como Laravel y WordPress.
  • Consistencia: Asegura que el proceso de despliegue sea el mismo cada vez.
  • Entornos de staging: Permite crear automáticamente dominios y bases de datos para pruebas.

No todos los servicios de hosting con cPanel serán compatibles o adecuados para Deployer. En nuestro caso, todos nuestros servicios de hosting lo son, por lo que podrás usarlo sin mayor problema.

Acceso SSH

El acceso SSH es esencial para trabajar con Deployer.org, por ello lo primero es revisar que lo tienes activo en tu cuenta:

Y por otro que has configurado tu equipo para conectar por medio de claves, lo que facilitará el uso (puedes conectar vía contraseña, pero tendrás que estar de forma continua introduciendo la misma):

Instalación de Deployer

Antes de configurar el archivo de despliegue, necesitas instalar Deployer en tu máquina local. Puedes hacerlo de varias formas:

Opción 1: Instalación global con Composer

composer global require deployer/deployer

Opción 2: Descarga directa del PHAR

curl -LO https://deployer.org/deployer.phar
mv deployer.phar /usr/local/bin/dep
chmod +x /usr/local/bin/dep

Opción 3: Como dependencia del proyecto

composer require --dev deployer/deployer

Una vez instalado, verifica que funciona ejecutando:

dep --version

Configuración Básica del Archivo deploy.php

Para comenzar, necesitas crear un archivo deploy.php en la raíz de tu proyecto local. Este archivo contendrá toda la configuración necesaria para conectar con tu servidor cPanel y definir las tareas de despliegue.

Una vez configurado, podrás ejecutar comandos como:

  • dep deploy - Para desplegar tu aplicación
  • dep rollback - Para revertir al despliegue anterior
  • dep pwd - Para verificar la conexión y ver el directorio actual
  • dep ls - Para listar archivos en el servidor
<?php
namespace Deployer;

require 'recipe/common.php'; 

set('shared_files', []);
set('shared_dirs', []);
set('writable_dirs', []);

set('ssh_multiplexing', false); 
set('git_ssh_command', 'ssh');

host('tu_dominio_o_ip_cpanel')
    ->set('remote_user', 'tu_usuario_cpanel') 
    ->set('port', 93)
    ->set('identity_file', '~/.ssh/id_rsa_cpanel') // Ruta a tu clave privada para cPanel
    ->set('deploy_path', '/home/tu_usuario_cpanel/ruta_despliegue') // IMPORTANTE: Ruta base para Deployer
    ->set('http_user', 'tu_usuario_cpanel'); // Usuario bajo el cual corre el servidor web

// Tareas
task('pwd', function () {
    $result = run('pwd');
    writeln("Current directory: {$result}");
});

task('ls', function () {
    $result = run('ls -la');
    writeln("{$result}");
});

// Notificar al final
after('deploy:failed', 'deploy:unlock');

Explicación de Parámetros Clave para cPanel:

  • remote_user: Tu nombre de usuario de cPanel (el que usas para SSH).
  • identity_file: La ruta en tu máquina local a la clave SSH privada que configuraste para cPanel.
  • deploy_path: Esta es la ruta en el servidor cPanel donde Deployer creará su estructura (releases, shared, current). No pongas esto directamente en public_html inicialmente. Es mejor una carpeta separada, por ejemplo: /home/tu_usuario_cpanel/my_laravel_app o /home/tu_usuario_cpanel/my_wordpress_site.
  • http_user: El usuario con el que Apache/LiteSpeed ejecuta los scripts PHP. El mismo que tu usuario de cPanel.

Para comprobar que funciona correctamente, puedes ejecutar dep ls lo que debería devolver el listado de ficheros y durectorios del servicio de hosting.

Importante: Diferencias entre Dominios en cPanel

Antes de continuar, es crucial entender las diferencias entre tipos de dominios en cPanel:

  • Dominio Principal: Es el dominio asociado a tu cuenta de hosting. Su DocumentRoot está forzado a ser /home/tu_usuario_cpanel/public_html y no se puede cambiar. Si quieres usar Deployer con el dominio principal, necesitarás usar el método de symlink.

  • Dominios Addon (Adicionales): Son dominios extra que puedes agregar a tu cuenta. Estos SÍ permiten cambiar el DocumentRoot a cualquier directorio que desees, incluso fuera de public_html. Con dominios addon, puedes apuntar directamente a {{deploy_path}}/current.

  • Subdominios: Generalmente funcionan como los dominios addon y permiten cambiar el DocumentRoot libremente.

Recomendación: Si planeas usar Deployer intensivamente, considera usar un dominio addon en lugar del dominio principal para evitar las limitaciones de public_html.

Configuración Avanzada con cPanel Recipe

Deployer incluye una receta específica para cPanel que automatiza la creación de dominios addon y bases de datos, especialmente útil para entornos de staging. Esta funcionalidad utiliza la API de cPanel v2 para gestionar recursos automáticamente.

Configuración de la Receta cPanel

<?php
namespace Deployer;

require 'recipe/common.php';

require 'contrib/cpanel.php';

set('cpanel', [
    'host' => getenv('CPANEL_HOST'),
    'port' => getenv('CPANEL_PORT'),
    'username' => getenv('CPANEL_USERNAME'),
    'auth_type' => getenv('CPANEL_AUTH_TYPE'),
    'token' => getenv('CPANEL_TOKEN'),
    'user' => getenv('CPANEL_USER'),
    'db_user' => getenv('CPANEL_DB_USER'),
    'db_user_privileges' => getenv('CPANEL_DB_PRIVILEGES'),
    'timeout' => 500,
    'allowInStage' => ['staging', 'beta', 'alpha'],
    'create_domain_format' => '%s-%s-%s',
    'create_domain_values' => ['staging', 'master', get('application')],
    'subdomain_prefix' => substr(md5(get('application')), 0,4) . '-',
    'subdomain_suffix' => getenv('SUBDOMAIN_SUFFIX'),
    'create_db_format' => '%s_%s-%s-%s',
    'create_db_values' => ['apps', 'staging','master', get('application')],
]);

Variables de Entorno para cPanel API

Crea un archivo .env en tu proyecto local con las credenciales de cPanel:

CPANEL_HOST=tu_servidor_cpanel.com
CPANEL_PORT=2083
CPANEL_USERNAME=tu_usuario_cpanel
CPANEL_TOKEN=tu_token_api_cpanel
CPANEL_USER=tu_usuario_cpanel
CPANEL_AUTH_TYPE=hash
CPANEL_DB_USER=usuario_db
CPANEL_DB_PRIVILEGES="ALL PRIVILEGES"
SUBDOMAIN_SUFFIX=.tudominio.com

Tareas Disponibles de cPanel

La receta de cPanel proporciona las siguientes tareas automáticas:

  • cpanel:createaddondomain: Crea un dominio addon automáticamente
  • cpanel:deleteaddondomain: Elimina un dominio addon
  • cpanel:createdb: Crea una nueva base de datos

Configuración de Staging Automático

host('staging.tudominio.com')
    ->stage('staging')
    ->set('cpanel_createdb', vsprintf(get('cpanel')['create_db_format'], get('cpanel')['create_db_values']))
    ->set('branch', 'develop')
    ->set('deploy_path', '~/staging/' . vsprintf(get('cpanel')['create_domain_format'], get('cpanel')['create_domain_values']))
    ->set('addondir', 'staging/' . vsprintf(get('cpanel')['create_domain_format'], get('cpanel')['create_domain_values']));

// Automatizar la creación de recursos en staging
after('deploy:prepare', 'cpanel:createaddondomain');
after('deploy:prepare', 'cpanel:createdb');

Despliegue de WordPress con Deployer en cPanel

Configuración para WordPress

<?php
namespace Deployer;

require 'recipe/wordpress.php'; // Receta específica para WordPress
require 'recipe/common.php';    // Siempre necesaria

// Configuración General (Adaptar si es necesario)
set('application', 'MiWordPress');
set('repository', 'git@github.com:tu_usuario/tu_repo_wordpress.git'); // URL de tu repositorio Git

// Archivos y directorios compartidos específicos de WordPress
set('shared_files', ['wp-config.php']); // wp-config.php se gestiona en 'shared'
set('shared_dirs', ['wp-content/uploads']); // Carpeta de subidas es compartida

// Directorios con permisos de escritura
set('writable_dirs', ['wp-content/uploads']);

// Host (Adaptar a tu configuración de cPanel)
host('tu_dominio_o_ip_cpanel')
    ->set('remote_user', 'tu_usuario_cpanel')
    ->set('port', 93)
    ->set('identity_file', '~/.ssh/id_rsa_cpanel')
    ->set('deploy_path', '/home/tu_usuario_cpanel/mi_wordpress_deploy') // Carpeta base para este sitio WP
    ->set('http_user', 'tu_usuario_cpanel');

// Tareas personalizadas (si son necesarias)
// Ejemplo: Si WP-CLI no está global, podrías necesitar definir su ruta
// set('bin/wp', '/home/tu_usuario_cpanel/wp-cli.phar');

// Configurar DocumentRoot en cPanel
// Debes configurar el DocumentRoot de tu dominio/subdominio en cPanel
// para que apunte a: /home/tu_usuario_cpanel/mi_wordpress_deploy/current
// Si no puedes cambiar el DocumentRoot, necesitarás un .htaccess en public_html (ver sección abajo)

// Notificar al final
after('deploy:failed', 'deploy:unlock');
desc('Deploy WordPress');
task('deploy', [
    'deploy:prepare',
    'deploy:vendors', // Si usas composer para gestionar WordPress o plugins
    'deploy:shared',
    'deploy:writable',
    'deploy:publish',
]);

Preparación en cPanel

Base de Datos: Crea una base de datos y un usuario para WordPress usando las herramientas de "MySQL Databases" en cPanel. Anota el nombre de la base de datos, el usuario y la contraseña.

Directorio de Despliegue: Asegúrate de que la ruta que especificaste en deploy_path (ej. /home/tu_usuario_cpanel/mi_wordpress_deploy) exista o que Deployer tenga permisos para crearla.

wp-config.php inicial:

  • Conéctate por SSH a tu servidor.
  • Navega a {{deploy_path}}/shared (ej. /home/tu_usuario_cpanel/mi_wordpress_deploy/shared). Si no existe, créalo: mkdir -p /home/tu_usuario_cpanel/mi_wordpress_deploy/shared.
  • Crea un archivo wp-config.php dentro de shared con los datos de la base de datos de cPanel y las sales de WordPress. Puedes copiar un wp-config-sample.php y modificarlo.
<?php
define('DB_NAME', 'tu_basedatos_cpanel');
define('DB_USER', 'tu_usuario_db_cpanel');
define('DB_PASSWORD', 'tu_contraseña_db_cpanel');
define('DB_HOST', 'localhost'); // Usualmente localhost en cPanel
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', '');

// Sales de WordPress (generarlas desde https://api.wordpress.org/secret-key/1.1/salt/)
define('AUTH_KEY',         'pon_tu_sal_aqui');
// ... (resto de sales) ...
define('NONCE_SALT',       'pon_tu_sal_aqui');

$table_prefix = 'wp_'; // O el prefijo que desees

define('WP_DEBUG', false);

if ( ! defined( 'ABSPATH' ) ) {
        define( 'ABSPATH', __DIR__ . '/' );
}
require_once ABSPATH . 'wp-settings.php';

Configurar DocumentRoot:

  • En cPanel, ve a "Dominios".
  • Para dominios addon (adicionales): Puedes cambiar fácilmente el DocumentRoot para que apunte a /home/tu_usuario_cpanel/mi_wordpress_deploy/current. Los dominios addon no están restringidos a public_html.
  • Para el dominio principal: Está forzado a usar public_html como DocumentRoot. En este caso, utiliza el método de symlink que se explica más adelante.
  • Para subdominios: Generalmente puedes cambiar el DocumentRoot, similar a los dominios addon.

Ejecutar el Despliegue

Desde tu máquina local, en la terminal, navega a la raíz de tu proyecto WordPress (donde está deploy.php) y ejecuta:

dep deploy

Si todo va bien, Deployer clonará tu repositorio, instalará dependencias (si aplica), creará los symlinks para wp-config.php y uploads, y finalmente apuntará el symlink current a la nueva release.

Importante: Este método solo es necesario para el dominio principal de tu cuenta cPanel, que está forzado a usar public_html. Los dominios addon y subdominios pueden cambiar directamente su DocumentRoot sin necesidad de symlinks.

Si tu dominio principal no puede cambiar el DocumentRoot en cPanel, la mejor solución es crear un symlink desde public_html hacia tu directorio de despliegue. Esto se puede automatizar desde Deployer:

Pasos:

  1. Configura tu deploy_path fuera de public_html, por ejemplo: /home/tu_usuario_cpanel/mi_wordpress_deploy

  2. Agrega esta tarea personalizada a tu deploy.php:

// Tarea para crear symlink de public_html
task('cpanel:symlink:public_html', function () {
    $publicHtmlPath = '/home/{{remote_user}}/public_html';
    $deployCurrentPath = '{{deploy_path}}/current';
    
    // Verificar si public_html existe y no es ya un symlink
    if (test("[ -d $publicHtmlPath ] && [ ! -L $publicHtmlPath ]")) {
        // Hacer backup del public_html original
        run("mv $publicHtmlPath {$publicHtmlPath}_backup_" . date('Y-m-d_H-i-s'));
        writeln("✅ Backup de public_html creado");
    } elseif (test("[ -L $publicHtmlPath ]")) {
        // Si ya es un symlink, eliminarlo
        run("rm $publicHtmlPath");
        writeln("✅ Symlink anterior eliminado");
    }
    
    // Crear el nuevo symlink
    run("ln -s $deployCurrentPath $publicHtmlPath");
    writeln("✅ Symlink de public_html creado correctamente");
})->desc('Crear symlink de public_html hacia current');

// Ejecutar después de deploy:symlink
after('deploy:symlink', 'cpanel:symlink:public_html');
  1. Importante: Antes del primer despliegue, conecta por SSH y asegúrate de hacer backup manual de tu public_html actual:
cd /home/tu_usuario_cpanel
mv public_html public_html_backup_manual
  1. Ahora cuando ejecutes dep deploy, Deployer automáticamente:
    • Hará el backup de public_html (si existe)
    • Creará un symlink desde public_html hacia {{deploy_path}}/current
    • Tu sitio servirá desde el directorio de despliegue actual

Ventajas de este método:

  • Despliegues zero-downtime reales
  • No requiere cambios en el servidor web
  • Funciona con cualquier proveedor de cPanel
  • Los rollbacks funcionan instantáneamente
  • No hay problemas de rutas como con .htaccess

Tareas Post-Despliegue

  • Accede a tu sitio WordPress para completar la instalación si es la primera vez (ej. tudominio.com/wp-admin/install.php).
  • Verifica que los permisos en wp-content/uploads permitan subir archivos.

Despliegue de Laravel con Deployer en cPanel

Configuración para Laravel

<?php
namespace Deployer;

require 'recipe/laravel.php'; // Receta específica para Laravel
require 'recipe/common.php';  // Siempre necesaria

// Configuración del proyecto
set('application', 'MiLaravelApp');
set('repository', 'git@github.com:tu_usuario/tu_repo_laravel.git'); // URL de tu repositorio Git
set('php_fpm_service', ''); // En cPanel no gestionamos PHP-FPM directamente así

// Hosts (Adaptar a tu configuración de cPanel)
host('tu_dominio_o_ip_cpanel')
    ->set('remote_user', 'tu_usuario_cpanel')
    ->set('port', 93) 
    ->set('identity_file', '~/.ssh/id_rsa_cpanel')
    ->set('deploy_path', '/home/tu_usuario_cpanel/mi_laravel_deploy') // Carpeta base para esta app Laravel
    ->set('http_user', 'tu_usuario_cpanel');

// Tarea para symlinkear el storage (si no lo hace la receta por defecto correctamente en cPanel)
task('artisan:storage:link:manual', function () {
    writeln("Recordatorio: Asegúrate que el enlace simbólico de 'storage' está correctamente configurado y accesible.");
    writeln("Si usas la receta de Laravel, debería intentar crear 'current/public/storage' -> 'shared/storage/app/public'.");
    writeln("Verifica que tu DocumentRoot en cPanel apunte a 'current/public'.");
});

// Configurar DocumentRoot en cPanel
// Debes configurar el DocumentRoot de tu dominio/subdominio en cPanel
// para que apunte a: /home/tu_usuario_cpanel/mi_laravel_deploy/current/public

// Tareas principales de despliegue
after('deploy:failed', 'deploy:unlock'); // Desbloquear en caso de fallo
desc('Deploy Laravel application');
task('deploy', [
    'deploy:prepare',
    'deploy:vendors', // Instalar dependencias de Composer
    'deploy:shared',  // Crear symlinks para archivos/directorios compartidos (ej. .env, storage)
    'artisan:storage:link', // Crear el symlink de storage
    'artisan:view:cache',   // Cachear vistas (opcional, pero recomendado en prod)
    'artisan:config:cache', // Cachear configuración (opcional, pero recomendado en prod)
    'artisan:migrate',      // Ejecutar migraciones (¡CUIDADO! Asegúrate de que el .env es correcto)
    'deploy:publish', // Publicar la nueva release (symlink current y cleanup)
]);

// Tareas adicionales
task('artisan:migrate:fresh:seed', function () {
    run("{{bin/php}} {{release_path}}/artisan migrate:fresh --seed --force");
})->desc('Run fresh migrations with seed');

Preparación en cPanel

Base de Datos: Crea una base de datos y un usuario MySQL en cPanel.

Directorio de Despliegue: /home/tu_usuario_cpanel/mi_laravel_deploy.

Archivo .env inicial:

  • Conéctate por SSH y navega a {{deploy_path}}/shared (ej. /home/tu_usuario_cpanel/mi_laravel_deploy/shared). Si no existe, créalo: mkdir -p /home/tu_usuario_cpanel/mi_laravel_deploy/shared.
  • Crea un archivo .env en shared con la configuración de tu entorno de cPanel:
APP_NAME="Mi App Laravel"
APP_ENV=production
APP_KEY= # Genera una con php artisan key:generate localmente y pégala aquí
APP_DEBUG=false
APP_URL=https://tudominio.com

LOG_CHANNEL=stack
LOG_LEVEL=error # O 'debug' mientras configuras

DB_CONNECTION=mysql
DB_HOST=127.0.0.1 # O el host de DB que te de cPanel (suele ser localhost)
DB_PORT=3306
DB_DATABASE=tu_basedatos_cpanel
DB_USERNAME=tu_usuario_db_cpanel
DB_PASSWORD=tu_contraseña_db_cpanel

# ... otras configuraciones (cache, session, mail) adaptadas a cPanel
# Por ejemplo, para el email, usa los datos SMTP de tu cuenta de cPanel si es necesario.
# CACHE_DRIVER=file
# SESSION_DRIVER=file
# SESSION_LIFETIME=120
# QUEUE_CONNECTION=sync # En shared hosting, las colas complejas pueden no funcionar bien

IMPORTANTE APP_KEY: Genera una llave localmente con php artisan key:generate --show y pégala en el .env del servidor. No dejes esto vacío.

Configurar DocumentRoot:

  • En cPanel, ve a "Dominios".
  • Para dominios addon (adicionales): Puedes cambiar fácilmente el DocumentRoot para que apunte a /home/tu_usuario_cpanel/mi_laravel_deploy/current/public. Los dominios addon no están restringidos a public_html.
  • Para el dominio principal: Está forzado a usar public_html como DocumentRoot. En este caso, utiliza el método de symlink que se explica más adelante.
  • Para subdominios: Generalmente puedes cambiar el DocumentRoot, similar a los dominios addon.

Ejecutar el Despliegue

Desde tu máquina local, en la terminal, navega a la raíz de tu proyecto Laravel y ejecuta:

dep deploy

Deployer intentará:

  • Clonar el repositorio.
  • Instalar dependencias con Composer (deploy:vendors).
  • Crear el symlink para .env y el directorio storage (deploy:shared).
  • Crear el symlink de public/storage (artisan:storage:link).
  • Ejecutar migraciones (artisan:migrate). ¡Asegúrate de que la base de datos y el .env son correctos antes de esto!
  • Publicar la release.

Importante: Este método solo es necesario para el dominio principal de tu cuenta cPanel, que está forzado a usar public_html. Los dominios addon y subdominios pueden cambiar directamente su DocumentRoot sin necesidad de symlinks.

Si tu dominio principal no puede cambiar el DocumentRoot en cPanel, la mejor solución es crear un symlink desde public_html hacia el directorio public de tu despliegue Laravel:

Pasos:

  1. Configura tu deploy_path fuera de public_html, por ejemplo: /home/tu_usuario_cpanel/mi_laravel_deploy

  2. Agrega esta tarea personalizada a tu deploy.php:

// Tarea para crear symlink de public_html hacia Laravel public
task('cpanel:symlink:public_html', function () {
    $publicHtmlPath = '/home/{{remote_user}}/public_html';
    $laravelPublicPath = '{{deploy_path}}/current/public';
    
    // Verificar si public_html existe y no es ya un symlink
    if (test("[ -d $publicHtmlPath ] && [ ! -L $publicHtmlPath ]")) {
        // Hacer backup del public_html original
        run("mv $publicHtmlPath {$publicHtmlPath}_backup_" . date('Y-m-d_H-i-s'));
        writeln("✅ Backup de public_html creado");
    } elseif (test("[ -L $publicHtmlPath ]")) {
        // Si ya es un symlink, eliminarlo
        run("rm $publicHtmlPath");
        writeln("✅ Symlink anterior eliminado");
    }
    
    // Crear el nuevo symlink hacia la carpeta public de Laravel
    run("ln -s $laravelPublicPath $publicHtmlPath");
    writeln("✅ Symlink de public_html hacia Laravel public creado correctamente");
})->desc('Crear symlink de public_html hacia Laravel public');

// Ejecutar después de deploy:symlink
after('deploy:symlink', 'cpanel:symlink:public_html');
  1. Importante: Antes del primer despliegue, conecta por SSH y haz backup de tu public_html:
cd /home/tu_usuario_cpanel
mv public_html public_html_backup_manual
  1. Cuando ejecutes dep deploy, Deployer automáticamente:
    • Creará un symlink desde public_html hacia {{deploy_path}}/current/public
    • Tu sitio Laravel servirá correctamente desde la carpeta public
    • Los assets, el index.php y el .htaccess de Laravel estarán disponibles

Ventajas de este método:

  • Funciona perfectamente con Laravel
  • Despliegues zero-downtime
  • Los rollbacks funcionan instantáneamente
  • No requiere modificar archivos manualmente
  • Mantiene la estructura estándar de Laravel

Tareas Post-Despliegue

  • Verifica los permisos de los directorios storage y bootstrap/cache dentro de {{deploy_path}}/shared/. Deben tener permisos de escritura para el usuario del servidor web. La receta de Laravel intenta hacer esto con deploy:writable.
  • Si las migraciones no se ejecutaron automáticamente, puedes intentar hacerlo manualmente con dep artisan:migrate stage (si definiste un stage).
  • Verifica que el symlink de public/storage se haya creado correctamente y sea accesible desde la web.

Estructura de Directorios Esperada por Deployer

Deployer organiza los archivos en el servidor de la siguiente manera dentro de tu deploy_path:

  • releases/: Contiene todas las versiones de tu código. Cada despliegue crea una nueva carpeta aquí (ej. 1, 2, 3, ...).
  • shared/: Contiene archivos y directorios que persisten entre despliegues.
    • Para WordPress: wp-config.php, wp-content/uploads/
    • Para Laravel: .env, storage/ (que incluye app/, framework/, logs/)
  • current: Un symlink (enlace simbólico) que apunta a la release activa actualmente en la carpeta releases/. Este es el directorio que tu servidor web debe servir.
    • WordPress: El DocumentRoot apunta a {{deploy_path}}/current/
    • Laravel: El DocumentRoot apunta a {{deploy_path}}/current/public/
  • .dep/: Contiene metadatos que Deployer usa para gestionar los despliegues.

Diagrama Simplificado:

/home/tu_usuario_cpanel/
└── mi_aplicacion_deploy/ (Este es tu 'deploy_path')
    ├── releases/
    │   ├── 1/
    │   ├── 2/
    │   └── 3/ (última release)
    │       ├── app/
    │       ├── public/ (para Laravel)
    │       │   └── index.php
    │       ├── wp-admin/ (para WordPress)
    │       ├── wp-content/
    │       │   └── uploads -> ../../../shared/wp-content/uploads (symlink)
    │       ├── vendor/
    │       ├── .env -> ../../shared/.env (symlink para Laravel)
    │       └── wp-config.php -> ../../shared/wp-config.php (symlink para WP)
    ├── shared/
    │   ├── .env (para Laravel)
    │   ├── wp-config.php (para WordPress)
    │   ├── storage/ (para Laravel, con sus subcarpetas)
    │   └── wp-content/
    │       └── uploads/ (para WordPress, con imágenes, etc.)
    ├── current -> releases/3 (symlink apuntando a la release activa)
    └── .dep/
        └── releases.log

Para que tu sitio funcione correctamente, tienes diferentes opciones según el tipo de dominio:

Opción 1: Cambiar DocumentRoot (para dominios addon y subdominios)

  • Dominios addon: Pueden apuntar directamente a cualquier ruta
    • WordPress: /home/tu_usuario_cpanel/mi_aplicacion_deploy/current
    • Laravel: /home/tu_usuario_cpanel/mi_aplicacion_deploy/current/public
  • Subdominios: Similar a los dominios addon, sin restricciones

Opción 2: Usar symlink desde public_html (solo para dominio principal)

  • Dominio principal: Está forzado a usar public_html, por lo que necesitas symlink:
    • public_html → symlink hacia mi_aplicacion_deploy/current (WordPress)
    • public_html → symlink hacia mi_aplicacion_deploy/current/public (Laravel)

Solución de Problemas Comunes en cPanel

Error de Conexión SSH

  • Verifica Usuario y Host: Asegúrate de que remote_user y el host en deploy.php son correctos.
  • Puerto SSH: Confirma el puerto SSH con tu proveedor.
  • Clave SSH:
    • La clave pública debe estar autorizada en cPanel.
    • La ruta a la clave privada en identity_file debe ser correcta en tu máquina local.
    • Los permisos de tu archivo de clave privada local deben ser restrictivos (ej. chmod 600 ~/.ssh/id_rsa_cpanel).
    • Intenta conectar manualmente por SSH desde tu terminal para aislar problemas: ssh -i ~/.ssh/id_rsa_cpanel -p PUERTO tu_usuario_cpanel@tu_dominio_o_ip_cpanel.
  • SSH Multiplexing: set('ssh_multiplexing', false); a veces ayuda si el servidor no lo soporta bien.

Fallo al Clonar Repositorio (Git)

  • Git no instalado: Verifica que git esté disponible en el servidor.
  • Acceso al Repositorio:
    • Si usas SSH para clonar (ej. git@github.com:...), la clave SSH del servidor cPanel (la que está en /home/tu_usuario_cpanel/.ssh/id_rsa) debe tener acceso al repositorio (como deploy key en GitHub/GitLab).
    • O, si forwardAgent está habilitado en tu ~/.ssh/config local y en Deployer (->forwardAgent(true) en la definición del host), tu clave local se usará. Asegúrate de que esta clave local tenga acceso al repo.
    • Si usas HTTPS para clonar, y el repo es privado, necesitarás configurar credenciales. Es más simple usar SSH.
  • Ruta del Repositorio: Verifica que la URL en set('repository', '...'); sea correcta.

Fallo en deploy:vendors (Composer)

  • Composer no instalado: Verifica que composer esté disponible. Si no, considera:
    • Subir composer.phar a tu deploy_path y ajustar set('bin/composer', '{{bin/php}} {{deploy_path}}/composer.phar');
    • Ejecutar composer install localmente y subir la carpeta vendor (no recomendado para consistencia).
  • Límites de Memoria/Tiempo: Los hostings compartidos pueden tener límites bajos. composer install puede fallar. Intenta composer install --prefer-dist --no-dev -o para optimizar.
  • Versión de PHP: Asegúrate de que la versión de PHP CLI en el servidor sea compatible con tu composer.json.
  • Permisos: El usuario SSH debe poder crear symlinks.
  • FollowSymLinks: La opción FollowSymLinks de Apache/LiteSpeed debe estar habilitada para el sitio. Esto es usualmente configurado por el administrador del servidor.
  • Rutas incorrectas: Verifica las rutas en shared_files, shared_dirs y la lógica de artisan:storage:link.
  • Error "Operation not permitted": Contacta a tu proveedor de hosting. Puede que los symlinks estén restringidos.

Errores de Permisos de Escritura

  • Asegúrate de que http_user está configurado correctamente.
  • Los directorios listados en writable_dirs (ej. storage/*, bootstrap/cache para Laravel; wp-content/uploads para WordPress) necesitan permisos de escritura para el usuario del servidor web (tu_usuario_cpanel usualmente).
  • Deployer intenta establecer estos permisos. Si falla, puede que necesites ajustar los permisos manualmente vía SSH/FTP o usar setfacl si está disponible y lo sabes usar.

php artisan migrate falla

  • Conexión a Base de Datos: Verifica que los datos en {{deploy_path}}/shared/.env (para Laravel) sean correctos (host, DB, usuario, pass).
  • Usuario de DB sin privilegios: El usuario MySQL debe tener permisos para crear/alterar tablas en la base de datos asignada.
  • Comando no encontrado: php o artisan no están en el PATH o no son ejecutables. Puedes intentar set('bin/php', '/ruta/absoluta/a/php'); si es necesario.

El sitio muestra una versión antigua o error 404/500 tras el despliegue

  • Symlink de public_html no funciona: Si usas el método de symlink, verifica que el symlink se haya creado correctamente: ls -la /home/tu_usuario_cpanel/public_html. Debe mostrar algo como public_html -> /ruta/hacia/deploy_path/current.
  • DocumentRoot Incorrecto: Si cambias el DocumentRoot manualmente, debe apuntar a {{deploy_path}}/current/public (Laravel) o {{deploy_path}}/current/ (WordPress).
  • Symlink current no actualizado: Revisa los logs de Deployer para ver si la tarea deploy:symlink se ejecutó correctamente.
  • Permisos en current: La carpeta current y sus contenidos deben ser legibles por el servidor web.
  • Errores PHP: Revisa los logs de error de PHP en cPanel o en {{deploy_path}}/shared/storage/logs/laravel.log (Laravel).
  • Servidor web en caché: Algunos servidores cachean la resolución de symlinks. Espera unos minutos o contacta al soporte del hosting.

"Shell TTY anidado no soportado" o similar

Prueba añadiendo ->setSshMultiplexing(false) o ->multiplexing(false) a la definición de tu host en deploy.php.

Consejos Adicionales para cPanel

  • Empieza Simple: Antes de desplegar una aplicación completa, prueba con una tarea simple como dep pwd o dep ls para verificar la conexión SSH y la ruta base.
  • Despliegues Lentos: Los hostings compartidos pueden ser lentos. Ten paciencia.
  • Limpieza de Releases: Usa set('keep_releases', 3); (o un número bajo) para no agotar el espacio en disco con releases antiguas.
  • WP-CLI y php artisan: Si estos comandos no están en el PATH del servidor, puede que necesites especificar sus rutas absolutas en deploy.php:
    • set('bin/wp', '/home/tu_usuario_cpanel/path/to/wp-cli.phar');
    • set('bin/php', '/opt/cpanel/ea-phpXX/root/usr/bin/php'); (la ruta de PHP puede variar)
    • Para artisan, Deployer usualmente lo encuentra relativo a {{release_path}}, pero bin/php debe ser correcto.
  • Rollbacks: Prueba la funcionalidad de rollback: dep rollback.
  • Staging Automático: Utiliza la receta de cPanel para crear automáticamente entornos de staging con dominios y bases de datos dedicadas para cada rama de desarrollo.
  • Habla con tu Proveedor: Si encuentras limitaciones específicas (ej. symlinks deshabilitados, comandos SSH bloqueados), contacta al soporte de tu hosting. Puede que no sea posible usar Deployer con todas sus características en ese entorno.
  • Alternativas: Si Deployer resulta demasiado complejo o incompatible con tu cPanel, considera alternativas más simples para la automatización como scripts de Git post-receive (si cPanel lo permite) o herramientas como Plesk (que a veces tiene mejor integración con Git). Para despliegues simples, FTP manual o vía cliente Git también son opciones, aunque menos robustas.

Desplegar con Deployer en cPanel requiere paciencia y adaptación. No todas las funciones de Deployer (especialmente el aprovisionamiento) serán relevantes o posibles. Enfócate en el flujo de despliegue de código y la gestión de releases.