Laravel, Forge, Envoyer, CloudFlare, SSL and You

Ted Nugent
10 min readJan 21, 2018

--

Forge and Envoyer are pretty powerful individually but paired up they should be ideal for supporting a developers array of applications. Unfortunately finding good reference and documentation for the pairing seems to be and far between, and tends to leave it to the readers interpretation — I have yet to find a clear recipe for getting them to work together. This article is based off Forge and Envoyer by Taylor Otwell and is intended to provide the additional detail and give a clearer outline on my approach of combining the two.

I assume from my research so far that many Laravel developers use Forge or Envoyer but tend not to intermix the two, and understand in many cases Forge can do much of the heavy-lifting but lacks granularity on the deployment side. Envoyer is all about deployments and doesn’t allow for provisioning which Forge streamlines nicely.

Key Ingredients:

  • GitHub (Source Control)
  • Laravel Forge (Server Provisioning)
  • Envoyer.io (handles all aspects of deployment )
  • CloudFlare (DNS & HTTPS config)
  • NameCheap (Domain and SSL Certificates)
  • DataDog and BlackFire.io (for performance monitoring and profiling — not covered in this article)

Background

I’m only a couple years into my Laravel journey but like many others love the framework, community and supporting technologies. I consider myself to be “full-stack” and have a preference towards the back-end systems and dabbling into the devops side for server setup and management. I am by no means a Laravel expert and am writing this article mostly for my own benefit to refer to in the future; hopefully you find it useful as well.

In my day-to-day work we use AWS with compliment of 50+ ec2 servers to which host our applications, and try to efficiently use all the Amazon-provided tools like EC2, RDS, CodePipeline, CodeDeploy to handle the periodic rollouts of each of our web app. It ‘works’ but feels fragile and doesn’t take much to take the system out of balance; I find it hard to get a good at-a-glance view of how the entire system is operating.

I personally am not a fan of AWS and find their eco-system to be overly complicated, jargon-y and perpetually confusing even for the most basic of tasks. The learning curve is high and i find it like navigating a minefield of options that aren’t clear or obvious; constantly wondering if I’ve missed something or am flipping a switch that will bite me later. Although we are regularly taking steps to improve, we have yet to hit that sweet spot of automated deployment, tests and verification; I long for the simplicity that Forge and Envoyer provide to do the same. I do hope that Amazon takes steps in the future to simplifying the users workflow in the near future so I may benefit from it.

Getting Started

Lets assume you’ve written a Laravel application and are finally ready to take steps push it into the public. Your application is stored in a private GIT repository in GitHub, and has 3 primary branches to control staged releases

  • develop (my base working branch for development)
  • preflight (a protected branch, allowing only pull-requests which are auto deployed to the QA server provisioned by Forge. The environment is biased for debugging, all integration and tests will generally executed against the application in this environment.)
  • master (also a protected branch, only pull requests allowed that have passed the entire gamut of pre-flight scrutiny, and are auto-deployed on each push to the PRODUCTION server, also provisioned by Forge.)

You need a domain and an SSL certificate. I currently favour NameCheap and have at least one domain and ssl cert per Laravel application to be deployed although your domain and cert can come from any valid provider such as letsencrypt.org

DNS Settings are all handled with Cloudflare, so once an SSL Certificate is installed, You’ll also need to ensure that the Crypto settings for that domain are updated accordingly. If improperly configured, once the SSL is enabled you can get into 502 hell (and other enjoyable HTTP errors).

Strategically I tend depend on Forge to only handle provisioning of servers and basic configuration such as SSH keys, SSL and website info. Leave the Git and other settings alone as they will be handled with Envoyer. For servers, all things being equal I like to have a dedicated server for production and one for QA, but they could just as easily be deployed to a singular server.

As an aside, I highly recommend F-Bar by Jan Östlund for keeping tabs on your forge servers and sites from your desktop once things are running. It is an awesome tool to keep passive watch on your server collection.

Once your servers are provisioned, configured in Forge and appropriate deployment configs are setup in Envoyer, things should run smoothly and be easily repeatable. You may find it goes smoothly without HTTPS, it is when we enable HTTPS that we run into some hiccup.

When all is said and done — the goal here is to only worry about continuing development and pushing to either preflight or master to get your app deployed to its appropriate server.

Step 1 : Create an Application

Let’s just assume for argument’s sake you have done all the work already and your app is ready to go into the wild, lives in Github and setup correctly with access for deployment.

Step 2 : Provision Your Forge Servers

You’ll need to ensure your production and preflight server(s) exist, so i find it best to tackle this first. In this example we’ll provision 1 servers. If you already have done this for previous applications, skip this step and jump to your DNS.

Configure and Provision your Forge Server(s)

In Forge, select your preferred provider under “Create Server” and configure to your needs. You may elect to go with 2 separate virtual servers, in this case we’ll use one server and setup subdomains to serve the production and preflight variants. I generally prefer a modest 2G configuration using PHP 7.2 and MySQL.

Provisioned servers and ip info

Once complete and provisioned, you’ll need to make note of their respective ip addresses for the DNS entries for Cloudflare. We’ll set them up using subdomains to make it easier to test later.

Step 3 : Domain & DNS Setup

Purchase or select an existing domain to be used for your application and hop on over to Cloudflare to get the DNS configured. Cloudflare steps are abbreviated here:

Typical WWW and prefligt DNS configuration
  1. Add a new Site with your domain name; CloudFlare will perform a scan set it up as best it can automatically.
  2. Add an A record of * pointing to your server ip
  3. Add a CNAME or A record of www pointing to your domain or production IP (this identifies our production server)
  4. Add a CNAME or A record of preflight with a value of your domain or preflight server respectively (this identifies our QA server)
  5. Add any other appropriate DNS entries as needed (Mail, MX etc.)
  6. Ensure that your domain registrar is pointing to your name-server as well to ensure everything works correctly. When you’re done, using a DNS checker like MXToobox or DNSCheck is great for a sanity check.

Step 4 : Back to Forge to setup the basics

Go to the detail page for your newly provisioned server and under “New Site” enter in your domain name and be sure to set your Web Directory to /current/public as Envoyer will expect this.

Be sure to set the Web Directory property correctly

Click on Add Site then click into the newly created Site Details > SSL and install your SSL certificate from NameCheap or provider.

Thankfully Forge makes this super easy but Eric L. Barnes wrote a great article called Laravel Forge with NameCheap SSL outlining these steps. Depending on how you authenticate the SSL you may need to go back to CloudFlare to add a DNS entry as they require. Be sure to activate the certificate and you should see something like:

Confirmed we installed the SSL Certificate

Here is the gotcha for the SSL/HTTPS configuration and Cloudflare configuration. As I mentioned at the top of the article, of you don’t make these adjustments you’ll get a bunch of 502 and other HTTP errors trying to get everything working. Now jump back to CloudFlare for a moment and go to the Crypto page, making sure to do the following:

  • Set the SSL to FULL
  • Set Always use HTTPS to ON
  • Set Require Modern TLS to ON

This should be all you need to ensure your DNS is configured correctly. If you get an error when you test in your browser, double-check these 3 settings.

Step 5 : Setup pre-flight subdomain

Lastly, if we’re using the same server for both production and preflight, we’ll need to either edit the NGINX configuration to specify a name matching preflight subdomain, or setup an additional site using the preflight.domain.com and a new path. Pick your poison here, and you’ll need to refer to the nginx docs and reference online how to accomplish this. From my own experience i find it simpler to just create an extra site but can add up if you have a bunch of sites on the same server.

The Forge-default will suffice for the production setup; the only difference between the two is a server name of preflight.domain.com and a path to where you will deploy a copy of the preflight branch.

Step 6 : Configure Envoyer to Trigger Deployments

Login to Envoyer and click “Add Project” and provide your project name and GitHub details. Now that we have the server provisioned and setup, all we should need to do now is setup the deployment and make sure both branches are being monitored for changes.

Adding a New Project to Envoyer

You’ll need to repeat this for both configurations — the only thing that differs here is the name — both will point to the same Repository.

Preflight and Production projects added

Click to your Production project and then hit the Settings and set your production url for the Health Check URL

Click to the Source Control tab and verify your configuration for production is to deploy the master branch. You’ll need to check the Deploy When Code Is Pushed option as well. When finished the other production settings do the same in your preflight project but specify preflight instead of master.

Production Source Control configuration

Then back to your production dashboard and click on the Servers Tab which should look like this:

Click the Add Server button and specify the ip address and path from your production configuration from Forge. Repeat for the preflight project as well, but specify a different path and ip address as necessary.

As mentioned in Taylor’s article, when you hit Save you will be presented with a popup for a public SSH Key that needs to be added to Forge. Copy and paste this as a new SSH Key on your provisioned servers as instructed. I believe this is necessary for each project you setup in envoyer, so I usually name them as envoyer_domain_tld to keep them easy to identify.

SSL Key added to our production server

Return to Envoyer and click the refresh button under Connection status. if all is good you should see it go green.

Server configuration complete and verified

Final step for Envoyer is to set the .env settings that will apply to all deployments. Simply copy and paste the contents from your local development .env file and adjust as appropriate. Should look something like this — be sure to make sure the Sync To option is checked so your servers get the settings.

Setting env options for Production (repeat for preflight with different settings)

Step 7 : Deploy!

Trigger your first deployment and check your respective preflight and production urls your browser. If all is well, you should see it appear as Finished under your Recent Deployment list

Now the big test, you should see your HTTPS confirmation in your browser too!

From this point forward, simple PR’s into preflight and master branches wil auto-deploy to your QA and production environments respectively and developer-bliss will be achieved!

Conclusion

Hopefully this article was easy to follow and i definitely hope that you find it helpful. I welcome your feedback and suggestions for improvements or if I’ve off base on any steps!

--

--

Ted Nugent

Full-stack Laravel/PHP Developer, Photographer - That's my real name too. I play guitar, badly.