Web Development & Deployment

Deploying Craft CMS to a VPS Server with Capistrano

Chris Dyer

A beginners guide to going from a development Craft CMS site, to a professional deployment on a virtual server such as a DigitalOcean droplet.

I personally like Capistrano and although using a Ruby gem with a PHP site doesn't feel completely natural, Capistrano works perfectly for a non-automated deployment workflow. Whenever you need to upload a new version just run cap production deploy.

I will assume you have Ruby installed and a working Craft CMS site on your local machine. The server should have PHP and a database MySQL / PostgreSQL installed.

Configuring the Craft Site

I created the capistrano-craft Rubygem which integrates with Capistrano and adds useful features for synchronizing the development and production assets and database.

Install capistrano by running gem install capistrano, gem install capistrano-craft and cap install within your project directory. This will produce various configuration files:

$ cap install
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
create Capfile

In the newly generated Capfile add require "capistrano/craft" towards the end. It should look like the following:

# Include tasks from other gems included in your Gemfile
require "capistrano/craft"

# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }

Change config/deploy/production.rb to point at the remote server by adding a line such as the following:

server "<server ip address>", user: "deployer", roles: %w{app db web}

Finally in config/deploy.rb change the default commented settings to match your project. This is probably :application, :repo_url and :deploy_to. We may also need to configure a couple of other settings:

append :linked_files, ".env"
append :linked_dirs, "web/uploads", "node_modules"

This tells Craft to look for our production settings in a .env file that will be symlinked into each deployment. My site assets are stored in web/uploads so I want this to be consistent and linked for each deployment. The same with node_modules which doesn't need a complete reinstall each time.

Server Setup

Your server will fetch the latest codebase from your git repository (that we just configured in config/deploy.rb). To authorize this, your server needs an SSH key. We can quickly generate one by running ssh-keygen -t rsa as our deployer user. The contents of ~/.ssh/id_rsa.pub can be added as an access / deployment key on our Git repository host.

We need to create a folder to store our site on the server. I'm going to create a folder in /var/www (this is the same path we configured in config/deploy.rb). Your deployer user should be the owner and it should also be accessible to your web server. Eg.

$ sudo mkdir /var/www/mysite
$ sudo chown -R deployer:www-data /var/www/mysite

Initial (Failing) Deployment

If we go ahead and run cap production deploy our deploy will fail with ERROR linked file /var/www/mysite/shared/.env does not exist on <server ip>. However, Capistrano will have setup its preferred folder structure and we can create and configure the missing .env file with our database settings.

Upload Local Database to Production

After configuring a production .env file with our server database credentials we can use capistrano-craft to upload our development database. This will verify our production server database credentials and mean that Craft has a valid database schema to start using when we deploy the site in a moment. You can view a list of all Capistrano tasks by running cap -T

To "push" the local database to production we should run cap production db:push. This will create a backup of our local database in db.sql as a safety precaution.

You will always receive a prompt in this case “Are you sure you want to drop and recreate the remote database?…” because you need to be certain before overwriting the live database. A live database backup is also taken automatically and placed in the backups folder.

Working Deployment

We can now run cap production deploy again which will finish setting up the folder structure, install composer dependencies and compile production assets.

By default capistrano-craft will attempt to run yarn install and yarn run production to update dependencies and then compile assets using your pipeline. You can disable this behaviour by setting :craft_compile_assets to false in config/deploy.rb. You may well need to customize this if you would like to compile assets as part of the deployment process. For instance, to use npm and gulp, you could add the following to config/deploy.rb

set :craft_compile_assets_command, "npm install && gulp production --silent"

Congratulations! Your Craft CMS site should now be deployed to the server. Please report any issues with the capistrano-craft gem in the Github issues area.