It’s no secret that the Roots theme is a robust starter theme for serious WordPress professionals. It uses Bootstrap and integrates Grunt to enable seasoned WordPress developers to create outstanding sites while using a modern workflow. I’ve been using it as my starter theme for custom WordPress sites for the past three years and I couldn’t be happier.
Roots also has a twelve factor app called Bedrock for taking WordPress development to the next level with Composer for dependency (i.e., plugin) management and the ultimate goal of enabling developers to deploy WordPress with Capistrano rapidly, securely, and with a single command.
I have not had much exposure to Ruby, which powers Capistrano, but the twelve factor app methodology’s organization and single command deployments (and rollbacks) appealed to me, so I wanted to try it out on a small project, namely the revamp of this site.
For now this site is hosted on Bluehost and I’m comfortable in this dev environment, so I wanted to get my feet wet here with Capistrano and not worry about simultaneously jumping into possible server config issues. What better way than to deploy my revamp using Bedrock?
Bedrock is aimed at developers hosting WordPress on VPS servers running Nginx, and since I will be bucking the trend pretty hard by deploying to a shared host running Apache, I thought my first post should chronicle the steps I took for a successful Bedrock deployment.
Before going through these steps you should already:
- Be comfortable using a command line interface.
- Be comfortable using Git for version control; you should be able to commit, push, and pull from both your localhost and your shared host without errors. NB, I use Bitbucket for free private Git repos.
- Read through the Bedrock documentation and install its required applications. Note: Composer is not listed as a Bedrock requirement but I will assume you have it installed on your localhost.
I’m running OS X and my shared host is Bluehost, but Dreamhost, Hostgator, and other shared hosts running cPanel should work with some minor differences; a quick Google search should help you if you’re running Windows or if you get stuck. If you’re on GoDaddy then get off of it. So let’s get Bedrock setup and deployed!
1. SSH Access
You absolutely need SSH access to your shared hosting account. I won’t go over that in this post because it’s been widely addressed. Here are Bluehost’s SSH instructions.
Also, my SSH connection uses authorized keys without prompting me for a password so that is how I went through this process, I recommend you setup authorized keys on Bluehost too.
2. Get Bedrock
Create a new project directory on your localhost and clone Bedrock:
$ git clone https://github.com/roots/bedrock.git .
3. Install Dependencies
Bedrock manages its dependencies with Composer. WordPress itself is even one of Bedrock’s dependencies, so to install WordPress and its other dependencies run:
$ composer install
4. Set Environmental Variables
One of the big goals Bedrock has is to separate configuration files from your WordPress sites, particularly when they contain sensitive information (i.e., login credentials and passwords). It keeps these tucked away in a .env
file, which we can create by using the example it ships with:
$ cp .env.example .env
This file should be self explanatory if you’re relatively experienced with WordPress. Make sure you enter your localhost credentials here. Once that is setup you should be able to access your site from the URL you entered in .env
.
If you’re lost, check out the Bedrock quick start documentation.
5. Add a Theme and Get to Work!
Now you can add your theme, create a Git repository, and make some commits which we will deploy in the next steps.
6a. Setup Your Subdomain or Addon Domain on Bluehost
Setup your folder structure as you would for creating a new project: either create a new subdomain or addon domain.
Ensure sure your config is set to use PHP 5.4, not PHP 5.4 (Single php.ini) and not PHP 5.4 (FastCGI).
Then create your database, add a user to the database, and import your database content from your localhost (if necessary). Remember to change your URLs and account for serialization (i.e., don’t just search and replace, I personally like Peach).
While we’re in phpMyAdmin (on Bluehost), you will need to change your wp_options.siteurl
entry to http://dev.example.com/current/web/wp
.
6b. Install Composer on Bluehost
I found the best place to install Composer is in your home directory (~), and was able to do it quickly1:
$ curl -sS https://getcomposer.org/installer | php
The -sS switches just prevent curl
from displaying its download progress but enable the display of error messages on failure.
Once that’s done you should be able to verify Composer was installed by running:
$ php-cli composer.phar
And while we’re here:
cd
into your home directory (~) and do a quick$ pwd
–save the result somewhere handy- type
$ which bash
–save the result somewhere handy
7. Create a Temporary Directory for Capistrano
During my deploy, Capistrano tried to access the /tmp/
directory and failed because it did not have permission. So, while in my Bluehost shell I did a quick:
$ mkdir ~/capistrano_tmp
In step 8 we will configure Capistrano to use this temporary directory instead of /tmp/
…
8. Setup deploy.rb
Back on your localhost, the Bedrock directory should have a file we need to edit: config/deploy.rb
.
Line 1: the application name should be the directory (relative to ~/public_html/
) where you setup your subdomain or add-on domain.
Line 2: change the URL to your Bitbucket repo URL. Mine looked like git@bitbucket.org:my_username/my_repo.git
.
Line 12: change /srv/www/
to your server directory–the one we found at the end of step 6b–and add a trailing /public_html/
. So if step 6b revealed your server directory to be /home2/whatever
, your new line 15 should read:
set :deploy_to, , -> { "/home2/whatever/public_html/#{fetch(:application)}" }
Line 14: change :info
to :debug
in case your deployment fails and you need help figuring out where it went wrong.
Line 16: change this line to read set :linked_files, %w{.env web/.htaccess}
2.
Line 18: should be empty but we need to tell Capistrano to use the temporary directory we created for it in step 7 using the server path we saved from step 6b. Add this line:
set :tmp_dir, "/home2/whatever/capistrano_tmp"
Now let’s grab the result from $ which bash
and $ pwd
that we saved from step 6b and add these lines at the end of the file:
SSHKit.config.command_map[:bash] = "%YOUR_BASH_PATH%"
SSHKit.config.command_map[:composer] = "php-cli %YOUR_HOME_PATH%/composer.phar"
Here is my finished file:
I rearranged the last two lines but you can order those any way you like.
9. Setup staging.rb
On your localhost, open up config/deploy/staging.rb
. All we need to change here is line 11 by adding our server URL and our username. These should be the same credentials that you use when connecting to Bluehost via SSH.
10. Deployment Check
Let’s have Capistrano prepare for our deploy and create its folder structure and symlinks by running (on your localhost):
$ bundle exec cap staging deploy:check
I’m assuming you’ve called the stage we’re deploying to staging
, but you can call it anything.
11a. Final Prep
Assuming your deploy:check
went well, let’s copy our local .env
to our remote project’s shared/
directory.
While we’re in shared/
, create a directory called shared/web/
and copy the .htaccess
file you want Bluehost to use into shared/web/
. I used the one from my localhost and it works fine for now.
Now edit your remote shared/.env
file and add the Bluehost database credentials for your remote WordPress installation.
Finally, change line 6 to reflect the name of your stage; mine is called staging
, so my line reads:
WP_ENV=staging
11b. Setup mod_rewrite
You won’t be able to view your site after it’s deployed unless you add some mod_rewrite
rules. If your remote project directory is ~/public_html/dev.example.com/
, create a new .htaccess
file there:
Finally we can…
Deploy WordPress with Capistrano
Whew, seems like we’ve been through a lot together and now we’re finally ready to deploy! So push all of your commits and run $ bundle exec cap staging deploy
and let ‘er rip! If you followed these instructions then you should be well on your way to one line deploys with WordPress + Bedrock + Capistrano + Bluehost! If you experience any issues or have any questions then leave a comment and I will reply.
Thank You
A huge thanks goes out to the Roots team and Bedrock team. They’ve created and maintained exceptional code and helped me through this process. Thank you!
- http://penawebservices.wordpress.com/2014/01/14/installing-composer-on-bluehost-com/ ↩
- “If you use Apache for your web server… by default Bedrock ignores the
.htaccess
file both in the version control AND in the deploy configurations. What this means is that not only is your local.htaccess
not sent to the server during a deploy, but even if you manually put one on your server it will be deleted each time you deploy. That’s a big problem for using WordPress. To fix this, add theweb/.htaccess
to the linked files setting indeploy.rb
, and then put an.htaccess
file in theshared/web
folder on the server (you’ll have to create theweb/
folder). Your production.htaccess
file shouldn’t change very often and is likely to deviate from your development.htaccess
file, so keeping it out of the normal workflow and version control is the way to go.”
–http://efeqdev.com/tutorial/using-bedrock-for-wordpress-for-the-first-time/ ↩
It’s April 2020 but this article still helped me to configure the htaccess file. Some other steps maybe redundant by now as I found Composer to be working by default on this client’s hosting server that I’m currently working. Thanks for taking time to write such a well-laid out article!
Hi Michael,
First of all, thank you very much for this very well-written post. I followed the steps and did managed to deploy a bedrock site to a subdomain on shared hosting. The strange thing here is that after everything is all setup, I couldn’t login to admin. Was trapped in the redirect loop to the login page. Could this be how I setup the mod_rewrite rules which is following your step 11b of your article? The path to my subdomain is ~/subdomain instead of ~/public_html/subdomain.
By the way, I also have some (failed) steps when running ‘bundle exec cap staging deploy’. Picking out only the error message here:
Have you experience this previously when you are deploying this to shared host?
Thanks for a lot in advance. Hope you can point me to the right direction.
Regards
Thanks for the quite indepth tutorial!
I have a question about Step 8, Setup deploy.rb
How would you handle this if you wanted different domains/subdomains for staging and production deployments.
I’m working on Siteground and have my directories setup like
public_html/example.com/
public_html/staging.example.com/
It seems that the deploy.rb script wants you to specify one application name that is used to set the deploy_to path.
Am I missing something here?
Hello, Michael.
The deploy worked fine for my WP site. All files are located where they should be. However, the site won’t load, I just get a blank screen when I try to load it. Have you experienced something like this before? I think maybe it is something to do with my wp-config.php file.
Thanks for your help.
Hi Guilherme, did you check your server logs for errors? Also make sure your files and dirs have proper permissions (644 and 755, respectively).
Hi Michael,
first of all, thanks for your article that helped me understand bedrock a few months ago!
After many installs, I realize that my folders and files don’t have the right permissions (775/664) after deployments.
How do you manage the change to 755/644 by your side?
Thanks again,
Frédéric
Hi Fred,
Run these on your remote in your WordPress root dir:
$ find . -type d -exec chmod 755 {} \;
$ find . -type f -exec chmod 644 {} \;
Source
Hi Michael,
thanks for your prompt answer.
I thought you would add it through the capistrano process.
Do you run the scripts each time you deploy your app?
Sorry for my long post above, actually you can delete it now. I now know I haven’t done the SSH thing properly.
What I have done about it so far is,
1. Enable SSH Access on Bluehost as in here
2.Create Public and private keys and authorize it as in
Since I am running windows I installed Putty & Puttygen and successfully establised a SSH access to my bluehost server using the private key I downloaded from bluehost.
But I wonder how the
bundle exec cap
can communicate to the bluehost server, because I don’t see a place inside the 11 steps above that does something about enabling my capistrano to get SSH access to my bluehost server.I also wonder how it can get access to my bitbucket repo as I haven’t done anything to grant it access. Please give me light on this.
I have seen the documentation at but couldn’t apply it directly to my context(Running windows).
Please Help. Thank you!
how do I know if the command has successfully executed or not. Mine returned with this.
Please let me know if this is what I should expect, BTW It didn’t do anything on my bluehost.
Assuming am correct, I continued on the next steps and run the deployment command
bundle exec cap staging deploy
Thanks for your wonderful post, I have been doing my wordpress deployments over FTP, which almost made me bored. Thanks to the bedrock stack it seems I have the chance to do it professionally. I have followed ur steps and made it as far as 11a, then I paused. Where is the the shared/ thing on my bluehost really? Is it public_html/mysite ???
EDIT: sorry my first comment had the first rewrite rule changed.
…I was having exactly the same problem. What I did was modify this line on the WordPress generated code in the .htaccess:
RewriteRule . /index.php [L]
to this:
RewriteRule . /current/web/index.php [L]
and then set the permission to the .htaccess file to 444 so WordPress cannot override it later. Hope this helps.
I seem to have everything working for my deploy except when I run it I get the following failures:
and
and
Everything else is successful. Anyone have any idea what is causing this and how to fix? It’s tough to be so close to the finish line on this.
I am experiencing similar problem as yours. Did you managed to find a solution? Look forward to your advise.
Thanks
So… I’ve got it pushing to my host following the instructions here, but when I try and push another update using cap deploy staging it errors out here:
Tasks: TOP => deploy:check:make_linked_dirs
Here’s the line for my linked directories on staging.rb:
set :linked_dirs, %w(‘web/app/uploads’)
I want to get this working in a test app before I start using it for actual applications.
Hello, mate!
Very good tutorial — got my deploys working to a shared server with A Small Orange, but I have encountered one problem upon further investigation: I can’t choose nicely structured Permalinks.
For example:
http://mysite.ca/?p=1
works, buthttp://mysite.ca/hello-world
doesn’t.I’ve been making little tweaks here and there to the .htaccess file as well as tried a bunch of different URL combinations, but haven’t gotten anything to show up with any other than the default Permalinks.
Moreover, I’ve noticed that this site has pretty links, so I was wondering if there was an extra step you took in your .htaccess file (or some code-level change it would be possible to make) that enabled you to do that.
If not, I’m kind of stumped so I suppose I’ll just keep the ugly links.
Hi Paul, thanks for the kind words and I’m glad you found this useful enough to get yourself up and running with Capistrano. Unfortunately for you I never encountered an issue like that with my site’s permalinks. I highly suggest that you post your issue with more details over on the WordPress Stack Exchange. Be sure to describe your hosting environment in more detail and even paste the contents of your
.htaccess
. Please also reply here with the link to your question so that other readers and I can have a look and hopefully someone among us can help you sort out your permalinks. Thanks!…I was having exactly the same problem. What I did was modify this line on the WordPress generated code in the .htaccess:
RewriteRule . /current/web/index.php [L]
to this:
RewriteRule . /current/web/index.php [L]
and then set the permission to the .htaccess file to 444 so WordPress cannot override it later. Hope this helps.
The edit goes in the .htaccess file that is located in
web/shared
correct?EDIT: sorry my first comment had the first rewrite rule changed. Also I forgot to hit reply. Damn i’m slow today.
…I was having exactly the same problem. What I did was modify this line on the WordPress generated code in the .htaccess:
RewriteRule . /index.php [L]
to this:
RewriteRule . /current/web/index.php [L]
and then set the permission to the .htaccess file to 444 so WordPress cannot override it later. Hope this helps.
Thanks for the tutorial! It’s taken me much closer to successfully deploying my site.
Unfortunately, I’ve been hung up on a single error for a while now, and can’t seem to figure it out. I’m a beginner with capistrano and google searches don’t turn much up for this error. In step 10, when I run the
deploy:check
command, capistrano returns the following error:In the tutorial, you create the
.env
file in step 11, after you rundeploy:check
, so it’s confusing to me that I would have this problem at all. In any case, this error prompted me to create theshared/
directory and the.env
file, which I assumed would solve the problem—alas, capistrano still complains that.env
does not exist, even though I’m sure it does.Any help on this issue would be much appreciated.
Funny – fixed this issue moments after I posted to your blog. You can delete both of these comments now (it was a stupid error on my part, no point in leaving the comments).
I’d like to leave your comments up in case anyone else comes across a similar issue. You might consider posting the solution that worked for you so others can bask in the Capistrano light! 😉
Fair enough. The issue was that I didn’t have a forward slash at the beginning of my deploy_to line (in front of the home directory). In other words, I had…
set :deploy_to, -> { "home//#{fetch(:application)}" }
instead of
set :deploy_to, -> { "/home//#{fetch(:application)}" }
A beginner’s mistake, I admit. But it was particularly hard to track down, because all Capistrano could tell me was that the .env file didn’t exist.
Nice post! I had not heard of Peach before, I’m sure that will come in handy. FYI, wp-cli also handles serialized data when doing search-replace on the DB and I’m in the process of editing my Capfile to make use of it. I’ve had success doing Cap deploys on Bluehost, Site5, Dreamhost and Media Temple. I’m about to check out Siteground and Flywheel which seem like new strong hosting contenders.
If you’re interested, I have a slightly different take on deploying with Capistrano that I wrote about here: http://karveldigital.com/how-to-deploy-wordpress-with-capistrano
Sadly, I have not yet jumped on the Grunt or Gulp train, but it’s on my list!
Thanks Kronda, I actually read your article and watched the screencast a while back and it’s definitely a must read! My deploy is pretty specific to Bedrock because I’m a diehard Roots developer.
Roots also introduced me to Grunt which quickly became indispensable in my workflow. If you have some time to check it out the documentation makes it quite easy to dive right in. You’ll be building minified JavaScript and CSS so fast your head will spin and you’ll wonder how you ever developed without it!
I’ve had success on some shared hosts changing the public_html folder to a symlink, that links to the current/app (or current/web) capistrano folder, contained in a another directory above public_html, on the account.
However, this doesn’t always work–it depends on the host (worked on Host Gator, but not on Media Temple grid, for example). And you have to watch folder permissions. For getting this to work on Host Gator, I had to remove group write permissions from the deployment folders as one of my deployment tasks (this was to undo the permissions that capistrano added automatically, which violated the server configuration and broke the site).
Hi Grant,
I’ve just tried this as well (Godaddy, ho-hum). With a symlink to ~/public_html/deploy_folder/current/web/ as ~/public_html/a_subdomain, which as the name implies is the root for a subdomain.
Oddly the page loads, but the theme styling got lost completely, even though I can access all the files via the symlink in the shell and they seem to be accessible through a web-browser.
The internal wordpress themes work … the wordpress mod_rewrite rules seem to work as well …
Is my .env files setup incorrectly now? I’ve changed the paths to subdomain.domain.com and subdomain.domain.com/wp.
It worked previously when just had everything sit in the root of a subdomain folder in public_html, but the unnecessary links (subdomain.domain.com/current/web/) annoyed me and I’m terrible at .htaccess files and mod_rewrite.
Anyone, any ideas? I’m at my wit’s end.
Thanks!
mike
Hi everybody,
I found my mistake. It was a trailing slash in the .env files that screwed up the paths for my roots-theme styling (ah, what a beginner’s mistake).
But I can confirm that having a subdomain point directly to the symlink web folder works well, so does a symlink folder pointing to the web folder.
And it works on cheap goDaddy Linux hosting, though you are limited to only one SSH account. At least I couldn’t add any users via the command line, as the Capistrano guides recommend doing.
Great guide, Michael! Definitely saved me a lot of sweat and tears.
I’m a bit disappointed that the roots people put up only a half-hearted documentation on the whole bedrock thing and then put the screencast for capistrano behind a paywall.
Pip-pip,
Mike
Wondering if it is possible to deploy production to the www/bare domain instead of a subdomain.
IOW: cap deploy the production (live) version to the root (public_html) because that is where cpanel automatically accesses the domain’s doc root.
Thanks for writing this up! Great reference!
I did that for this site in a way, but sometimes I need to host staging subdomains on this account and I didn’t want this site’s files and directory structure cluttering my
~/public_html/
directory so it’s actually deployed to~/public_html/cfxdesign.com/
. It’s definitely doable, it just takes a bit of.htaccess
trickery. Instead of putting the.htaccess
withmod_rewrite
intoshared/web/
I stuck it in my~/public_html/
directory and edited it accordingly.shared/web/
just contains a default WordPress.htaccess
. The only caveat is that my~/public_html/.htaccess
needs to haveAddHandler application/x-httpd-php54 .php
at the top to ensure the correct version of PHP, along with Bluehost’sphp.ini
.Thanks Michael. (And Grant for the symlink idea).
Have either of you used this env to update the databases and sync uploads folder on staging and local dev systems? Essentially pulling the current database/uploads dir to the dev copies in order to have a duplicate of the system as published?
I’m taking steps in that direction because I’ve already been doing it manually. That workflow isn’t suited to every project (think ecommerce where potentially sensitive custom info might be stored in the db) but for smaller informational apps I don’t see any huge issues. I’ve had great success using
grunt-exec
andgrunt-peach
separately. When I get them working nicely together then I will definitely be writing a post on it… which should be soon.Just posted WordPress Database Sync with Grunt!