Deploying a Joomla site with Capistrano

What's your deployment strategy for Joomla! sites? Complex changes to your site can often involve changes to:

  • Your site files
  • Your database schema and or information
  • Updates to project dependencies

If a change to your site involves all three, how do you manage this change? How can you be sure of replicable results? How can you roll back these changes in the event of a problem?

Perhaps most important of all, how can you manage all three at the same time and have zero downtime on your site?

Capistrano to the rescue

We've used Capistrano at Joomlatools for years now.

Described as:

A remote server automation and deployment tool written in Ruby. 

It can help you with the process of shipping changes from your development environment to staging before releasing them into the live service.

By having automated steps you can be assured of consistent results everytime, no more finger trouble. However in the event of problems with your changes, you can rollback with ease.

In this tutorial, we'll show you how to set up Capistrano and deploy a Joomla site using our Joomlatools Vagrant box.

1. Create a new Joomla site

Let's start the vagrant box and SSH into it:

vagrant up
vagrant ssh

Create a new site:

joomla site:create capistrano --sample-data=learn

Change directory to the root of your site

cd /var/www/capistrano

2. Use Bundler to install Capistrano

Let's start by creating a Gemfile:

source 'https://rubygems.org'
gem 'highline'
gem 'capistrano', '~> 3.3.0', require: false, group: :development

Run the following command to install Capistrano:

bundle install

3. Create a new Git repository

Initiate a new Git repository:

git init

and add all your site files:

git add .

Make an inital commit:

git commit -m "initial commit"

Now create a new repository under your github account so we can push this site to it. Refer to the GitHub documentation if you don't know how to create a new repository.

Grab your repository's SSH URL and add it as a remote:

git remote add origin git@github.com:joomlatools/capistrano.git

then push your files to GitHub:

git push origin master

4. Bootstrapping your project

The very first thing you will need to do is bootstrap your existing project and put the required Capistrano configuration files in place:

bundle exec cap install

This creates all the necessary configuration files and directory structure for a Capistrano-enabled project with two servers, staging and production:

├── Capfile
├── config
│   ├── deploy
│   │   ├── production.rb
│   │   └── staging.rb
│   └── deploy.rb
└── lib
    └── capistrano
            └── tasks

Here's what these files do and how you should configure them:

Capfile

The Capfile represents your main configuration file:

# Load DSL and set up stages
require 'capistrano/setup'
# Include default deployment tasks
require 'capistrano/deploy'
# Load custom tasks from `lib/capistrano/tasks' if you have any defined
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

This file should be good to go by default.

config/deploy.rb

This file is the main location for your deployment configuration. Open it and make sure to configure the following directives:

# Set your application name 
set :application, 'capistrano'
# Tell Capistrano where to find your Git repository
set :repo_url, 'git@github.com:joomlatools/capistrano.git'
# Set the deploy_to directory. This is the path where Capistrano should deploy to on your target servers.
set :deploy_to, '/var/www/capistrano/'

config/deploy/

This folder contains environment-specific confiugration. By default there is a a seperate configuration file for your staging and production environment.

Our production.rb looks like this:

set :stage, :production
set :branch, "production"
server '1.2.3.4', port: 22, user: 'deploy', roles: %w{web app}

For instance, in production.rb you might want to set the appropriate repository branch, whilst the server directive would naturally have a unique IP address and possibly a different user account, from which the deployment should take place.

lib/capistrano/tasks/

You can write custom tasks in this directory. These are a little outside of the scope of this post, but we will return to this in a later tutorial.

5. Shared directories

In order for your Joomla site to work correctly, certain files and directories need to writable (cache, tmp and logs), whilst others may contain user uploaded content (such as images or joomlatools-files). Other files are environment-specific, like configuration.php.

Because these directories should also remain the same between releases, Capistrano has the concept of shared folders and files.

We can use the :linked_dirs and :linked_files configuration options for this. A typical Joomla configuration for config/deploy.rb would therefore be:

set :linked_dirs, %w{cache tmp logs images joomlatools-files}
set :linked_files, %w{configuration.php}

Any file or directory that is committed to the repository will be copied on the remote server into a release directory under /var/www/capistrano/releases/.

Shared directories and files inside /var/www/capistrano/shared/ only exist on the remote server and will be symlinked into the release directory during deployment.

So therefore on your remote server be sure to create the following directory structures and files and grant appropriate permissions:

/var/www/capistrano/
   |-- shared/
      |-- cache/
      |-- images/
      |-- joomlatools-files/
      |-- logs/
      |-- tmp/
      |-- configuration.php

6. Capistrano Composer plugin

By default, your Joomla site includes all dependencies. If you have added your own dependencies to composer.json you need to make sure these are installed during deployment.

The Capistrano Composer plugin makes adding project dependencies to your site a snap.

First, add the plugin to your Gemfile:

gem 'capistrano-composer'

then run bundle install again.

Now load the plugin in your Capfile so Capistrano can load it:

require 'capistrano/composer'

7. Running a deploy

Now let's deploy your changes to your server:

bundle cap staging deploy

Note the staging argument means that the configurations for staging are loaded. Use production for the production environment.{.callout-blue}

8. Final server configuration

When Capistrano is finished, you'll see the following directories and files on your server:

/var/www/capistrano/
  |-- current -> /var/www/capistrano/releases/20190618090342
  |-- releases
  |-- repo
  |-- revisions.log
  |-- shared

Capistrano first copies your files into the releases directory. Then it will symlink any shared directory or file into it and run any other task to complete, such as installing Composer dependencies.

Once completed, Capistrano will update the /var/www/capistrano/current symbolic link to point to this release. You'll need to update your virtual host configuration, ensuring that its document root points to this current symlink.

The latest version of your site has now been succesfully deployed!

Extra goodies

We have created a Capistrano plugin for our Joomlatools Console which creates a wrapper call to Capistrano. So bootstrapping and deploying your site is as easy as:

  • Bootstrap your site with: joomla capistrano:deploy sitename
  • Deploy to pre configured server: joomla capistrano:deploy sitename -e staging

Send us your feedback

This Capistrano set up is our preferred deployment workflow. If you have any more ideas or want to share your workflow with us, we'd love to hear from you!

Get in touch through our developer channels on Twitter or Facebook.

Happy Joomla coding!