Installing SilverStripe with Composer and Deploying with Capistrano

This blog will walk you through installing SilverStripe on your local development machine using Composer, setting it up and deploying it to a staging server with Capistrano.

 Download SilverStripe

  1. Create a new repo and clone it on your local machine
    You may consider using BitBucket.
    BitBucket will also let you clone your repository directly into SourceTree.
    cd projectdirectory
    git init
    git remote add origin https://usernmae@bitbucket.org/usernmane/reponame.git
  2. Setup Composer *
    * Skip this step if you already have Composer setup, you can test this by running command 'composer'.
    curl -sS https://getcomposer.org/installer | php
  3. Use composer to download and install the latest version of SilverStripe
    Copy Composer command from http://www.silverstripe.org/software/download/.
    This will install SilverStripe in the silverstripe directory.

    cd projectdirectory
    composer create-project silverstripe/installer silverstripe 3.1.15
  4. Remove installation folder
    cd projectdirectory/silverstripe
    mv * ../
    cd ..
    rm -rf silverstripe
  5. Git ignore 'cms' and 'framework'
    ~/yoursite/silverstripe/.gitignore
    As we will be using Composer to manage dependencies, we can safely git ignore those directories.
    cms/
    framework/
    vendor/
  6. Create CMS database
    mysql -uroot -proot -e "create database newsitedb"

Setup Apache

  1. Create Virtual Host
    /etc/apache2/extra/httpd-vhosts.conf
    Note: You will need to restart Apache once the change has been made with 'sudo apachectl restart'.
    <VirtualHost *:80>
    	DocumentRoot "/Users/yourusername/Sites/yoursite"
    	ServerName yoursite.dev
    	<Directory /Users/yourusername/Sites/yoursite/>
    		Options FollowSymLinks MultiViews
    		AllowOverride All
    		Order allow,deny
    		allow from all
    		Require all granted
    	</Directory>
    </VirtualHost>
  2. Add a hosts entry for your new site
    /etc/hosts
    127.0.0.1    yoursite.dev

Install SilverStripe

  1. Load the CMS installation page
    yoursite.dev/install.php
  2. Enter DB connection settings
    Username, Password, Database Name.
    Note: These settings will be saved in ~/yoursite/silverstripe/mysite/_config.php
  3. Enter login details
    Username, Password.
  4. Install SilverStripe
  5. Remove installation files on completion
  6. Git commit your files to the repo

Install Additional Modules

As we're using Composer, installing additional modules is easy!
Follow the steps below.

  1. Install the module using Composer
    Note: This will update the Composer dependencies manifest () to include the new module
    composer require silverstripe/blog
  2. Git ignore the new module directory
    ~/yoursite.dev/silverstripe/.gitignore
    As we are using Composer, it is not necessary to commit module code into the repository.
    Other developers will simply need to run 'composer install' to install all dependencies specified in the composer.json.
    blog/
    tagfield/
  3. Commit changes into the repository
    Note: There should just be three modified files to commit: .gitignore, composer.json and composer.lock.
  4. Rebuild the SilverStripe database
    yoursite.dev/dev/build?flush=all

Setup Site Deployment

Now that you have your site setup and running locally, you should think about deployment!
We're going to be using Capistrano to deploy our site onto staging / prod servers.

  1. Install Capistrano Ruby Gem
    gem install capistrano
  2. Setup Capistrano within your project directory
    This will generate the required Capistrano files.
    cap install
  3. Setup your deployment script
    ~/yoursite.dev/config/deploy.rb
    set :application, 'projectname'
    set :application, 'appname'
    set :repo_url, 'git@bitbucket.org:yourusername/yoursite.git'
    set :deploy_to, '/var/www/yoursite_deploy'
    set :linked_files, %w{mysite/_config.php .htaccess}
    set :linked_dirs, %w{silverstripe-cache assets vendor}
    set :db_backup_dir, '/var/www/yoursite_deploy/db_backups'
    set :tmp_dir, '/var/www/yoursite_deploy/tmp'
    namespace :deploy do
    	before :updating, 'silverstripe:db:backup'
    	before :updating, 'silverstripe:db:purge'
    	after :updated, 'silverstripe:composer:update'
    	after :reverted, 'silverstripe:db:restore'
    	after :finishing, 'deploy:cleanup'
    	after :finishing_rollback, 'silverstripe:composer:update'
    	after :finished, 'silverstripe:build'
    end
    
  4. Setup your Staging deployment script
    ~/yoursite/config/deploy/staging.rb
    set :stage, :staging
    set :root_dir, '/var/www/yoursite_deploy/current'
    set :website_url, 'http://yoursite/yoursite'
    set :db_host, 'localhost'
    set :db_name, 'dbname'
    set :db_user, 'dbuser'
    set :db_password, 'dbpassword'
    role :web, %w{root@youripaddress}
    server 'youripaddress', user: 'root', roles: %w{web}
    
  5. Setup SilverStripe deployment task
    ~/yoursite/lib/capistrano/tasks/silverstripe.rake
    namespace :silverstripe do
    namespace :composer do
    desc 'Run Composer update'
    task :update do
    on roles(:web) do
    within release_path do
    execute :php, "-d allow_url_fopen=on composer.phar update"
    end
    end
    end
    end
    desc 'Run SilverStripe dev/build'
    task :build do
    on roles(:web) do
    within fetch(:root_dir) do
    execute :php, "framework/cli-script.php dev/build"
    # execute :rm, "-R ./silverstripe-cache/*"
    # Need to figure out issues with flushing the cache before enabling curl
    # execute :curl, fetch(:website_url)
    end
    end
    end
    namespace :db do
    desc 'Backup the database'
    task :backup do
    on roles(:db) do
    within fetch(:db_backup_dir) do
    releases = capture(:ls, '-xr', releases_path).split
    if releases.length > 0
    last_release = releases.first
    execute :mysqldump, "-u#{fetch(:db_user)} --password='#{fetch(:db_password)}' --host='#{fetch(:db_host)}' #{fetch(:db_name)} > ./#{last_release}.sql"
    end
    end
    end
    end
    desc 'Purge old backups'
    task :purge do
    on roles(:db) do
    within fetch(:db_backup_dir) do
    backup_files = capture("ls -t #{fetch(:db_backup_dir)}/*").split.reverse
    if backup_files.length > fetch(:keep_releases)
    delete_backups = (backup_files - backup_files.last(fetch(:keep_releases))).join(" ")
    execute :rm, "-rf #{delete_backups}"
    end
    end
    end
    end
    desc 'Restore database'
    task :restore do
    on roles(:db) do
    within fetch(:db_backup_dir) do
    releases = capture(:ls, '-xr', releases_path).split
    if releases.length > 1
    latest_release = releases[0]
    rollback_release = releases[1]
    execute :mysqldump, "-u#{fetch(:db_user)} --password='#{fetch(:db_password)}' --host='#{fetch(:db_host)}' #{fetch(:db_name)} > ../rolled-back-release-#{latest_release}.sql && mysql -u#{fetch(:db_user)} --password='#{fetch(:db_password)}' --host='#{fetch(:db_host)}' #{fetch(:db_name)} < ./#{rollback_release}.sql"
    end
    end
    end
    end
    end
    end
  6. Add your local public key to your repo host deployment keys
    In BitBucket you may add deployment keys in:
    https://bitbucket.org/yourusername/sitename.com/admin/deploy-keys/
    cat ~/.ssh/id_rsa.pub | pbcopy
  7. Repeat the above step and the Staging server public key
    Again remember to copy the public key and add it to the deployment keys in BitBucket.
    ssh-keygen -t rsa
    cat ~/.ssh/id_rsa.pub | ssh root@stagingserveraddress 'cat >> ~/.ssh/authorized_keys'
  8. Create empty database on your staging server
    mysql -uroot -proot -e "create database newsitedb"
  9. Create website config in your shared files
    /var/www/yourwebsite.com_deploy/shared/mysite/_config.php
    Note: This will be used by Capistrano deploy script.
    <?php
    global $project;
    $project = 'mysite';
    global $databaseConfig;
    $databaseConfig = array(
    "type" => 'MySQLDatabase',
    "server" => 'localhost',
    "username" => 'dbuser',
    "password" => 'dbpass',
    "database" => 'dbname',
    "path" => '',
    );
    i18n::set_locale('en_US');
  10. Create site config
    /var/www/yourwebsite.com_deploy/shared/mysite/config/config.yml
    ---
    Name: mysite
    After:
    - 'framework/*'
    - 'cms/*'
    ---
    SSViewer:
    theme: 'simple'
  11. Create .htaccess file and add to shared directory
    /var/www/yourwebsite.com_deploy/shared/.htaccess
    ### SILVERSTRIPE START ###
    # Deny access to templates (but allow from localhost)
    <Files *.ss>
    	Order deny,allow
    	Deny from all
    	Allow from 127.0.0.1
    </Files>
    
    # Deny access to IIS configuration
    <Files web.config>
    	Order deny,allow
    	Deny from all
    </Files>
    
    # Deny access to YAML configuration files which might include sensitive information
    <Files *.yml>
    	Order allow,deny
    	Deny from all
    </Files>
    
    # Route errors to static pages automatically generated by SilverStripe
    ErrorDocument 404 /assets/error-404.html
    ErrorDocument 500 /assets/error-500.html
    
    <IfModule mod_rewrite.c>
    	SetEnv HTTP_MOD_REWRITE On
    	RewriteEngine On
    	RewriteBase '/'
    
    	# Deny access to potentially sensitive files and folders
    	RewriteRule ^vendor(/|$) - [F,L,NC]
    	RewriteRule silverstripe-cache(/|$) - [F,L,NC]
    	RewriteRule composer\.(json|lock) - [F,L,NC]
    
    	# Process through SilverStripe if no file with the requested name exists.
    	# Pass through the original path as a query parameter, and retain the existing parameters.
    	RewriteCond %{REQUEST_URI} ^(.*)$
    	RewriteCond %{REQUEST_FILENAME} !-f
    	RewriteRule .* framework/main.php?url=%1 [QSA]
    </IfModule>
    ### SILVERSTRIPE END ###
  12. Run the deploy script again from your development machine
    cap staging deploy
  13. Git commit changes
    Note: You may need to amend your deployment script to include tasks such as bower install if you're using Bower to manage front end dependencies.