Freelance developer, and designer

My Envoy Deployment Script

I am a huge fan of Laravel Forge and Envoyer for my server provisioning and deployment needs. Check them out if you haven’t already, they save me a lot of time whenever I’m handling large scale projects.

There are cases though that we all end up writing our own build and deployment scripts, or for some, even doing it manually.


Server Access

First of all, you have to setup your SSH keys with your server. We’ll use and envoy as our deployment user.

ssh-copy-id deploy@

Now, connect to the shell and we’ll disable sudo for restarting php-fpm:

# Connect to the server
ssh deploy@

# Disable sudo for the user `envoy`
echo "envoy ALL=NOPASSWD: /usr/sbin/service php7.0-fpm restart" | sudo tee -a /etc/sudoers.d/php-fpm

Once we've got that disabled, we can now go to our deployment script.

Directory Structure

This is the directory structure for my setup:

| /home/envoy/
|- jag.gy
|-- .env              # laravel dotenv file
|--- current/         # sym linked to the latest release
|--- releases/
|---- 20150101230918/ # timestamp of the release

Take note of the .env file under the website domain.

Environment File

In the .env file, I added a SERVER_PRODUCTION variable for the envoy script so we don't have to commit any sensitive data in version control.






Envoy Script

    function env(string $key) {
        $dotenv = file_get_contents('.env');
        $rows   = explode("\n", $dotenv);

        $search = array_filter($rows, function ($row) use ($key) {
            if (strstr($row, $key)) {
                return $row;

        $variable = reset($search);
        $segments = explode('=', $variable);
        $user = end($segments);

        return $user;

    $now      = date('YmdHis');
    $home     = '/home/forge';
    $domain   = 'default';
    $base     = "{$home}/{$domain}";
    $releases = "{$base}/releases";
    $current  = "{$releases}/{$now}";

    $repository        = 'https://github.com/jaggy/blog/archive/master.zip';
    $production_server = env('SERVER_PRODUCTION');

@servers(['production' => $production_server])


    cd {{ $releases }}

    wget {{ $repository }}
    unzip master.zip
    mv blog-master {{ $now }}
    rm master.zip

    cd {{ $current }}

    composer install --prefer-dist --no-dev

    cd {{ $current }}

    php artisan clear-compiled

    php artisan optimize
    php artisan route:cache
    {{-- php artisan config:cache --}}

    cd {{ $domain }}

    {{-- Delete symbolic link --}}
    rm current

    {{-- Link the latest release to the current release --}}
    ln -s {{ $current }} current

    cd {{ $current }}

    {{-- Link the global .env file to the current release --}}
    ln -s {{ $base }}/.env .

    sudo /usr/sbin/service php7.0-fpm reload

To run the script:

envoy run deploy

Just to give a rundown on what the script does:

  1. Download the master archive file from Github and stores it at the releases folder.
  2. Install the composer dependencies.
  3. Cache the routes and compile the laravel classes.
  4. Switch the symbolic link to the new release.
  5. Create a symbolic link of the .env in the latest release
  6. Reload the PHP-FPM server.


I disabled the php artisan config:cache since for some reason, whenever I execute that script, the application isn't reading the .env and starts throwing a cipher key error.

I want to expand the script where we store the github repository in the environment file as well. Also, I wanna add a branch or even a commit sha flag for rolling back releases as well.

I also wanna add a release folder clean up to remove the bloat on the releases folder and move the storage/ folder under the domain for the cache to not be affected by any of the releases.


Here are some additional or different things you can do for your deployment.

Pulling the changes from Github

Rather than downloading an archive file, you can just go to your project directory and executing a git pull origin master from there.

cd {{ $current }}

git pull origin {{ $branch }}

Comiling your Assets

Some people don't want to commit their compiled stylesheets and javascript files, which is reasonable. (I like committing them since I don't like the idea of production compiling any of the assets, unless I have a build server that does the job though).

cd {{ $current }}

gulp stylus --production     # or whatever pre-processor you fancy.
gulp browserify --production
gulp optimize-images         # script to run image optimizations in resources/assets/images/


Most of the things I applied here I learned from using Envoy and Forge and from subscribing to Servers for Hackers by @fideloper