{"id":3485,"date":"2017-04-25T16:00:22","date_gmt":"2017-04-25T14:00:22","guid":{"rendered":"https:\/\/florianbrinkmann.com\/en\/?p=3485"},"modified":"2020-02-09T10:59:52","modified_gmt":"2020-02-09T09:59:52","slug":"deployment-travis-ci","status":"publish","type":"post","link":"https:\/\/florianbrinkmann.com\/en\/deployment-travis-ci-3485\/","title":{"rendered":"Auto deployment to staging and production server with Travis CI"},"content":{"rendered":"\n<p>Two weeks ago I wrote a post about <a href=\"https:\/\/florianbrinkmann.com\/en\/3473\/deployment-gitlab-ci\/\">deployment via GitLab<\/a>. Now I realized the same behavior for a public GitHub repository with Travis, and this post shows you how I did it.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>The goal was, like already said, the same like in the GitLab post \u2014 I wanted to move a theme to the staging or production server, depending on if the push goes to <code class=\"lang-markup\">staging<\/code> or <code class=\"lang-markup\">master<\/code> branch. <a href=\"https:\/\/travis-ci.org\/\">Travis CI<\/a> is free for public GitHub repos.<\/p>\n\n\n\n<p>Travis works with a <code class=\"lang-markup\">.travis.yml<\/code> file, which stores the CI steps. The finished file looks like that:<\/p>\n\n\n<pre class=\"wp-block-code lang-yaml\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">language: php\n\naddons:\n  ssh_known_hosts:\n  - $STAGING_SERVER\n  - $PRODUCTION_SERVER\n\nbefore_script:\n  - <span class=\"hljs-keyword\">echo<\/span> -e <span class=\"hljs-string\">\"Host $STAGING_SERVERntStrictHostKeyChecking non\"<\/span> &gt;&gt; ~\/.ssh\/config\n  - <span class=\"hljs-keyword\">echo<\/span> -e <span class=\"hljs-string\">\"Host $PRODUCTION_SERVERntStrictHostKeyChecking non\"<\/span> &gt;&gt; ~\/.ssh\/config\n\nscript:\n  -\nbefore_deploy:\n  - openssl aes<span class=\"hljs-number\">-256<\/span>-cbc -K $ENCRYPTED_KEY -iv $ENCRYPTED_IV -in deploy_rsa.enc -out \/tmp\/deploy_rsa -d\n  - <span class=\"hljs-keyword\">eval<\/span> <span class=\"hljs-string\">\"$(ssh-agent -s)\"<\/span>\n  - chmod <span class=\"hljs-number\">600<\/span> \/tmp\/deploy_rsa\n  - ssh-add \/tmp\/deploy_rsa\n\ndeploy:\n  - provider: script\n    skip_cleanup: <span class=\"hljs-keyword\">true<\/span>\n    script: ssh -p22 $STAGING_SERVER_USER@$STAGING_SERVER <span class=\"hljs-string\">\"mkdir -p $STAGING_PATH_STABLE\"<\/span> &amp;&amp; ssh -p22 $STAGING_SERVER_USER@$STAGING_SERVER <span class=\"hljs-string\">\"mkdir -p $STAGING_PATH_TRUNK\"<\/span> &amp;&amp; rsync -rav -e ssh --exclude=<span class=\"hljs-string\">'.git\/'<\/span> --exclude=scripts\/ --exclude=<span class=\"hljs-string\">'.travis.yml'<\/span> --delete-excluded .\/ $STAGING_SERVER_USER@$STAGING_SERVER:$STAGING_PATH_TRUNK &amp;&amp; rsync -rav -e ssh --exclude=<span class=\"hljs-string\">'.git\/'<\/span> --exclude=scripts\/ --exclude=<span class=\"hljs-string\">'.travis.yml'<\/span> --delete-excluded .\/ $STAGING_SERVER_USER@$STAGING_SERVER:$STAGING_PATH_STABLE\n    on:\n      branch: staging\n  - provider: script\n    skip_cleanup: <span class=\"hljs-keyword\">true<\/span>\n    script: ssh -p22 $PRODUCTION_SERVER_USER@$PRODUCTION_SERVER <span class=\"hljs-string\">\"mkdir -p $PRODUCTION_SERVER_THEMES_PATH\/_tmp-bornholm\"<\/span>&amp;&amp; ssh -p22 $PRODUCTION_SERVER_USER@$PRODUCTION_SERVER <span class=\"hljs-string\">\"mkdir -p $PRODUCTION_SERVER_THEMES_PATH\/bornholm\"<\/span> &amp;&amp; rsync -rav -e ssh --exclude=<span class=\"hljs-string\">'.git\/'<\/span> --exclude=scripts\/ --exclude=<span class=\"hljs-string\">'.travis.yml'<\/span> --delete-excluded .\/ $PRODUCTION_SERVER_USER@$PRODUCTION_SERVER:$PRODUCTION_SERVER_THEMES_PATH\/_tmp-bornholm &amp;&amp; ssh -p22 $PRODUCTION_SERVER_USER@$PRODUCTION_SERVER <span class=\"hljs-string\">\"mv $PRODUCTION_SERVER_THEMES_PATH\/bornholm $PRODUCTION_SERVER_THEMES_PATH\/_old-bornholm &amp;&amp; mv $PRODUCTION_SERVER_THEMES_PATH\/_tmp-bornholm $PRODUCTION_SERVER_THEMES_PATH\/bornholm\"<\/span> &amp;&amp; ssh -p22 $PRODUCTION_SERVER_USER@$PRODUCTION_SERVER <span class=\"hljs-string\">\"rm -rf $PRODUCTION_SERVER_THEMES_PATH\/_old-bornholm\"<\/span>\n    on:\n      branch: master<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>At first, we set <code class=\"lang-markup\">php<\/code> as the language of our project and add the server addresses to the <code class=\"lang-markup\">known_hosts<\/code>, like described in the docu post \u00bb<a href=\"https:\/\/docs.travis-ci.com\/user\/ssh-known-hosts\/\">Adding to SSH Known Hosts<\/a>\u00ab \u2014 the variables can be set under Settings in the repo in Travis.<\/p>\n\n\n\n<p><strong>Be careful not to write sensitive data directly into the file, but use the Travis variables as the file is publicly in the GitHub repo!<\/strong><\/p>\n\n\n\n<p>After that we prevent that we need to <a href=\"http:\/\/stackoverflow.com\/a\/16638729\/7774451\">confirm the fingerprint of the unknown server<\/a> in the <code class=\"lang-markup\">before_script<\/code> part. If no <code class=\"lang-markup\">script<\/code> is defined, Travis runs a default procedur depending on the choosen language (for example PHPunit for PHP) \u2013 we only want a deployment, so we set an empty script.<\/p>\n\n\n\n<p>How to get ready for the SSH connection is described in the post \u00bb<a href=\"https:\/\/oncletom.io\/2016\/travis-ssh-deploy\/\">SSH deploys with Travis CI<\/a>\u00ab on oncletom.io (the encryption does not work without problems on Windows, you can use the Windows Subsystem for Linux on Windows 10. The command I needed to get it working are listed at the end of the post) \u2014 the result is our <code class=\"lang-markup\">before_deploy<\/code>.<\/p>\n\n\n\n<p>The <code class=\"lang-markup\">deploy<\/code> part has two sub areas \u2014 one for <code class=\"lang-markup\">staging<\/code> and one for <code class=\"lang-markup\">master<\/code>. The <code class=\"lang-markup\">script:<\/code> commands are mostly the same as in the <a href=\"https:\/\/florianbrinkmann.com\/en\/3473\/deployment-gitlab-ci\/\">GitLab deployment post<\/a>.<\/p>\n\n\n\n<p><strong>Steps for encrypting the SSH key on Windows with the Subsystem for Linux<\/strong> (run in the git repository directory):<\/p>\n\n\n<pre class=\"wp-block-code lang-bash\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">apt-<span class=\"hljs-keyword\">get<\/span> install ruby-dev\ngem install travis -v 1.8.8 --no-rdoc --no-ri\nsudo travis login\nssh-keygen -t rsa -b 4096 -C 'build@travis-ci.org' -f .\/deploy_rsa\nsudo travis encrypt-file deploy_rsa --add<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>After that you add the public key to your server and remove the key files (do not leave them in the repository and accidently push them to GitHub!):<\/p>\n\n\n<pre class=\"wp-block-code lang-bash\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">rm<\/span> <span class=\"hljs-selector-tag\">-f<\/span> <span class=\"hljs-selector-tag\">deploy_rsa<\/span> <span class=\"hljs-selector-tag\">deploy_rsa<\/span><span class=\"hljs-selector-class\">.pub<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>","protected":false},"excerpt":{"rendered":"<p>Two weeks ago I wrote a post about deployment via GitLab. Now I realized the same behavior for a public GitHub repository with Travis, and this post shows you how I did it.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"wpf_show_in_dewp_planet_feed":false,"flobn_post_versions":"","webmentions_disabled_pings":false,"webmentions_disabled":false,"lazy_load_responsive_images_disabled":false,"footnotes":""},"categories":[6],"tags":[],"class_list":["post-3485","post","type-post","status-publish","format-standard","hentry","category-web-development"],"wp-worthy-pixel":{"ignored":false,"public":"ceef17546a2544b09f78ace29a29336c","server":"vg07.met.vgwort.de","url":"https:\/\/vg07.met.vgwort.de\/na\/ceef17546a2544b09f78ace29a29336c"},"wp-worthy-type":"normal","_links":{"self":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/3485","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/comments?post=3485"}],"version-history":[{"count":3,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/3485\/revisions"}],"predecessor-version":[{"id":5895,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/3485\/revisions\/5895"}],"wp:attachment":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/media?parent=3485"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/categories?post=3485"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/tags?post=3485"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}