Thursday, December 29, 2016

Using Forge To Provision And Manage WordPress Sites

I used to claim I didn't know anything about servers. And, while I'm not an expert, I have learned quite a bit in by time as a web developer. I use Ubuntu every day, both as my desktop computer's OS and as the OS for the virtual machine I host my WordPress sites.

Though I've learned a lot, I couldn't set up my own server — or really a Virtual Private Server (VPS) without help. However, I've become familiar Laravel Forge, a server provisioning and deployment tool created by the Laravel project that is easy to learn. While it is designed primarily for Laravel projects, which is what I first used it for, it works great for any PHP app, including WordPress.

In this article, I want to walk you through why and how I recently built and deployed the new CalderaForms.com using Composer and the WP Starter project — and set up its server on AWS using Forge.

Why Forge?

Forge provides two main features – automatic provisioning of a VPS on Amazon, Digital Ocean, or similar and automated deployment. There are many other products that offer one or both of these services. For example, Easy Engine provides automated provisioning of VPSs on Digital Ocean for WordPress and DeployHQ provides similar automated deployment. I've used both before and they are excellent.

I recently started Forge for managing a few Laravel apps I have built, which is what it was intended for. Also, the $10 a month you pay for it, helps support an open source project.

For the relaunch of the Caldera Forms site, I wanted to manage all of my dependencies — plugins, theme and WordPress with Composer, both locally and on the live site. So I figured, since it's a tool for provisioning and deploying PHP applications, it should work fine for WordPress. And it did.

Why WP Starter?

I actually had my local site built first using WP Starter by We Code More a group of WordPress developers. WP Starter is primarily authored by Giuseppe Mazzapica. I have used a few different boilerplates for managing WordPress with a composer, including my own.

I like WP Starter because it uses .env variables for its configuration, and has a pretty simple setup. In addition, it handles loading the Composer autoloader, moving the content directory out of the main WordPress directory, creating a proper index.php and wp-config files to work with this setup. It is also really well documented.

WP Starter also has some cool tricks I've never seen before, which I will walk through in the next section.The biggest reasons I went with WP Starter is that it is purely a PHP system — I don't have to write any Ansible or Puppet scripts. I am uncomfortable with any script I don't know how to modify, which is why I try and stick to automating all of my tasks with something written in PHP or JavaScript. Also, using the .env for configuration made it very easy to set up with Forge.

What Is An Env Variable?

WordPress makes use of a lot of constants to define its configuration. For example, in wp-config, we define the database configuration using constants. As a result we store sensitive information in wp-config making it so the full stack of a site doesn't have to be open source. In addition, wp-config becomes environment specific.

Both of these concerns violate the principle of the Twelve factor app. I was first introduced to this philosophy when Scott Walkinshaw published the Twelve Factor WordPress App, that addressed building better WordPress stacks using the Twelve Factor methodology and formed the basis of the Roots Bedrock and later Trellis projects.

In that series of posts, I was introduced to environment variables. They are variables — set on the server — that are available to the application. By using references to a server's environment variable, the application's configuration is no longer tied to the environment and when used in wp-config, that file no longer stores sensitive information.

We can use the phpdotenv to easily access environment variables in PHP. This package is used in WP Starter, Bedrock, Trellis, and Laravel. Using a simple .env file, and this package, variables can be loaded into the $_ENV super global.

Setting Up Locally

First, let's walk through building the local site using Composer and WP Starter. I used VVV to provision a new site, you can use whatever local environment you like, it really doesn't matter.

Once the local site is provisioned, you will need a composer.json file. Here is a good starter:

{ "name": "your-name/yoursite-name", "description": "Example project for WordPress + Composer + WP Starter", "type": "project", "repositories": [ { "type": "composer", "url": "https://wpackagist.org" }, { "type": "vcs", "url": "https://gist.github.com/Giuseppe-Mazzapica/e8c8e4dfc8e65f1903ac.git" }, ], "require": { "wecodemore/wpstarter": "~2.0", "wpackagist-plugin/wp-super-cache": "*", "wpackagist-plugin/caldera-forms": "*", "gmazzap/wpstarter-example-files": "*" }, "require-dev": { "wpackagist-plugin/query-monitor": "2.7.*" }, "config": { "vendor-dir": "public/content/vendor", "optimize-autoloader": true }, "scripts": { "post-install-cmd": "WCM\\WPStarter\\Setup::run", "post-update-cmd": "WCM\\WPStarter\\Setup::run", "wpstarter": "WCM\\WPStarter\\Setup::run" }, "extra": { "wordpress-install-dir": "public/wp", "wordpress-content-dir": "public/content", "wpstarter": { "dropins": { "object-cache.php": "public/content/vendor/gmazzap/wpstarter-example-files/object-cache.php" }, "prevent-overwrite": [ ".gitignore", "public/wp-config.php", "public/index.php" ], "env-example": "public/content/vendor/gmazzap/wpstarter-example-files/.env.example", "gitignore": { "wp": true, "wp-content": true, "vendor": true, "common": true, "custom": [ "*.log", ".htaccess", "sitemap.xml", "sitemap.xml.gz" ] } }, "installer-paths": { "public/content/plugins/{$name}": [ "type:wordpress-plugin" ], "public/content/mu-plugins/{$name}": [ "type:wordpress-muplugin" ], "public/content/themes/{$name}": [ "type:wordpress-theme" ] } } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

{

    "name": "your-name/yoursite-name",

    "description": "Example project for WordPress + Composer + WP Starter",

    "type": "project",

    "repositories": [

        {

            "type": "composer",

            "url": "https://wpackagist.org"

        },

      {

            "type": "vcs",

            "url": "https://gist.github.com/Giuseppe-Mazzapica/e8c8e4dfc8e65f1903ac.git"

        },

    ],

    "require": {

        "wecodemore/wpstarter": "~2.0",

        "wpackagist-plugin/wp-super-cache": "*",

        "wpackagist-plugin/caldera-forms": "*",

        "gmazzap/wpstarter-example-files": "*"

    },

    "require-dev": {

        "wpackagist-plugin/query-monitor": "2.7.*"

    },

    "config": {

        "vendor-dir": "public/content/vendor",

        "optimize-autoloader": true

    },

    "scripts": {

        "post-install-cmd": "WCM\\WPStarter\\Setup::run",

        "post-update-cmd": "WCM\\WPStarter\\Setup::run",

        "wpstarter": "WCM\\WPStarter\\Setup::run"

    },

    "extra": {

        "wordpress-install-dir": "public/wp",

        "wordpress-content-dir": "public/content",

        "wpstarter": {

            "dropins": {

                "object-cache.php": "public/content/vendor/gmazzap/wpstarter-example-files/object-cache.php"

            },

            "prevent-overwrite": [

                ".gitignore",

                "public/wp-config.php",

                "public/index.php"

            ],

            "env-example": "public/content/vendor/gmazzap/wpstarter-example-files/.env.example",

            "gitignore": {

                "wp": true,

                "wp-content": true,

                "vendor": true,

                "common": true,

                "custom": [

                    "*.log",

                    ".htaccess",

                    "sitemap.xml",

                    "sitemap.xml.gz"

                ]

            }

        },

        "installer-paths": {

            "public/content/plugins/{$name}": [

                "type:wordpress-plugin"

            ],

            "public/content/mu-plugins/{$name}": [

                "type:wordpress-muplugin"

            ],

            "public/content/themes/{$name}": [

                "type:wordpress-theme"

            ]

        }

    }

}

Let's walk through this because some of it is not very common. This looks pretty normal at first, though one thing you may note is that a gist file is being used as a repository. I didn't know that you could do that until I used WP Starter, but you can. Files from that Gist are used later on for loading the object cache drop-in, creating an example .env file and more.

I prefilled the require and require-dev sections with a few plugins coming from wpackagist.org as examples. Note that Query Monitor is included as a dev requirement, that way it will be installed on the local site, but not live.

In the config section, the path for the vendor directory is moved into the WordPress content directory. This is useful for organizing things the WordPress way. Below that, the install scripts that WP Starter provides are specified. Again, I love that all of this is done using PHP scripts. I didn't need to modify these scripts, but if I need to I feel confident doing so because they are in PHP.

Below that is the extra section, which has lots of interesting stuff. In addition to setting up install paths, something I covered in an earlier article for Torque, all configurations options for wpstarter are setup. You can read the docs for more information, but one thing I found really cool is how it can be used to configure dropins. The example composer.json I have shown specifies which object cache drop in to use.

You should add the other plugins, and probably a theme to the composer.json before going further.

Once you have your composer.json set up, switch in your terminal to the project directory and run "composer install." After that, you will have a complete WordPress site, with all of the files — including your plugins and themes, as well as WordPress set up and ready to go. That is except the .env file.

You will see a .env.example file in the project. Change the name of that to .env. This file has all of the configuration options you need for your WordPress site and is very well documented. You can see the full content of it here.

Open up your .env file and look at the section near the top "MANDATORY DATABASE SETTINGS". You will need to set your database name, username and password there. That is all you have to do to make your site work.

This file names all environment variables the same as their corresponding constants. So for example if you want to set the WP_SITEURL constant, find the line #WP_SITEURL=, remove the # and then put the value after the = sign. That's it.

Now if all has gone well you should have a WordPress site working locally. You can commit everything to the site's Git repo and even host that repo publically. Your sensitive information is not stored in the repo. In addition, none of the dependencies are either. Updating a plugin or WordPress is a one line change.

If you have another developer working on the project. They can clone the repo, setup the .env file with their own local database and be ready to work.

Setting Up The Server

Once the local site is working, it needs a compatible deployment system. For this, I used Laravel Forge because the servers they provision have everything I needed: PHP7, MySQL, Memcached, and Composer. The provisioning system is super easy once you connect your Amazon or Digital Ocean account. Also, they make adding SSL certificates, your own, or Let's Encrypt, super simple.

To get started, create a Forge account and sign in. From the account page, under the servers page, you can provide Digital Ocean, Linode or AWS credentials and verify the connection.

Then go to the server's page, select the type of server, in my case I used Amazon, set the server name, and size, as well as PHP version. As of when I wrote this, all three versions of PHP — 5.6, 7.0 and 7.1 beta were available. Then click Add Server. This takes a while, go get more coffee.

screen-shot-2016-12-29-at-8-44-59-am

While Forge recently added a WordPress option, I still recommend their Laravel/ PHP option. The WordPress option is designed for simple WordPress sites, not WordPress applications or anything using proper dependency management.

Once the server is configured, navigate to that server's configuration page, and go to the MySQL tab and use it to add a new database table and a user to that table. Make sure to keep the password for that SQL user handy.

Once created, go back to the sites tab and create a new site:

screen-shot-2016-12-29-at-8-48-45-am

Once the new site is created, its management screen will ask you to attach a Git repo. In my experience this is seamless with Bitbucket. It takes a few extra steps to connect with Github, but it works if you follow the instructions.

Once the repo is connected, go to the Environment tab, and click the "Edit .env" button. This will open a popup you can use to modify the .env file for your application. It comes preset for Laravel, which isn't too useful. Luckily you can use the .env.example file from WPStarter as your basis. Just make sure to use the MySQL details you set up for this server. Save that when you're done.

Now the last step is to modify the deploy script. Again, the default is created with Laravel in mind. For example, the deploy script that is there by default calls an artisan command. Artisan is like WPCLI, but for Laravel.

Here is what I used for my deploy script:

cd /home/forge/default if [ -b "public/index.php" ] then rm public/index.php fi git pull origin master composer update --no-interaction --no-dev --prefer-dist

cd /home/forge/default

if [ -b "public/index.php" ]

then

  rm public/index.php

fi

git pull origin master

composer update --no-interaction --no-dev --prefer-dist

Notice that this is a standard bash script. You can customize it anyway you want. Since WPStarter generates a new index.php file, I had my deploy script delete the existing one first. This solved an issue that was causing my second deploy to fail. After that, I just pull changes on the Git repo and run Composer.

In the future I plan to install WPCLI — Forge provides an easy way to add your SSH keys to the server. Then I can use WPCLI as part of my deploy process.

With the deploy script in place. You could be ready to hit deploy and go. But you should probably click on the SSH tab to setup SSH. Adding a SSH certificate using LetsEncrypt just takes a few clicks and a few minutes. Redirects from HTTP to HTTPS are handled automatically. You can also add your own certificate if you want.

screen-shot-2016-12-29-at-9-05-22-am

Once everything is set, go ahead and hit deploy. One thing you will notice is that Forge only alerts you to failed deploys. There is no indication that it went right. I connected Forge to my Slack channel to send me all notifications.

That's about it, but Forge can do a lot more. You can configure CRON jobs, automated deploys and even build a network of load balanced servers. I encourage you to dig into what it can do. I know I am.

Getting Comfortable With Servers

For the most part my sites are on a managed WordPress host because it makes my life easier. But there are trade-offs, especially in terms of tooling. Using Forge, which I was already using since I needed an easy way to make my Laravel apps live, makes it simple for me — someone who doesn't really get servers — to provision a VPS and setup sensible deployments.

I hope this article has taught you a bit about how to use this cool tool, as well as a little more about Composer and why using environment variables is awesome.

Josh Pollock

Josh is a WordPress plugin developer and educator. He is the owner and a developer for CalderaWP, makers of Caldera Forms, a different kind of and Ingotthe native WordPress A/B testing solution.


Source: Using Forge To Provision And Manage WordPress Sites

No comments:

Post a Comment