DEV Community

Cover image for Deployment of static websites to Digital Ocean using TravisCI
Thibaut Tiberghien
Thibaut Tiberghien

Posted on

Deployment of static websites to Digital Ocean using TravisCI

Originally posted on Medium on May 8, 2016.

YMMV: The code below is given for the environment and use-case I had at the time of writing, adapt it for your requirements.

Stack

  • Code on GitHub, master branch deploys to prod, and staging branch deploys to a subdomain for preview and QA.
  • Web hosting on a Digital Ocean droplet, running Ubuntu 16.04. Using Nginx web server, serving www.planecq.com from /var/www/planecq.com/html.
  • TravisCI for the automatic deployment when git pushing to specific branches. It pushes to a bare git repo at /var/www/planecq.com/.git. From there, a post-receive hook checks out the latest code to the html folder.
  • Gulp used for the build and test workflow

1. Create an encrypted private key for travis (on your dev machine)

Install Travis CLI if needed:

gem install travis
travis login

Create the encrypted key and public key in your local repo:

cd ~/Sites/planecq.com
touch .travis.yml
ssh-keygen -t rsa -N "" -C "travis@planecq.com" -f travis_rsa
travis encrypt-file travis_rsa --add
rm travis_rsa
cat travis_rsa.pub # << copy this for later

2. Setup Travis on the droplet

Create a passwordless travis user on the droplet, setup the generated access key, and give it access to the folder where the website is hosted:

sudo adduser --disabled-password --gecos "" travis
sudo chown -R travis:travis /var/www/planecq.com
sudo su travis
mkdir ~/.ssh
chmod 700 .ssh
emacs .ssh/authorized_keys
"copy content of previous cat, save, exit"
chmod 600 .ssh/authorized_keys
exit

3. Prepare remote repository on the droplet

sudo su travis
cd /var/www/planecq.com
mkdir .git
cd .git
git init --bare
cd hooks
emacs post-receive
"copy the content of the hook posted below, save, exit"
chmod +x post-receive
exit

post-receive hook:

#!/bin/sh
git --work-tree=/var/www/planecq.com/html/ --git-dir=/var/www/planecq.com/.git checkout -f

4. Travis config

.travis.yml

language: node_js
node_js:
  - 4.3.1
env:
  global:
  - NOKOGIRI_USE_SYSTEM_LIBRARIES=true # speeds up installation of html-proofer
addons:
  ssh_known_hosts: webhost.planecq.xyz
branches:
  only:
  - master
  - staging
before_install:
  - rvm install 2.2.2
  - openssl aes-256-cbc -K $encrypted_b0b2958c016f_key -iv $encrypted_b0b2958c016f_iv -in .travis/travis_rsa.enc -out ~/.ssh/travis_rsa -d
  - chmod 600 ~/.ssh/travis_rsa
install:
  - gem install html-proofer
  - npm install -g gulp
  - npm install
script:
  - gulp build && gulp test
deploy:
  skip_cleanup: true
  provider: script
  script: .travis/deploy.sh
  on:
    all_branches: true
notifications:
  email: false
  slack:
    secure: rWg9[...]x69

gulp build

This is where the website is compressed for production. I have written a separate post covering that.

gulp test (extract of gulpfile.js)

var exec = require('child_process').exec;
var gulp = require('gulp');
var runSequence = require('run-sequence');
var bootlint  = require('gulp-bootlint');

// Validate html, links, etc.
gulp.task('html-proofer', function(done) {
  execute('htmlproofer ./index.min.html --check-html --check-favicon --check-external-hash', {}, done);
});

// Validate bootstrap
gulp.task('bootlint', function() {
  return gulp.src('./index.html.min')
    .pipe(bootlint({
      stoponerror: true
    }));
});

// Full test task
gulp.task('test', function(cb) {
  runSequence('html-proofer', 'bootlint', cb);
});

// Util to execute external command
function execute(cmd, opts, done) {
  console.log(cmd);
  exec(cmd, opts, function(error, stdout, stderr) {
    console.log(stdout);
    console.error(stderr);
    done(error);
  });
}

.travis/deploy.sh

#!/bin/bash

# print outputs and exit on first failure
set -xe

if [ $TRAVIS_BRANCH == "master" ] ; then

    # setup ssh agent, git config and remote
    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/travis_rsa
    git remote add deploy "travis@webhost.planecq.xyz:/var/www/planecq.com"
    git config user.name "Travis CI"
    git config user.email "travis@planecq.com"

    # commit compressed files and push it to remote
    rm -f .gitignore
    cp .travis/deployignore .gitignore
    git add .
    git status # debug
    git commit -m "Deploy compressed files"
    git push -f deploy HEAD:master

elif [ $TRAVIS_BRANCH == "staging" ] ; then

    # setup ssh agent, git config and remote
    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/travis_rsa
    git remote add deploy "travis@webhost.planecq.xyz:/var/www/planecq.xyz"
    git config user.name "Travis CI"
    git config user.email "travis@planecq.com"

    # commit compressed files and push it to remote
    rm -f .gitignore
    cp .travis/deployignore .gitignore
    git add .
    git status # debug
    git commit -m "Deploy compressed files"
    git push -f deploy HEAD:master

else

    echo "No deploy script for branch '$TRAVIS_BRANCH'"

fi

.travis/deployignore

This file replaces .gitignore for deploy only and lets the following files to be committed and deployed (files generated by gulp build and normally ignored in the repository):

gulp/
index.min.html
*.gz

Top comments (0)