diff --git a/.travis.yml b/.travis.yml
index edd7824cb156248a35592e2af6d98450919b6e0b..fd6489ada6ba3019039e417248410eee5275c5c6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,13 @@
+sudo: false
 language: node_js
 git:
   depth: 10
 node_js:
   - "0.12"
 before_install:
-  - travis_retry sudo pip install -r test-infra/requirements.txt
+  - export PATH=$HOME/.local/bin:$PATH
+  - travis_retry pip install -r test-infra/requirements.txt --user `whoami`
   - rvm install 2.0.0 && rvm use 2.0.0
-  - bundle install
   - export GEMDIR=$(rvm gemdir)
   - if [ "$TWBS_TEST" = validate-html ]; then echo "ruby=$(basename $GEMDIR) jekyll=$JEKYLL_VERSION rouge=$ROUGE_VERSION" > pseudo_Gemfile.lock; fi
   - "export TRAVIS_COMMIT_MSG=\"$(git log --format=%B --no-merges -n 1)\""
@@ -14,12 +15,18 @@ before_install:
   - echo "$TRAVIS_COMMIT_MSG" | grep '\[skip sauce\]'; export TWBS_DO_SAUCE=$?; true
   - if [ "$TRAVIS_REPO_SLUG" = twbs-savage/bootstrap ]; then export TWBS_DO_VALIDATOR=0; fi
 install:
+  - bundle install --deployment --jobs=3
   - npm install -g grunt-cli
-  - ./test-infra/s3_cache.py download npm-modules
-  - if [ "$TWBS_TEST" = validate-html ] && [ $TWBS_DO_VALIDATOR -ne 0 ]; then ./test-infra/s3_cache.py download rubygems; fi
+  - npm install
+  # - ./test-infra/s3_cache.py download npm-modules
+  # - if [ "$TWBS_TEST" = validate-html ] && [ $TWBS_DO_VALIDATOR -ne 0 ]; then ./test-infra/s3_cache.py download rubygems; fi
 after_script:
   - if [ "$TRAVIS_REPO_SLUG" != twbs-savage/bootstrap ] && [ "$TWBS_TEST" = core ]; then ./test-infra/s3_cache.py upload npm-modules; fi
   - if [ "$TRAVIS_REPO_SLUG" != twbs-savage/bootstrap ] && [ "$TWBS_TEST" = validate-html ] && [ $TWBS_DO_VALIDATOR -ne 0 ]; then ./test-infra/s3_cache.py upload rubygems; fi
+cache:
+  directories:
+    - node_modules
+    - vendor/bundle
 env:
   global:
     - JEKYLL_VERSION="2.5.3"