Laravel Deployments using Envoy - A Step-by-Step Guide

In the realm of web development, the journey doesn't end once you've built a feature-rich Laravel application. The real magic happens when you smoothly and reliably deploy that masterpiece to a production server, making it accessible to the world.

However, the process of deploying a Laravel application can be a complex chore, riddled with potential pitfalls and challenges. That's where Laravel Envoy steps in as your trusty sidekick.

Envoy, a task runner developed by the Laravel team, simplifies the deployment process, making it efficient, repeatable, and dare we say, enjoyable.

laravel_envoy

Laravel Envoy is a tool for executing common tasks you run on your remote servers. Using Blade style syntax, you can easily set up tasks for deployment, Artisan commands, and more. Currently, Envoy only supports the Mac and Linux operating systems. However, Windows support is achievable using WSL2.

In this comprehensive step-by-step guide, we'll embark on a journey to demystify Laravel deployments using Envoy.

So, let's see laravel deployments using Envoy - a step-by-step guide, laravel 10 envoy, laravel/envoy deploy, how to install Envoy in laravel 10, and laravel envoy deploy.

Step 1: Installing Envoy

Install Envoy globally on your development machine using Composer:

composer global require laravel/envoy

 

Step 2: Preparing Your Laravel Project

Ensure your Laravel project is ready for deployment, including environment configuration (e.g., .env), setting up a database, and configuring any environment-specific settings.

 

Step 3: Creating an Envoy.blade.php File

Creating an Envoy.blade.php file in your Laravel project's root directory. This file will serve as the script that defines the deployment tasks you want to execute using Laravel Envoy.

 

Step 4: Defining Deployment Tasks and Configuring Server and Deployment Settings

Inside the Envoy.blade.php file, you will define your deployment tasks using Blade directives. Each task typically includes a name, a list of servers or hosts where the task should run (@servers directive), and the actual shell commands or actions to perform on the server (@task directive).

@servers(['web' => 'user@your-server.com'])

@task('deploy', ['on' => 'web'])
    cd /path/to/your/laravel/project
    git pull origin master
@endtask

Example 1:

{{-- servers array, deploy-myapp is the ssh hostname added in the config file in the prev step. --}}
@servers(['web'=>'deploy-myapp'])

{{-- add the git repo, specify branch(if you want to target specific branch), app_dir is the directory on your server, however you've configured it.
releases_dir as it'll be used to clone into those directories. --}}
@setup
$repo = 'git@github.com:usernam/myrepo.git';
$branch = "branch";
$app_dir      = '/var/www/mywebsite.com';
$releases_dir =  $app_dir . '/releases';
$release_dir  =  $app_dir . '/releases/' . date('YmdHis');

{{-- we'll be only storing last 3 no of releases and remove all rest. --}}
$keep = 3;

{{-- for permissions --}}
$writable = [
'storage'
];

{{-- shared files/directories --}}
$shared = [
'storage' => 'd',
'.env' => 'f',
];
@endsetup

{{-- define list of tasks to be executed on deploy runner --}}
@macro('deploy',['on'=>'web'])
fetch_repo
run_composer
update_permissions
assets_install
migrate
clean
update_symlinks
@endmacro

{{-- get and clone the repository in the releases directory. --}}
@task('fetch_repo')
[ -d {{ $releases_dir  }} ] || mkdir -p {{ $releases_dir }};
git clone {{ $repo }}  --branch={{ $branch }} {{ $release_dir }};
echo "Repository has been cloned";
@endtask

{{-- copy .env files and run composer install to install the dependencies --}}
@task('run_composer')
cd {{ $release_dir }};
cp .env.stage .env
composer install --prefer-dist --no-interaction;
echo "Composer dependencies have been installed";
@endtask

{{-- configure project files/folder permissions --}}
@task('update_permissions')
@foreach($writable as $item)
    chmod -R 755 {{ $release_dir }}/{{ $item }}
    chmod -R g+s {{ $release_dir }}/{{ $item }}
    chgrp -R www-data {{ $release_dir }}/{{ $item }}
    echo "Permissions have been set for  {{ $release_dir }}/{{ $item }}"
@endforeach
chmod -R ug+rwx {{ $release_dir }}
chgrp -R www-data {{ $release_dir }}
echo "Permissions have been set for  {{ $release_dir }}"
@endtask

{{-- run and build assets using npm --}}
@task('assets_install')
cd {{ $release_dir }};
npm install && npm run production;
@endtask

{{-- migrate database if any new changes --}}
@task('migrate')
php {{ $release_dir }}/artisan migrate --force --no-interaction;
@endtask


{{-- Clean old releases --}}
@task('clean')
echo "Clean old releases";
cd {{ $releases_dir }};
rm -rf $(ls -t | tail -n +{{ $keep }});
@endtask

{{-- update symlinks --}}
@task('update_symlinks')
[ -d {{ $app_dir }}/shared ] || mkdir -p {{ $app_dir }}/shared;

@foreach($shared as $item => $type)

    #// if the item passed exists in the shared folder and in the release folder then
    #// remove it from the release folder;
    #// or if the item passed not existis in the shared folder and existis in the release folder then
    #// move it to the shared folder

    if ( [ -{{ $type }} '{{ $app_dir }}/shared/{{ $item }}' ] && [ -{{ $type }} '{{ $release_dir }}/{{ $item }}' ] );
    then
    rm -rf {{ $release_dir }}/{{ $item }};
    echo "rm -rf {{ $release_dir }}/{{ $item }}";
    elif ( [ ! -{{ $type }} '{{ $app_dir }}/shared/{{ $item }}' ]  && [ -{{ $type }} '{{ $release_dir }}/{{ $item }}' ] );
    then
    mv {{ $release_dir }}/{{ $item }} {{ $app_dir }}/shared/{{ $item }};
    echo "mv {{ $release_dir }}/{{ $item }} {{ $app_dir }}/shared/{{ $item }}";
    fi

    ln -nfs {{ $app_dir }}/shared/{{ $item }} {{ $release_dir }}/{{ $item }}
    echo "Symlink has been set for {{ $release_dir }}/{{ $item }}"
@endforeach

ln -nfs {{ $release_dir }} {{ $app_dir }}/current;
chgrp -h www-data {{ $app_dir }}/current;
echo "All symlinks have been set"
@endtask

 

Example 2:

you'll define your server settings and associate deployment tasks with specific servers in your Envoy.blade.php file.

@servers(['web' => 'user@your-server.com'])

@setup
    $projectRoot = '/path/to/your/laravel/project';
@endsetup

@task('deploy', ['on' => 'web'])
    cd {{ $projectRoot }}
    git pull origin master
    composer install --no-interaction --prefer-dist --optimize-autoloader
    php artisan migrate --force
    php artisan optimize
    php artisan config:cache
    php artisan route:cache
    php artisan view:cache
@endtask

Explanation:

  • @servers: Defines a server named 'web' with the SSH address 'user@your-server.com'. Replace 'user@your-server.com' with the actual SSH address of your remote server.

  • @setup: Sets up environment variables. In this example, we define $projectRoot, which stores the path to your Laravel project on the server. Replace '/path/to/your/laravel/project' with the actual path to your project.

  • @task('deploy', ['on' => 'web']): Defines a deployment task named 'deploy' that will run on the 'web' server.

Inside the task:

  • cd {{ $projectRoot }}: Changes the working directory to your project root.

  • git pull origin master: Pulls the latest code from the Git repository.

  • composer install ...: Runs Composer to install dependencies, optimize autoloading, and ensure the project is up to date.

  • php artisan migrate ...: Runs database migrations.

  • php artisan optimize: Optimizes Laravel for production.

  • php artisan config:cache: Caches the configuration files.

  • php artisan route:cache: Caches the route files.

  • php artisan view:cache: Caches the Blade views.

 

Step 5: Running Envoy Tasks

Run Envoy tasks from your local machine using the envoy run command and specify the task you want to execute. For example, to deploy your project:

envoy run deploy

 

Conclusion:

Summarize the benefits of using Envoy for Laravel deployments. Encourage readers to implement these best practices in their projects for smoother and more reliable deployments.

 


You might also like:

RECOMMENDED POSTS

FEATURE POSTS