laravel/envoy
Laravel Envoy is a lightweight SSH task runner for defining and executing remote server tasks using a clean Blade-style syntax. Ideal for deployments, running Artisan commands, and other repeatable server automation workflows across multiple hosts.
Installation:
composer require laravel/envoy --dev
Add the envoy.php config file via:
php artisan vendor:publish --provider="Laravel\Envoy\EnvoyServiceProvider"
First Use Case:
Create a Envoy.blade.php file in your project root (or specify a custom path in envoy.php).
Define a simple task:
@servers(['web' => ['host' => 'your-server.com']])
@task('deploy', ['on' => 'web'])
cd /path/to/your/app
git pull origin main
composer install --no-dev --optimize-autoloader
php artisan optimize
@endtask
Run it via:
php artisan envoy deploy
Where to Look First:
envoy.php config file for global settings (e.g., timeout, keep_alive).Task Organization:
@task('deploy:database'), @task('deploy:code')).@servers to define environments (e.g., staging, production) with host-specific configurations:
@servers([
'staging' => ['hosts' => ['staging.example.com']],
'production' => ['hosts' => ['prod.example.com'], 'options' => ['port' => 2222']]
])
Reusable Task Logic:
_deploy-steps.blade.php):
@include('_deploy-steps')
@env directives to conditionally include logic:
@env('production')
php artisan cache:clear
@endenv
Artisan Integration:
@task('migrate', ['on' => 'web'])
php artisan migrate --force
@endtask
php artisan envoy migrate --env=production -- --seed
Parallel Execution:
@parallel
@servers(['web-1' => ['host' => 'server1.com']])
@task('restart-queue')
php artisan queue:restart
@endtask
@servers(['web-2' => ['host' => 'server2.com']])
@task('restart-queue')
php artisan queue:restart
@endtask
@endparallel
Environment Variables:
.env variables in tasks:
@task('deploy')
cd {{ env('DEPLOY_PATH') }}
git pull origin {{ env('BRANCH', 'main') }}
@endtask
Hooks for Pre/Post Actions:
@before and @after to wrap tasks:
@task('deploy', ['on' => 'web'])
@before
echo "Starting deployment..."
@endbefore
git pull origin main
composer install
@after
echo "Deployment complete!"
php artisan down --releases
@endafter
@endtask
Custom SSH Options:
@servers(['web' => ['host' => 'server.com', 'options' => ['user' => 'deploy', 'key' => '~/.ssh/id_rsa']]])
Local Development Proxy:
laravel/valet or laravel/homestead with Envoy for local task execution:
@servers(['local' => ['host' => 'homestead.app']])
CI/CD Pipelines:
# Example GitHub Actions step
- name: Deploy
run: php artisan envoy deploy --env=production
Composer Scripts:
composer.json:
{
"scripts": {
"deploy": "envoy deploy --env=production"
}
}
Run with:
composer deploy
Laravel Forge/Panel:
Monitoring:
@task('deploy')
@before
echo "=== DEPLOY STARTED ===" >> /tmp/deploy.log
@endafter
Docker Integration:
@task('docker:restart')
docker-compose restart web
@endtask
Blade Syntax Conflicts:
if.blade.php) to prevent parsing errors.@verbatim for raw SSH commands with special characters:
@verbatim
echo "This is a literal command with @symbols"
@endverbatim
Timeouts:
@servers(['slow' => ['host' => 'server.com', 'timeout' => 120]])
envoy.php:
'timeout' => 60,
SSH Key Management:
~/.ssh/id_rsa by default, but specify custom paths:
@servers(['web' => ['host' => 'server.com', 'key' => '~/.ssh/custom_key']])
@servers(['web' => ['host' => 'server.com', 'options' => ['-A']]])
Permission Issues:
sudo carefully:
@task('sudo-task')
sudo chmod -R 755 /path/to/app
@endtask
setfacl or configure permissions via deployment scripts.Variable Scope:
@servers are not automatically available in tasks. Pass them explicitly:
@servers(['web' => ['host' => 'server.com', 'deploy_path' => '/var/www/app']])
@task('deploy')
cd {{ $deploy_path }}
@endtask
Parallel Task Quirks:
@parallel tasks run independently. Avoid shared state (e.g., modifying the same file).Debugging:
-v:
php artisan envoy deploy -v
@echo for debugging:
@task('debug')
@echo "Current directory: $(pwd)"
@endtask
Windows Line Endings:
LF line endings (Linux/Unix). Convert files with:
dos2unix Envoy.blade.php
Task Templates:
@servers(['web' => ['host' => 'server.com', 'deploy_path' => '/var/www/app']])
@task('deploy', ['on' => 'web'])
cd {{ $deploy_path }}
git pull origin {{ env('BRANCH', 'main') }}
composer install --no-dev --optimize-autoloader
php artisan config:cache
php artisan route:cache
php artisan view:cache
touch storage/framework/cache/data/cache_tags
@endtask
Dry Runs:
ssh flags:
php artisan envoy deploy --env=production --ssh="ssh -vvv"
Environment-Specific Files:
Envoy.blade.staging.php or `Envoy.blade.proHow can I help you explore Laravel packages today?