How to configure Push to Deploy with Envoyer

Introduction

It’s hard to not stumble across Envoyer, once you become the member of Laravel community. It’s advertised as Zero Downtime PHP Deployments and is one of many commercial products from Taylor Otwell, creator of Laravel framework.

I will walk you through the configuration of Push to Deploy. This means that whenever you push or merge your code into specified branch, Envoyer should detect it and automatically trigger deployment.

Keep in mind that Envoyer allows one project to be associated with exactly one branch from chosen repository.

Assumptions

  • you have git repository hosted on Bitbucket, Github or Gitlab
  • you have some cash to spend every month
  • you have no time nor knowledge of how to perform Zero Downtime Deployments

Solution

Head over to Envoyer, where you may register as

  • someone who creates and manages projects (paid, however 5-days free trial available)
  • someone who wishes to collaborates with others (free)

Once you do it, you will be presented with Connectivity page, where you can connect to the most popular GIT repository hosting services such as GitHub, BitBucket or GitLab.


Connect to one of available Code Providers – for this tutorial I’ve chosen Bitbucket. As you see, Envoyer uses oAuth and requests following information from your Bitbucket user.

If you hesitate a bit before granting the final access, it’s a good thing. Personally I would prefer to have more granular and opt-in control over which repository is accessible by Envoyer – unfortunately it’s not possible. One of the solution could be creating a special Bitbucket deployment user who has access only to subset of your repositories and then connect him with Envoyer.

After successful oAuth dance, you should be presented with following screen

Before you proceed to click big red Add Project button, please stop for a second and try to answer this question.

Is there an easy way to delete the connection between Envoyer and Bitbucket?

You may go to your Envoyer profile, click the tab Integration and see this screen

Whoops, there is no way to remove the connection, just refreshing the tokens. Hopefully, there is a place where you can clean up your oAuth integrations – in this case head over to Bitbucket website and open your user’s profile page. Navigate to Settings, then to oAuth (under Access Management) and find Envoyer under integrated applications.

Feel free to click Revoke button if you are already tired and don’t want to continue. Otherwise let’s see what Envoyer actually offers.

Start off by clicking aforementioned Add Project button. Specify what type of project it is and then type in your unique user/repository combination. As you see, Envoyer is tailored for Laravel-kind projects and in this tutorial I will focus on Laravel 5.4 deployment.

After you add your first project, you will be presented with following screen

At this moment, default branch is master, there are no deployments yet, nor any server configured. Post-deployment health checks are not in place either.

Before I show you how to Add a Server, it’s good to know a bit more about Project Settings page (Accessible by clicking the Settings button), where you can do the following

Under The Basics section

  • rename your project
  • choose different type of project
  • define health check url (domain or IP)

Under Source Control section, as shown below, you may

  • change provider,  repository or branch
  • opt-in for Deploy When Code Is Pushed
  • opt-in for Install “Dev” Composer Dependencies

And lastly, under Delete Project section, you may obviously delete your project by typing in its name.

Please make sure that Deploy When Code is Pushed is checked before you proceed any further.

Finally, we are ready to Add a Server, so let’s do it together. Head over to your Project main page, choose Servers tab and then click Add Server button.

As you see, it was pretty straightforward, although some options need more explanation.

  • Your IP Address must be reachable from outside and your SSH Server configured properly
  • Your project must run on one of the following PHP Versions: PHP 7.1, PHP 7.0, PHP 5.6 with php5.6-fpm, PHP 5.6 with php5-fpm
  • You may decide to not receive Code Deployments which may be useful for Database Servers, where you still want to perform some hooks but not run any code
  • Project Path that you provided will be used by Envoyer to create releases directory and current symlink, so don’t forget to adjust your web server’s document root directory to something like /var/www/test-repository/current/public

Upon success you will be given Envoyer’s public SSH key which should be placed in your server’s .ssh/authorized_keys file.

You can monitor whether the connection was established by tracking Connection Status column under your Server list.

As soon as you upload your Envoyer’s public SSH key, click on the Refresh icon. If everything went fine, it should change to green.

Before we look into Deployment Hooks, it’s good to know that you can configure more options during Server edition. In this case click Update Server button.

As you see, you can opt-in to Restart FPM After Deployments as well as specify your php and composer paths.

Ready for the final step of configuring Push to Deploy? Perfect, let’s do it then together.

Head over to Deployment Hooks tab and look around. First thing to notice is four distinct actions which are fixed and cannot be deleted. You can hook into them by creating Before or After steps.

As you see I created four steps. Two after-steps take care of database migration and directory permissions – they will run after composer finishes installing its dependencies. Another two before-steps take care of NPM dependencies and assets compilation – they will run just before the activation of new release.

It’s pretty simple to define new hooks, just click the Cog icon.

Being there, press Add Hook button and you will be presented with popover as shown below.

Envoyer is pretty flexible – you can use any shell commands that are available on you server.

Make sure you define Run As to a user which has acknowledged Envoyer’s public SSH key. If you need to use many users, make sure you put the same Envoyer’s public SSH key into this user’s .ssh/authorized_keys file. (e.g: /home/newuser/.ssh/authorized_keys)

Keep also in mind that you need to specify on which server those hooks will run. If you add new server later on, you must come back to each hook you defined and manually check it there.

It’s worth knowing that Envoyer provides three variables which should make your life easier.

We are almost ready to perform our first Deployment, isn’t it exciting? As you know, Deployments may be triggered in three ways

  • manually,
  • using Push to Deploy
  • by making a request to URL like: https://envoyer.io/deploy/5KtMRITISFAKEIKNOWYOUKNOW2knNfQQB

What you may not know is that after you checked the Deploy When Code Is Pushed in your Project Settings, Envoyer silently created a POST Service in your Bitbucket’s repository.

Head over to your Bitbucket’s repository settings, choose newly created section Services (under Workflow) and on the right pane you should see pretty familiar URL.

There is one gotcha though – remember this third option of deployments where you can post to url? On the Deployment Hooks tab, there is a little refresh icon next to this URL – once you click it, your automatic push to deploy will simply stop working! In order to fix it, head over to your Project Settings, uncheck and check the Deploy When Code Is Pushed option and then save the project – your Bitbucket’s Service will be regenerated and your Push to Deploy should work again.

So you’ve set up everything, you also know now some of the common pitfalls, but still don’t see any deployments. Why is that?

As Push to Deploy suggests, you must firstly commit something to your branch, then push it to your origin (e.g: https://tekmi@bitbucket.org/tekmi/test-repository.git) and patiently wait until Envoyer gets notified about this event.

You look at the Deployment tab of your project and all of the sudden the spinner shows off, announcing deployment – Envoyer’s worker is ready to work on your server. With all that joy, please don’t forget to click the Arrow button on the right, which will give you detailed information about deployment

As you see, all the fixed steps as well as your hooks are launching in order you set before. You may want to click Documents icon to see even more details of a certain step – usually this will be echo/print messages returned from your server’s shell scripts.

If any of the scripts fails (returning non-0 shell status code), all the subsequent steps will be cancelled, causing the whole deployment to stop and marked as failed.

Don’t worry, your website should still be running and in perfect shape, since this was the Zero Downtime deployment. However here may be one gotcha.

Please consider situation when you had the database migration step and another script after it failed. In this case the deployment is cancelled, your website in happily in old state, but unfortunately the newest database changes have been applied – if you deleted some tables, you may be in trouble.

To remedy this, you have two options – either log in to your server and cast the command php artisan migrate:rollback or quickly fix failed scripts and reschedule previous deployment.

Situations like above are rare, so in most cases you should sleep well, without worrying too much about it.

Having gone through all the steps, it’s time to enjoy freshly deployed project, heading towards browser and checking if everything looks like you expected.

Findings

  1. Laravel by default comes with some predefined JavaScript libraries listed out in package.json. They all are defined under devDependencies, so don’t forget to run npm install –dev, even on your production server. Alternatively you can move all those libs under dependencies and remove the flag –dev.
  2. Installation of NPM dependencies takes most of the deployment time (in my case around 30-40s) and runs every time deployment is scheduled. One way to avoid it could be to use Yarn package manager . Another way could be to install NPM dependencies one level above release folder (using {{project}} variable), sharing it among deployments. Or maybe waiting until NPM dependency manager becomes configurable via Envoyer, like PHP Composer package manager is.
  3. Laravel’s 5.4 bootstrap cache directory is not writable by default, causing Laravel project to fail. One way to tackle this would be to add sudo chmod -R 777 bootstrap/cache/. 

Bugs

  1. If you use Push to Deploy deployments, there is no way to detect which event happened in your Bitbucket repository. As a consequence, if you merge your Pull Requests, Envoyer schedules as many deployments as you had commits under this Pull Request.
  2. If you add collaborator to your Envoyer project, this collaborator cannot change projects settings, since some of them need remote changes on the Bitbucket website.
  3. If you try to regenerate your Push URL under Deployment Hooks tab, your previous Push to Deploy Project Setting is not updated accordingly, causing the automatic deployments to fail.

Summary

Envoyer looks like an interesting addition to PHP ecosystem which may make some developers happy and satisfied, at least at the first glance.

It’s a good tool for not complicated, Laravel-based projects. It’s thousands times better than using old-fashion FTP/SFTP to transfer the latest changes into production server.

However the more you work with Envoyer and the more your projects grow, the more shortcomings and drawbacks you become to see. In the end it’s just a thin, web-based convenience layer on top of the vast application deployment topic – it imposes certain rules on your development team, so read carefully following points

  • you can add multiple servers, but you cannot export theirs configuration
  • you can hook into four fixed steps of deployment, but you cannot export their configuration either
  • you can only see four latest deployments
  • you cannot decide how many releases of your project Envoyer is about to keep – magic number four from my experience
  • one project equals one repository branch, so you need to keep creating projects if you want to deploy multiple branches of the same repository on the same server
  • you theoretically can have Push to Deploy deployments, but they become unusable when you start using Pull Requests
  • if you use Subversion or have privately hosted git repository (which is not Self-hosted Gitlab), you cannot even start
  • if you like Envoyer’s url health checks, you can actually check out Status Cake uptime monitoring tool, which is free and does the job much better

If some of the information are incorrect or you experienced other issues, please let me know in comments.

Personal opinion

I always advocate for tools/software that are free to use/explore for unlimited time as long as your volume is low. Unfortunately Envoyer is paid from the very beginning, and in the most annoying way, since it charges you 10$ every month.

If I were a student, living in the third-world countries or just wanted to share my open source project in more professional way, those 10$ monthly may become a blocker.

Some may argue that Taylor has already created Laravel and it should be enough as a give away. They even may point to scarce documentation of Laravel Envoy, which is actually free.

I’m completely with you guys. I just want to take another step and share more useful knowledge for those who cannot afford even a 1$ a month.

In one of the future posts, I will examine multiple free deployment tools, which may be an interesting option for your future projects! Stay tunned!


If you enjoyed this post, then make sure you subscribe to my Newsletter

Leave a Reply

Your email address will not be published. Required fields are marked *