Automatic WordPress Deployment + Free SSL: Trellis How-To
A step-by-step video tutorial on setting up a local WordPress development environment in minutes using Trellis, plus how to deploy FAST with free SSL.
Elevator Pitch:
Set up a new WordPress site using the Roots stack.
Prerequisites
- A private server (we’ll walk through how to set this up for $5/month) — Trellis cannot run on a shared host, so this isn’t optional.
- Homebrew (v1.0.7 used in this tutorial)
- Git (v2.10.1 used in this tutorial)
- Ansible (v2.1.2.0 used in this tutorial)
- Composer (v1.2.1 used in this tutorial)
- Virtualbox (v5.0.18r106667 used in this tutorial)
- Vagrant (v1.8.5 used in this tutorial)
Part I: Install Trellis
To get things rolling, we need to grab a copy of Trellis from GitHub.
Create a new directory for the site.
Get a copy of Trellis to manage environments and deployment.
Since we want to track our copy of Trellis as its own project, we don’t actually want the Trellis repo information. By adding --depth=1
to the clone
command, we’re able to get only the most recently committed version (avoiding a lot of wasted bandwidth downloading the commit history). Then, we delete the .git
directory so we can have our own Git project.
Install Ansible dependencies.
One of the most powerful parts of Ansible is the ability to use community-supplied scripts — called “roles” in the Ansible world — rather than having to write them from scratch or copy-paste them from various forums and tutorials.
This collection of community roles is called Galaxy, and it’s home to thousands of roles. Trellis uses several of these to configure a WordPress server, so we need to get those installed.
Part II: Install Bedrock
We’re not going to do talk much about Bedrock, but the short version is this: Bedrock makes WordPress development on a team much less frustrating by:
- Using Composer to manage all dependencies — including WordPress plugins and the core itself — to make it easier to work with version control and develop across teams
- Easier environment-specific configuration
- Better security through directory structure improvements and the use of better password encryption
Get a copy of Bedrock to make WordPress’s file structure sane.
Just like we did with Trellis, we want to get a copy of Bedrock without the Git repository. So we do a shallow clone and then remove the .git
folder.
Part III: Configure a Development Site
With all the proper dependencies installed, we can start configuring our development site, which will run on our computer.
Add site details to wordpress_sites.yml
.
Open trellis/group_vars/development/wordpress_sites.yml
in your editor:
If you’re not familiar with YAML, it’s a common way of describing data. It’s indentation-based, so the default file creates a wordpress_sites
object, and that contains an example.com
object, which holds config properties (e.g. site_hosts
).
Each site is identified by a key — in the example, the key is example.com
— which allows us to link together our development, staging, and production environments without a bunch of duplicated configuration.
As a general rule, the production domain name is a good key to use.
With that in mind, let’s set up our site by making the following changes to wordpress_sites.yml
:
I’ll be deploying the site to a production domain of roots.code.lengstorf.com
, so that’s my site key. For local development, we’ll use roots.dev
as the URL, and we don’t need the redirects
here, so we can remove them.
Finally, we updated the admin_email
.
Save the changes and we’re ready to move on.
Add credentials to vault.yml
.
Next, we’ll open trellis/group_vars/development/vault.yml
:
Here we can see that the site key is example.com
, so we’ll need to update that.
We also need to update admin_password
, which is the password we’ll use to log into WordPress’s dashboard.
And finally, we’ll add strong passwords for the MySQL root user and the site’s DB access.
Make the following changes in vault.yml
:
Save the changes — now we’re ready to fire up a local development box.
Part IV: Start a Local Instance of the WordPress Site Using Vagrant
Here’s where the power of Trellis starts to become apparent.
Assuming the required software is installed, only four steps are required to get to this point:
- Clone Trellis.
- Clone Bedrock.
- Update
wordpress_sites.yaml
- Update
vault.yaml
When you compare that to the “normal” WordPress setup — clone WordPress, create a database, configure your local hosts
file to give you a development URL, and so on — Trellis is far simpler. And we’re not even to the really good stuff yet.
Start the development site.
To start the development site, it’s one simple command:
The first time you run this, it’ll take a 5–10 minutes. This is because Vagrant needs to download and configure all the pieces required to get the box up and running properly. After the first time, a lot of dependencies will be cached, which makes things much quicker for subsequent calls to vagrant up
.
Check the development site on your local machine.
Once Vagrant is done, we can open the dev site by visiting http://roots.dev/
in our browser.
Log into the WordPress dashboard.
To log into the WordPress dashboard, head to http://roots.dev/wp/wp-admin/
in your browser and use the admin_password
we set in vault.yml
earlier.
Part V: Configure a Production Server
Wait, what? We’re already deploying to production?
Yep. That’s how easy Trellis is.
Create a Digital Ocean droplet to host the site.
It’s hard to beat $5/month for hosting a website, so Digital Ocean will be our choice of production host.
To get started, create or log into your DigitalOcean account, then create a new droplet.
Choose Ubuntu 16.04.1 x64 for the distribution, $5/mo for the size, and choose any datacenter region.
Update hosts/production
.
To tell Trellis where the production server lives, we need to add its IP address to trellis/hosts/production
.
Make the following edits:
Enable free SSL and caching for production.
Setting up the production site configuration is nearly identical to the development site, except we need to add a few more settings for things like security. We can get these in place by editing trellis/group_vars/production/wordpress_sites.yml
:
Inside, make the following edits:
In addition to setting the site’s URL, we also tell Trellis where the source code can be found with the repo
setting, and enable SSL and caching for a faster, more secure site.
Add security settings to vault.yml
.
Next, we need to add passwords and encryption keys for the site. We do this by editing trellis/group_vars/production/vault.yml
:
Make the following changes:
Note that you can automatically generate YAML-formatted encryption keys using the Roots salt generator.
Encrypt sensitive data with Ansible Vault.
Since it’s always a bad idea to commit plain text credentials in a repo, we’re going to use Ansible’s built-in encryption to keep passwords and other sensitive data safe.
To do this, we create a password that will only be stored on our computer, which Ansible can use to decrypt the files. Trellis is already configured to ignore the password, so someone would need physical access to our computer to get the credentials.
Create a password for encrypting and decrypting files.
First, create a new file at trellis/.vault_pass
:
Open trellis/.vault_pass
for editing, then add a strong password:
Save and close this file.
Update the Ansible config to use the vault password.
Open trellis/ansible.cfg
for editing and add the highlighted line:
This tells Ansible where to look for the vault password, rather than prompting for it.
Use ansible-vault
to encrypt the files.
To actually encrypt the files, run the following command:
The output is a garbled mass of shit. This is a good thing — it means it’s encrypted. Here’s a snippet of what the encrypted file looks like:
Part VI: Provision the Production Server
Now that the proper configuration is in place, we need to let Trellis provision — or configure — the production server. Before we can do that, we need to update a few more configuration options, then make sure our source code is in a public repo and our domain name points to the production server.
Set up DNS so Let’s Encrypt can run properly.
Since Let’s Encrypt needs to verify the domain name in order to create an SSL certificate, we need to make sure the domain name points to the server before we try to provision it. Otherwise, we’ll get an error during the SSL step.
In your DNS manager of choice (typically the site you bought the domain name through, e.g. Namecheap or GoDaddy), update the A record for your domain to point to your DigitalOcean droplet’s IP address.
Use your GitHub keys for deployment.
To make sure cloning the repo on the production server goes smoothly, Ansible needs to know about your GitHub account’s public keys.
Open trellis/group_vars/all/users.yml
for editing, uncomment the GitHub URLs, and edit them to reflect your GitHub username:
Disable root login for better security.
This step is optional, but unless you have a really good reason to keep the root user enabled, it’s a good idea to disable it. The root user can wreak havoc on a server, so we can sleep better knowing that it’s disabled and can’t hurt anyone anymore.
Open trellis/group_vars/all/security.yml
for editing and change the highlighted line:
Commit the site’s code to GitHub.
For this tutorial, I created a repo called roots.code.lengstorf.com. You’ll want to create your own for this step.
To get our site’s code up to that repo, run the following commands:
Run the server provisioning script.
With the repo ready, the DNS configured, and some security measures in place, we’re ready to provision the server.
Provisioning means getting the server ready: Ansible will run through a series of commands that download, install, and configure our server based on the information we’ve provided in the configuration files.
To make it happen, all we need to do is run the following:
This takes about 5–10 minutes. The output in the command line walks through everything that’s being installed and configured, so if you’re curious you can follow along and see what the Roots maintainers consider best practices for server configuration.
Or, we can walk away and let the robots do our bidding.
When it’s all done, we’ll see a “play recap” from Ansible that looks something like this:
With 0 failures, we’re ready to deploy!
Part VII: Deploy the Site to Production
Our last step — deploying our WordPress site to the DigitalOcean droplet — is really fucking easy — even compared to the rest of the steps in this walkthrough. We’ve already configured everything. We’ve already committed all our site’s files to GitHub. We’ve already provisioned a server.
Now we just need Ansible to copy the site files and fire it up.
Enter the following to make it happen:
This takes a minute or two, and ends with a “play recap”, just like provisioning. It should look something like this:
Check the Live Site
And that’s it. We’ve successfully deployed an SSL-secured (for free), painlessly-source-controlled WordPress site on a live domain name, all for about 20 minutes and $5/month.
BONUS: Synchronize Databases Using WP Sync DB
Trellis only manages files, so you’ll notice that the new site doesn’t match up with the development site. This isn’t a big deal when you first start out, but as the production site starts to grow and the content builds up, it’s a pain in the ass to pull a copy of the database so you can develop using real data.
Fortunately, the free plugin WP Sync DB makes synchronizing databases really painless. So let’s install that and try it out.
Install WP Sync DB on the site.
Since we’re using Bedrock, installing the plugin is as simple as telling Composer we want to use it.
Commit and redeploy to production.
After WP Sync DB is installed, we need to get it installed on the production server. This is a good example of how easy it is to deploy changes using Trellis: if you run git status
, you’ll see that composer.json
and composer.lock
have been updated; simply commit and push those files, then redeploy to production.
Activate WP Sync DB on the production site and get the API key.
Once the deploy is complete, go to the production site’s WordPress dashboard (e.g. https://roots.code.lengstorf.com/wp/wp-admin/
), log in, then click “Plugins” in the left-hand menu.
Activate both the “WP Sync DB” and “WP Sync DB Media Files” plugins, then navigate to “Tools”, then “Migrate DB” in the left-hand menu.
Click the “Settings” tab, then do the following:
- Check the “Accept push requests…” option.
- Copy the link in the “Connection Info” box.
Now the plugin is able to receive a database update from an external site (our development site, in this example).
Activate WP Sync DB on the development site and configure the sync.
On your development site, head to the “Plugins” page on your WordPress dashboard to activate the WP Sync DB and WP Sync DB Media Files plugins, then navigate to Tools > Migrate DB.
On the “Migrate” tab, update the settings as shown:
- Choose the “Push” option.
- Paste the production site’s connection info into the text area that appears (what we copied in the previous step).
- Under Advanced options:
- Uncheck the “Replace GUIDs” option.
- Check the “exclude spam comments” option.
- [OPTIONAL] Check the “Backup the remote database before replacing it” option. This is probably a good idea if the production site has real data on it.
- Check the “Media Files” option.
- [OPTIONAL] Check the “Save Migration Profile” option and create a name so you can quickly push changes to production.
Once all these settings have been updated, click the “Migrate DB & Save” button.
Once this is done, you can reload the production site and see that the database from the development site is now live on production.