mirror of
				https://github.com/capistrano/capistrano
				synced 2023-03-27 23:21:18 -04:00 
			
		
		
		
	More Docs!
This commit is contained in:
		
							parent
							
								
									0e1bf5d13a
								
							
						
					
					
						commit
						94b8564296
					
				
					 18 changed files with 1835 additions and 120 deletions
				
			
		
							
								
								
									
										30
									
								
								_includes/metrics.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								_includes/metrics.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | <script type="text/javascript"> | ||||||
|  |   var _gauges = _gauges || []; | ||||||
|  |   (function() { | ||||||
|  |     var t   = document.createElement('script'); | ||||||
|  |     t.type  = 'text/javascript'; | ||||||
|  |     t.async = true; | ||||||
|  |     t.id    = 'gauges-tracker'; | ||||||
|  |     t.setAttribute('data-site-id', '51c83c32613f5d7df70000bc'); | ||||||
|  |     t.src = '//secure.gaug.es/track.js'; | ||||||
|  |     var s = document.getElementsByTagName('script')[0]; | ||||||
|  |     s.parentNode.insertBefore(t, s); | ||||||
|  |   })(); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <script type="text/javascript"> | ||||||
|  |   setTimeout(function(){var a=document.createElement("script"); | ||||||
|  |   var b=document.getElementsByTagName("script")[0]; | ||||||
|  |   a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0017/6418.js?"+Math.floor(new Date().getTime()/3600000); | ||||||
|  |   a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <script> | ||||||
|  |   (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||||||
|  |   (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||||||
|  |   m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||||||
|  |   })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | ||||||
|  | 
 | ||||||
|  |   ga('create', 'UA-41970098-1', 'capistranorb.com'); | ||||||
|  |   ga('send', 'pageview'); | ||||||
|  | </script> | ||||||
|  | @ -8,7 +8,7 @@ | ||||||
|   <h5>Getting Started</h5> |   <h5>Getting Started</h5> | ||||||
|   <li><a href="/documentation/getting-started/installation/">Installation</a></li> |   <li><a href="/documentation/getting-started/installation/">Installation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/preparing-your-application/">Preparing Your Application</a></li> |   <li><a href="/documentation/getting-started/preparing-your-application/">Preparing Your Application</a></li> | ||||||
|   <li><aj href="/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a></li> |   <li><a href="/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/cold-start/">Cold Start</a></li> |   <li><a href="/documentation/getting-started/cold-start/">Cold Start</a></li> | ||||||
|   <li><a href="/documentation/getting-started/rollbacks/">Rollbacks</a></li> |   <li><a href="/documentation/getting-started/rollbacks/">Rollbacks</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|  |  | ||||||
|  | @ -16,6 +16,36 @@ | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
| 
 | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       var _gauges = _gauges || []; | ||||||
|  |       (function() { | ||||||
|  |         var t   = document.createElement('script'); | ||||||
|  |         t.type  = 'text/javascript'; | ||||||
|  |         t.async = true; | ||||||
|  |         t.id    = 'gauges-tracker'; | ||||||
|  |         t.setAttribute('data-site-id', '51c83c32613f5d7df70000bc'); | ||||||
|  |         t.src = '//secure.gaug.es/track.js'; | ||||||
|  |         var s = document.getElementsByTagName('script')[0]; | ||||||
|  |         s.parentNode.insertBefore(t, s); | ||||||
|  |       })(); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       setTimeout(function(){var a=document.createElement("script"); | ||||||
|  |       var b=document.getElementsByTagName("script")[0]; | ||||||
|  |       a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0017/6418.js?"+Math.floor(new Date().getTime()/3600000); | ||||||
|  |       a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script> | ||||||
|  |       (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||||||
|  |       (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||||||
|  |       m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||||||
|  |       })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | ||||||
|  | 
 | ||||||
|  |       ga('create', 'UA-41970098-1', 'capistranorb.com'); | ||||||
|  |       ga('send', 'pageview'); | ||||||
|  |     </script> | ||||||
|     {% include header.html %} |     {% include header.html %} | ||||||
| 
 | 
 | ||||||
|     <div class="row"> |     <div class="row"> | ||||||
|  |  | ||||||
|  | @ -16,6 +16,36 @@ | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
| 
 | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       var _gauges = _gauges || []; | ||||||
|  |       (function() { | ||||||
|  |         var t   = document.createElement('script'); | ||||||
|  |         t.type  = 'text/javascript'; | ||||||
|  |         t.async = true; | ||||||
|  |         t.id    = 'gauges-tracker'; | ||||||
|  |         t.setAttribute('data-site-id', '51c83c32613f5d7df70000bc'); | ||||||
|  |         t.src = '//secure.gaug.es/track.js'; | ||||||
|  |         var s = document.getElementsByTagName('script')[0]; | ||||||
|  |         s.parentNode.insertBefore(t, s); | ||||||
|  |       })(); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       setTimeout(function(){var a=document.createElement("script"); | ||||||
|  |       var b=document.getElementsByTagName("script")[0]; | ||||||
|  |       a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0017/6418.js?"+Math.floor(new Date().getTime()/3600000); | ||||||
|  |       a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script> | ||||||
|  |       (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||||||
|  |       (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||||||
|  |       m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||||||
|  |       })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | ||||||
|  | 
 | ||||||
|  |       ga('create', 'UA-41970098-1', 'capistranorb.com'); | ||||||
|  |       ga('send', 'pageview'); | ||||||
|  |     </script> | ||||||
|     <div class="top-bar"> |     <div class="top-bar"> | ||||||
|   <a href="/" class="brand"> |   <a href="/" class="brand"> | ||||||
|     <img src="/images/CapistranoLogo.png" /> |     <img src="/images/CapistranoLogo.png" /> | ||||||
|  | @ -33,28 +63,28 @@ | ||||||
|   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> |   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Getting Started</h5> |   <h5>Getting Started</h5> | ||||||
|   <li><a href="/documentation/getting-started/installation/index.html">Installation</a></li> |   <li><a href="/documentation/getting-started/installation/">Installation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/preparing-your-application/index.html">Preparing Your Application</a></li> |   <li><a href="/documentation/getting-started/preparing-your-application/">Preparing Your Application</a></li> | ||||||
|   <li><aj href="/documentation/getting-started/authentication-and-authorisation/index.html">Authentication & Authorisation</a></li> |   <li><a href="/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/cold-start/index.html">Cold Start</a></li> |   <li><a href="/documentation/getting-started/cold-start/">Cold Start</a></li> | ||||||
|   <li><a href="/documentation/getting-started/rollbacks/index.html">Rollbacks</a></li> |   <li><a href="/documentation/getting-started/rollbacks/">Rollbacks</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Troubleshooting</h5> |   <h5>Troubleshooting</h5> | ||||||
|   <li><a href="/documentation/troubleshooting/authentication/index.html">SCM (Git) Authentication</a></li> |   <li><a href="/documentation/troubleshooting/authentication/">SCM (Git) Authentication</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/connectivity/index.html">Connectivity</a></li> |   <li><a href="/documentation/troubleshooting/connectivity/">Connectivity</a></li> | ||||||
|   <!--<li><a href="/documentation/troubleshooting/gateway-servers/index.html">Gateway Servers</a></li>--> |   <!--<li><a href="/documentation/troubleshooting/gateway-servers/">Gateway Servers</a></li>--> | ||||||
|   <li><a href="/documentation/troubleshooting/agent-forwarding/index.html">Agent Forwarding</a></li> |   <li><a href="/documentation/troubleshooting/agent-forwarding/">Agent Forwarding</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/sudo-password/index.html">`sudo` Password</a></li> |   <li><a href="/documentation/troubleshooting/sudo-password/">`sudo` Password</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/index.html">RVM, `rbenv` And `nvm`</a></li> |   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/">RVM, `rbenv` And `nvm`</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>FAQ</h5> |   <h5>FAQ</h5> | ||||||
|   <li><a |   <li><a | ||||||
|     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/index.html">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> |     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> | ||||||
|   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/index.html">Should I Use Capistrano To Provision My Servers?</a></li> |   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/">Should I Use Capistrano To Provision My Servers?</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Power Use-Cases</h5> |   <h5>Power Use-Cases</h5> | ||||||
|   <li><a href="/documentation/power-use-cases/integration-with-rake/index.html">Integration With Rake</a></li> |   <li><a href="/documentation/power-use-cases/integration-with-rake/">Integration With Rake</a></li> | ||||||
|   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/index.html">Driving Tools Such As <em>Chef Solo</em></a></li> |   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/">Driving Tools Such As <em>Chef Solo</em></a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Recent Announcements</h5> |   <h5>Recent Announcements</h5> | ||||||
|    |    | ||||||
|  |  | ||||||
|  | @ -16,6 +16,36 @@ | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
| 
 | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       var _gauges = _gauges || []; | ||||||
|  |       (function() { | ||||||
|  |         var t   = document.createElement('script'); | ||||||
|  |         t.type  = 'text/javascript'; | ||||||
|  |         t.async = true; | ||||||
|  |         t.id    = 'gauges-tracker'; | ||||||
|  |         t.setAttribute('data-site-id', '51c83c32613f5d7df70000bc'); | ||||||
|  |         t.src = '//secure.gaug.es/track.js'; | ||||||
|  |         var s = document.getElementsByTagName('script')[0]; | ||||||
|  |         s.parentNode.insertBefore(t, s); | ||||||
|  |       })(); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       setTimeout(function(){var a=document.createElement("script"); | ||||||
|  |       var b=document.getElementsByTagName("script")[0]; | ||||||
|  |       a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0017/6418.js?"+Math.floor(new Date().getTime()/3600000); | ||||||
|  |       a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script> | ||||||
|  |       (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||||||
|  |       (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||||||
|  |       m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||||||
|  |       })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | ||||||
|  | 
 | ||||||
|  |       ga('create', 'UA-41970098-1', 'capistranorb.com'); | ||||||
|  |       ga('send', 'pageview'); | ||||||
|  |     </script> | ||||||
|     <div class="top-bar"> |     <div class="top-bar"> | ||||||
|   <a href="/" class="brand"> |   <a href="/" class="brand"> | ||||||
|     <img src="/images/CapistranoLogo.png" /> |     <img src="/images/CapistranoLogo.png" /> | ||||||
|  | @ -33,28 +63,28 @@ | ||||||
|   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> |   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Getting Started</h5> |   <h5>Getting Started</h5> | ||||||
|   <li><a href="/documentation/getting-started/installation/index.html">Installation</a></li> |   <li><a href="/documentation/getting-started/installation/">Installation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/preparing-your-application/index.html">Preparing Your Application</a></li> |   <li><a href="/documentation/getting-started/preparing-your-application/">Preparing Your Application</a></li> | ||||||
|   <li><aj href="/documentation/getting-started/authentication-and-authorisation/index.html">Authentication & Authorisation</a></li> |   <li><a href="/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/cold-start/index.html">Cold Start</a></li> |   <li><a href="/documentation/getting-started/cold-start/">Cold Start</a></li> | ||||||
|   <li><a href="/documentation/getting-started/rollbacks/index.html">Rollbacks</a></li> |   <li><a href="/documentation/getting-started/rollbacks/">Rollbacks</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Troubleshooting</h5> |   <h5>Troubleshooting</h5> | ||||||
|   <li><a href="/documentation/troubleshooting/authentication/index.html">SCM (Git) Authentication</a></li> |   <li><a href="/documentation/troubleshooting/authentication/">SCM (Git) Authentication</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/connectivity/index.html">Connectivity</a></li> |   <li><a href="/documentation/troubleshooting/connectivity/">Connectivity</a></li> | ||||||
|   <!--<li><a href="/documentation/troubleshooting/gateway-servers/index.html">Gateway Servers</a></li>--> |   <!--<li><a href="/documentation/troubleshooting/gateway-servers/">Gateway Servers</a></li>--> | ||||||
|   <li><a href="/documentation/troubleshooting/agent-forwarding/index.html">Agent Forwarding</a></li> |   <li><a href="/documentation/troubleshooting/agent-forwarding/">Agent Forwarding</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/sudo-password/index.html">`sudo` Password</a></li> |   <li><a href="/documentation/troubleshooting/sudo-password/">`sudo` Password</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/index.html">RVM, `rbenv` And `nvm`</a></li> |   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/">RVM, `rbenv` And `nvm`</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>FAQ</h5> |   <h5>FAQ</h5> | ||||||
|   <li><a |   <li><a | ||||||
|     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/index.html">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> |     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> | ||||||
|   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/index.html">Should I Use Capistrano To Provision My Servers?</a></li> |   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/">Should I Use Capistrano To Provision My Servers?</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Power Use-Cases</h5> |   <h5>Power Use-Cases</h5> | ||||||
|   <li><a href="/documentation/power-use-cases/integration-with-rake/index.html">Integration With Rake</a></li> |   <li><a href="/documentation/power-use-cases/integration-with-rake/">Integration With Rake</a></li> | ||||||
|   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/index.html">Driving Tools Such As <em>Chef Solo</em></a></li> |   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/">Driving Tools Such As <em>Chef Solo</em></a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Recent Announcements</h5> |   <h5>Recent Announcements</h5> | ||||||
|    |    | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ body { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| h1, h2, h3, h4, h5, h6 { | h1, h2, h3, h4, h5, h6 { | ||||||
|  |   font-weight: 400; | ||||||
|   font-family: 'Enriqueta', serif; |   font-family: 'Enriqueta', serif; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,36 @@ | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
| 
 | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       var _gauges = _gauges || []; | ||||||
|  |       (function() { | ||||||
|  |         var t   = document.createElement('script'); | ||||||
|  |         t.type  = 'text/javascript'; | ||||||
|  |         t.async = true; | ||||||
|  |         t.id    = 'gauges-tracker'; | ||||||
|  |         t.setAttribute('data-site-id', '51c83c32613f5d7df70000bc'); | ||||||
|  |         t.src = '//secure.gaug.es/track.js'; | ||||||
|  |         var s = document.getElementsByTagName('script')[0]; | ||||||
|  |         s.parentNode.insertBefore(t, s); | ||||||
|  |       })(); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       setTimeout(function(){var a=document.createElement("script"); | ||||||
|  |       var b=document.getElementsByTagName("script")[0]; | ||||||
|  |       a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0017/6418.js?"+Math.floor(new Date().getTime()/3600000); | ||||||
|  |       a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script> | ||||||
|  |       (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||||||
|  |       (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||||||
|  |       m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||||||
|  |       })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | ||||||
|  | 
 | ||||||
|  |       ga('create', 'UA-41970098-1', 'capistranorb.com'); | ||||||
|  |       ga('send', 'pageview'); | ||||||
|  |     </script> | ||||||
|     <div class="top-bar"> |     <div class="top-bar"> | ||||||
|   <a href="/" class="brand"> |   <a href="/" class="brand"> | ||||||
|     <img src="/images/CapistranoLogo.png" /> |     <img src="/images/CapistranoLogo.png" /> | ||||||
|  | @ -33,28 +63,28 @@ | ||||||
|   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> |   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Getting Started</h5> |   <h5>Getting Started</h5> | ||||||
|   <li><a href="/documentation/getting-started/installation/index.html">Installation</a></li> |   <li><a href="/documentation/getting-started/installation/">Installation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/preparing-your-application/index.html">Preparing Your Application</a></li> |   <li><a href="/documentation/getting-started/preparing-your-application/">Preparing Your Application</a></li> | ||||||
|   <li><aj href="/documentation/getting-started/authentication-and-authorisation/index.html">Authentication & Authorisation</a></li> |   <li><a href="/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/cold-start/index.html">Cold Start</a></li> |   <li><a href="/documentation/getting-started/cold-start/">Cold Start</a></li> | ||||||
|   <li><a href="/documentation/getting-started/rollbacks/index.html">Rollbacks</a></li> |   <li><a href="/documentation/getting-started/rollbacks/">Rollbacks</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Troubleshooting</h5> |   <h5>Troubleshooting</h5> | ||||||
|   <li><a href="/documentation/troubleshooting/authentication/index.html">SCM (Git) Authentication</a></li> |   <li><a href="/documentation/troubleshooting/authentication/">SCM (Git) Authentication</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/connectivity/index.html">Connectivity</a></li> |   <li><a href="/documentation/troubleshooting/connectivity/">Connectivity</a></li> | ||||||
|   <!--<li><a href="/documentation/troubleshooting/gateway-servers/index.html">Gateway Servers</a></li>--> |   <!--<li><a href="/documentation/troubleshooting/gateway-servers/">Gateway Servers</a></li>--> | ||||||
|   <li><a href="/documentation/troubleshooting/agent-forwarding/index.html">Agent Forwarding</a></li> |   <li><a href="/documentation/troubleshooting/agent-forwarding/">Agent Forwarding</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/sudo-password/index.html">`sudo` Password</a></li> |   <li><a href="/documentation/troubleshooting/sudo-password/">`sudo` Password</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/index.html">RVM, `rbenv` And `nvm`</a></li> |   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/">RVM, `rbenv` And `nvm`</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>FAQ</h5> |   <h5>FAQ</h5> | ||||||
|   <li><a |   <li><a | ||||||
|     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/index.html">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> |     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> | ||||||
|   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/index.html">Should I Use Capistrano To Provision My Servers?</a></li> |   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/">Should I Use Capistrano To Provision My Servers?</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Power Use-Cases</h5> |   <h5>Power Use-Cases</h5> | ||||||
|   <li><a href="/documentation/power-use-cases/integration-with-rake/index.html">Integration With Rake</a></li> |   <li><a href="/documentation/power-use-cases/integration-with-rake/">Integration With Rake</a></li> | ||||||
|   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/index.html">Driving Tools Such As <em>Chef Solo</em></a></li> |   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/">Driving Tools Such As <em>Chef Solo</em></a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Recent Announcements</h5> |   <h5>Recent Announcements</h5> | ||||||
|    |    | ||||||
|  |  | ||||||
|  | @ -0,0 +1,774 @@ | ||||||
|  | <!DOCTYPE html> | ||||||
|  | <html> | ||||||
|  |   <head> | ||||||
|  |     <meta charset="utf-8"> | ||||||
|  |     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|  |     <title>Authentication & Authorisation</title> | ||||||
|  |     <link href='http://fonts.googleapis.com/css?family=Enriqueta' rel='stylesheet' type='text/css'> | ||||||
|  |     <script type="text/javascript" src="//use.typekit.net/itm5ubu.js"></script> | ||||||
|  |     <script type="text/javascript">try{Typekit.load();}catch(e){}</script> | ||||||
|  |     <link rel="stylesheet" href="/css/foundation.css" /> | ||||||
|  |     <link rel="stylesheet" href="/css/capistrano.css"> | ||||||
|  |     <link rel="stylesheet" href="/css/social_foundicons.css" /> | ||||||
|  |     <link rel="stylesheet" href="/css/okaidia.css"> | ||||||
|  |     <script src="/js/vendor/custom.modernizr.js"></script> | ||||||
|  |   </head> | ||||||
|  |   <body> | ||||||
|  | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       var _gauges = _gauges || []; | ||||||
|  |       (function() { | ||||||
|  |         var t   = document.createElement('script'); | ||||||
|  |         t.type  = 'text/javascript'; | ||||||
|  |         t.async = true; | ||||||
|  |         t.id    = 'gauges-tracker'; | ||||||
|  |         t.setAttribute('data-site-id', '51c83c32613f5d7df70000bc'); | ||||||
|  |         t.src = '//secure.gaug.es/track.js'; | ||||||
|  |         var s = document.getElementsByTagName('script')[0]; | ||||||
|  |         s.parentNode.insertBefore(t, s); | ||||||
|  |       })(); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       setTimeout(function(){var a=document.createElement("script"); | ||||||
|  |       var b=document.getElementsByTagName("script")[0]; | ||||||
|  |       a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0017/6418.js?"+Math.floor(new Date().getTime()/3600000); | ||||||
|  |       a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script> | ||||||
|  |       (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||||||
|  |       (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||||||
|  |       m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||||||
|  |       })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | ||||||
|  | 
 | ||||||
|  |       ga('create', 'UA-41970098-1', 'capistranorb.com'); | ||||||
|  |       ga('send', 'pageview'); | ||||||
|  |     </script> | ||||||
|  |     <div class="top-bar"> | ||||||
|  |   <a href="/" class="brand"> | ||||||
|  |     <img src="/images/CapistranoLogo.png" /> | ||||||
|  |   </a> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     <div class="row"> | ||||||
|  |       <div class="large-4 columns"> | ||||||
|  |         <ul class="side-nav"> | ||||||
|  |   <li><a href="http://www.harrow.io/" class="advertisment"><span class="label label-important">New</span> Hosted Capistrano for Teams</a></li> | ||||||
|  |   <li class="divider"></li> | ||||||
|  |   <h5>Overview</h5> | ||||||
|  |   <li><a href="/documentation/overview/what-is-capistrano/">What is Capistrano?</a></li> | ||||||
|  |   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> | ||||||
|  |   <li class="divider"></li> | ||||||
|  |   <h5>Getting Started</h5> | ||||||
|  |   <li><a href="/documentation/getting-started/installation/">Installation</a></li> | ||||||
|  |   <li><a href="/documentation/getting-started/preparing-your-application/">Preparing Your Application</a></li> | ||||||
|  |   <li><a href="/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a></li> | ||||||
|  |   <li><a href="/documentation/getting-started/cold-start/">Cold Start</a></li> | ||||||
|  |   <li><a href="/documentation/getting-started/rollbacks/">Rollbacks</a></li> | ||||||
|  |   <li class="divider"></li> | ||||||
|  |   <h5>Troubleshooting</h5> | ||||||
|  |   <li><a href="/documentation/troubleshooting/authentication/">SCM (Git) Authentication</a></li> | ||||||
|  |   <li><a href="/documentation/troubleshooting/connectivity/">Connectivity</a></li> | ||||||
|  |   <!--<li><a href="/documentation/troubleshooting/gateway-servers/">Gateway Servers</a></li>--> | ||||||
|  |   <li><a href="/documentation/troubleshooting/agent-forwarding/">Agent Forwarding</a></li> | ||||||
|  |   <li><a href="/documentation/troubleshooting/sudo-password/">`sudo` Password</a></li> | ||||||
|  |   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/">RVM, `rbenv` And `nvm`</a></li> | ||||||
|  |   <li class="divider"></li> | ||||||
|  |   <h5>FAQ</h5> | ||||||
|  |   <li><a | ||||||
|  |     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> | ||||||
|  |   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/">Should I Use Capistrano To Provision My Servers?</a></li> | ||||||
|  |   <li class="divider"></li> | ||||||
|  |   <h5>Power Use-Cases</h5> | ||||||
|  |   <li><a href="/documentation/power-use-cases/integration-with-rake/">Integration With Rake</a></li> | ||||||
|  |   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/">Driving Tools Such As <em>Chef Solo</em></a></li> | ||||||
|  |   <li class="divider"></li> | ||||||
|  |   <h5>Recent Announcements</h5> | ||||||
|  |    | ||||||
|  |     <li><a href="/2013/06/01/release-announcement.html"><span class="post-date">01 Jun 2013</span> Capistrano Version 3 Release Announcement</a></li> | ||||||
|  |    | ||||||
|  | </ul> | ||||||
|  | 
 | ||||||
|  |       </div> | ||||||
|  |       <div class="large-8 column"> | ||||||
|  |         <div class="content"> | ||||||
|  |           <h2>Authentication & Authorisation</h2> | ||||||
|  |           <p><strong>Note:</strong> In the documentation we simply recommend creating a single deployment user, | ||||||
|  | and sharing it between team members. If you know why this is a bad idea (or | ||||||
|  | why this may be against regulations in your jurisdiction in some cases, we | ||||||
|  | assume that you know well enough how to use groups, umasking and setgid bits | ||||||
|  | to make this work reliably for unique logins across team members)</p> | ||||||
|  | 
 | ||||||
|  | <p>To create this deploy user we'll assume something like the following has been | ||||||
|  | done:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>root@remote $ adduser deploy | ||||||
|  | root@remote $ passwd -l deploy</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>The first line creates a completely standard user, it has a home directory, | ||||||
|  | which we'll need in a moment, and has a shell, so it may log in. This needs to | ||||||
|  | be done <strong>on every server in your environment</strong>.</p> | ||||||
|  | 
 | ||||||
|  | <p>The second line <em>locks</em> the user, it changes the user's password to an | ||||||
|  | untypable string, guaranteeing that the user has no password which can be used | ||||||
|  | to log in.</p> | ||||||
|  | 
 | ||||||
|  | <h3 id="toc_0">Authentication</h3> | ||||||
|  | 
 | ||||||
|  | <p>There are two places that we need automated, promptless authentication:</p> | ||||||
|  | 
 | ||||||
|  | <ol> | ||||||
|  | <li><strong>From our workstation/notebook/etc to our servers.</strong> We do this with <strong>SSH | ||||||
|  |  keys</strong>, passphrase protected, ideally, using a <strong>key agent</strong>.</li> | ||||||
|  | <li><strong>From our servers to the repository host</strong>. We do this so that our servers | ||||||
|  |  can check out our application code from Github, or similar and install it | ||||||
|  |  to the servers. This is usually done using <strong>SSH agent forwarding</strong>, HTTP | ||||||
|  |  authentication, or with deploy keys.</li> | ||||||
|  | </ol> | ||||||
|  | 
 | ||||||
|  | <h4 id="toc_1">1.1 SSH keys from workstation to servers</h4> | ||||||
|  | 
 | ||||||
|  | <p><strong>Note:</strong> If you are on Windows, all bets are off, I'd love it if someone | ||||||
|  | could contribute a Windows guide to this, so we can include it here.</p> | ||||||
|  | 
 | ||||||
|  | <p>An SSH key is a mechanism that allows a <em>public</em> half one key to be placed on | ||||||
|  | a server, when we want to authenticate with that server, our SSH client uses | ||||||
|  | the <strong>private</strong> part of that key to negotiate with the server, if the keys are | ||||||
|  | correct, then we need to create the key.</p> | ||||||
|  | 
 | ||||||
|  | <p><strong>Hint:</strong> If you have more than one developer in your team, they should all add their | ||||||
|  | public key to the <code>deploy</code> user's <code>authorized_keys</code> file, that way if someone | ||||||
|  | quits or gets fired, you can remove their key from that file, and the rest of | ||||||
|  | you can keep on shipping!</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ ssh-keygen -t rsa -C 'me@my_email_address.com'</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>You'll be prompted for a passphrase, that's fine. Type one and keep it safe. | ||||||
|  | This passphrase ensures that if your computer is stolen, people still need a | ||||||
|  | passphrase to access your keys, in order to access your servers.</p> | ||||||
|  | 
 | ||||||
|  | <p>To avoid having to type this passphrase every time you need to use a key, most | ||||||
|  | operating systems have a concept of a <em>key agent</em>. This <em>key agent</em> stores SSH | ||||||
|  | keys securely between uses, typically the first time a key is needed in a | ||||||
|  | given time period, the SSH agent will load the key, prompt you for your | ||||||
|  | passphrase and then the key agent will remember the key for a certain amount | ||||||
|  | of time (on OSX it tends to be indefinite, on linux this can vary from 15 | ||||||
|  | minutes updwards.)</p> | ||||||
|  | 
 | ||||||
|  | <p>We can see which keys are loaded in the SSH agent by running <code>ssh-add -l</code></p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ ssh-add -l | ||||||
|  | 2048 af:ce:7e:c5:93:18:39:ff:54:20:7a:2d:ec:05:7c:a5 /Users/me/.ssh/id_rsa (RSA)</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>If you don't see any keys listed, you can simply run <code>ssh-add</code>:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhsot $ ssh-add | ||||||
|  | Identity added: /Users/me/.ssh/id_rsa (/Users/me/.ssh/id_rsa)</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>Typically, ssh-add will ask you for the passphrase when you add a key.</p> | ||||||
|  | 
 | ||||||
|  | <p><strong>Note:</strong> Although it's not mandatory to use an SSH agent (one could simply | ||||||
|  | use an unpassphrased key, and rely on SSH to find the key and exchange it). | ||||||
|  | Using an SSH agent makes things more secure, because we can use a passphrased | ||||||
|  | key without being prompts every time it is used. It <strong>also</strong> allows us to use | ||||||
|  | this same key to access the repository <em>via</em> the server without creating an | ||||||
|  | additional identity.</p> | ||||||
|  | 
 | ||||||
|  | <p>At this point with the key loaded into the agent, we need to put the | ||||||
|  | <strong>public</strong> part of the key into a file on each remote server called | ||||||
|  | <code>/home/users/deploy/.ssh/authorized_keys</code>, to get the contents of that file, | ||||||
|  | we can ask our local key agent for the public parts of the keys it has loaded:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ ssh-add -L | ||||||
|  | ssh-rsa jccXJ/JRfGxnkh/8iL........dbfCH/9cDiKa0Dw8XGAo01mU/w== /Users/me/.ssh/id_rsa</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>This will be a lot longer when you run it, I snipped the output because it | ||||||
|  | looked bad.</p> | ||||||
|  | 
 | ||||||
|  | <p>This line, as one line, needs to make it to the remote server and be added <em>to | ||||||
|  | it's own line</em> of the <code>deploy</code> user's <code>~/.ssh/authorized_keys</code> file. This file | ||||||
|  | then needs to be changed to permission mode <code>0600</code> (owner read/write, group | ||||||
|  | none, other none), in the <code>~/.ssh</code> directory which needs the permissions | ||||||
|  | <code>0700</code> (owner read/write/execute, group none, other none).</p> | ||||||
|  | 
 | ||||||
|  | <p>If you are on linux there often exists a command | ||||||
|  | <a href="http://linux.die.net/man/1/ssh-copy-id"><code>ssh-copy-id</code></a> which streamlines this | ||||||
|  | process, otherwise the worlflow is something like:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ ssh root@remote | ||||||
|  | root@remote $ su - deploy | ||||||
|  | deploy@remote $ cd ~ | ||||||
|  | deploy@remote $ mkdir .ssh | ||||||
|  | deploy@remote $ echo "ssh-rsa jccXJ/JRfGxnkh/8iL........dbfCH/9cDiKa0Dw8XGAo01mU/w== /Users/me/.ssh/id_rsa" >> .ssh/authorized_keys | ||||||
|  | deploy@remote $ chmod 700 .ssh | ||||||
|  | deploy@remote $ chmod 600 .ssh/authorized_keys</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p><strong>Remember:</strong> This needs to be done on every server you want to use, you can | ||||||
|  | use the same key for each one, but only one key per developer is recommended. | ||||||
|  | <em>Private</em> keys are named as such for a reason!</p> | ||||||
|  | 
 | ||||||
|  | <p>If we did all that correctly, we should now be able to do something like this:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ ssh deploy@one-of-my-servers.com 'hostname; uptime' | ||||||
|  | one-of-my-servers.com | ||||||
|  | 19:23:32 up 62 days, 44 min, 1 user, load average: 0.00, 0.01, 0.05</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>That should happen without having to enter a passphrase for your SSH key, or | ||||||
|  | promoting you for an SSH password (which the deploy user doesn't have anyway).</p> | ||||||
|  | 
 | ||||||
|  | <p>Verify that this works for all of your servers, and put your private key | ||||||
|  | somewhere safe. If you're working with multiple team members, it often pays to | ||||||
|  | collect everyone's public keys, indeed if your team is already using SSH keys | ||||||
|  | to access Github, you can reach any user's SSH keys at the following URL:</p> | ||||||
|  | 
 | ||||||
|  | <ul> | ||||||
|  | <li><code>https://github.com/theirusername.keys</code></li> | ||||||
|  | </ul> | ||||||
|  | 
 | ||||||
|  | <p>This can make getting user's keys onto servers much easier, as you can simply | ||||||
|  | <code>curl</code>/<code>wget</code> each user's key into the authorized keys file on the server | ||||||
|  | directly from Github.</p> | ||||||
|  | 
 | ||||||
|  | <blockquote class="twitter-tweet"><p>TIL <a | ||||||
|  | href="https://twitter.com/github">@github</a> exposes the ssh public keys for | ||||||
|  | users. <a href="https://t.co/Wo9g8nxI">https://t.co/Wo9g8nxI</a> Handy for | ||||||
|  | adding devs to servers/repos.</p>— Postmodern (@postmodern_mod3) <a | ||||||
|  | href="https://twitter.com/postmodern_mod3/statuses/300438256200339456">February | ||||||
|  | 10, 2013</a></blockquote> | ||||||
|  | 
 | ||||||
|  | <script async src="//platform.twitter.com/widgets.js" | ||||||
|  | charset="utf-8"></script> | ||||||
|  | 
 | ||||||
|  | <h4 id="toc_2">1.2 From our servers to the repository host</h4> | ||||||
|  | 
 | ||||||
|  | <p>With access from workstations to the servers settled, there is another hop to | ||||||
|  | contend with, which is letting the deploy user get access to the code | ||||||
|  | repository automatically. The options in order of preference:</p> | ||||||
|  | 
 | ||||||
|  | <h5 id="toc_3">1.2.1 SSH Agent Forwarding</h5> | ||||||
|  | 
 | ||||||
|  | <p>As we've already set up an SSH agent, we can use the <em>agent forwarding</em> | ||||||
|  | feature of SSH to make this key agent available to further <em>hops</em>. In short, | ||||||
|  | we can use <strong>our own ssh key</strong> to authenticate ourselves from the server, to | ||||||
|  | Github.</p> | ||||||
|  | 
 | ||||||
|  | <p>Here's how we can check if that works, first get the URL of the repository:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ git config remote.origin.url | ||||||
|  | git@github.com:capistrano/rails3-bootstrap-devise-cancan.git</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>Here we're listing our private (for testing purposes) fork of the | ||||||
|  | rails3-bootstrap-devise-cancan repository forked from the Rails Examples and | ||||||
|  | Tutorials project.</p> | ||||||
|  | 
 | ||||||
|  | <p>We can try to access the repository via our server by doing the following:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'># List SSH keys that are loaded into the agent | ||||||
|  | me@localhost $ ssh-add -l | ||||||
|  | # Make sure they key is loaded if 'ssh-add -l' didn't show anything | ||||||
|  | me@localhost $ ssh-add | ||||||
|  | me@localhost $ ssh -A deploy@one-of-my-servers.com 'git ls-remote git@github.com:capistrano/rails3-bootstrap-devise-cancan.git</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>We first check that the agent has the keys loaded, if not we simply load it, | ||||||
|  | and enter the passphrase when prompted.</p> | ||||||
|  | 
 | ||||||
|  | <p>Finally we use <code>ls-remote</code> from Git to list the remote objects, this is the | ||||||
|  | exact same check that Capistrano does internally before attempting to deploy. | ||||||
|  | The <code>-A</code> option may, or may not be required on your system, it's worth trying | ||||||
|  | it both ways just to know how your system treats agent forwarding by default.</p> | ||||||
|  | 
 | ||||||
|  | <p>From the SSH documentation:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>-A  Enables forwarding of the authentication agent connection.  This can also be | ||||||
|  |     specified on a per-host basis in a configuration file. | ||||||
|  | 
 | ||||||
|  |     Agent forwarding should be enabled with caution.  Users with the ability to | ||||||
|  |     bypass file permissions on the remote host (for the agent's UNIX-domain | ||||||
|  |     socket) can access the local agent through the forwarded connection.  An | ||||||
|  |     attacker cannot obtain key material from the agent, however they can perform | ||||||
|  |     operations on the keys that enable them to authenticate using the identities | ||||||
|  |     loaded into the agent.</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>In laymans terms, you should't use SSH agent forwarding to machines where you | ||||||
|  | don't trust the administrators, as they can can override the permissions on | ||||||
|  | the system and use your keys as if they were you. That said, if you can't | ||||||
|  | trust your server administrators, perhaps they shouldn't have access to your | ||||||
|  | servers!</p> | ||||||
|  | 
 | ||||||
|  | <h5 id="toc_4">1.2.2 HTTP Authentication</h5> | ||||||
|  | 
 | ||||||
|  | <p>In the case of HTTP authentication <strong>be sure to use HTTPS</strong>, otherwise your | ||||||
|  | password will be sent in cleartext over the network, depending what your hosts | ||||||
|  | network infratructure looks like that might be <em>very</em> bad news.</p> | ||||||
|  | 
 | ||||||
|  | <p>Typically when we try and list our remote objects, using the https method from | ||||||
|  | Github, we'll be prompted for a username and password:</p> | ||||||
|  | 
 | ||||||
|  | <h5 id="toc_5">1.2.2.1 With a regular username/password</h5> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ git ls-remote https://github.com/capistrano/rails3-bootstrap-devise-cancan.git | ||||||
|  | Username for 'https://github.com': myownusername | ||||||
|  | Password for 'https://capistrano@github.com':</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>This challenge response prompt doesn't work well for automating things, so | ||||||
|  | there are two ways to get around this depending on your server's host | ||||||
|  | operating system, the first is to use a <code>netrc</code> file, we won't talk about that | ||||||
|  | because the netrc is a global file that doesn't lend itself well to security.</p> | ||||||
|  | 
 | ||||||
|  | <p>The other mechanism, and the reason that its <strong>very</strong> important to always use | ||||||
|  | HTTPS not plain ol' HTTP is to embed the username and password in the URL, | ||||||
|  | note this won't work well if your password has special characters:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ git ls-remote https://capistrano:ourverysecretpassword@github.com/capistrano/rails3-bootstrap-devise-cancan.git | ||||||
|  | 3419812c9f146d9a84b44bcc2c3caef94da54758HEAD | ||||||
|  | 3419812c9f146d9a84b44bcc2c3caef94da54758HEADrefs/heads/master</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>The bigger problem with passwords, whether inlined into the URL, or entered | ||||||
|  | into a <code>netrc</code> file, is that the password gives access to <strong>your entire Github | ||||||
|  | Account</strong> not just to one single repository.</p> | ||||||
|  | 
 | ||||||
|  | <h5 id="toc_6">1.2.2.2 With an OAuth Personal API Token</h5> | ||||||
|  | 
 | ||||||
|  | <p>This mechanism still gives access to <strong>every repository</strong> you can access, but | ||||||
|  | at Github, they recently rolled out a feature called <a href="https://github.com/blog/1509-personal-api-tokens">Personal API | ||||||
|  | Tokens</a> which allow you to | ||||||
|  | do something like this:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ git ls-remote https://.....................@github.com/capistrano/rails3-bootstrap-devise-cancan.git | ||||||
|  | 3419812c9f146d9a84b44bcc2c3caef94da54758HEAD | ||||||
|  | 3419812c9f146d9a84b44bcc2c3caef94da54758HEADrefs/heads/master</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>Where <code>....</code> is a personal API token, as such:</p> | ||||||
|  | 
 | ||||||
|  | <p><img src="/images/github-personal-api-token-page.png" alt="Github Personal API Token Page"></p> | ||||||
|  | 
 | ||||||
|  | <h5 id="toc_7">1.2.3 Deploy Keys</h5> | ||||||
|  | 
 | ||||||
|  | <p>Deploy keys, a feature of Github, and some other platforms allow you to | ||||||
|  | generate a <strong>second</strong> set of SSH keys for the connection between Github and | ||||||
|  | the servers themselves.</p> | ||||||
|  | 
 | ||||||
|  | <p>Slightly perversely in this case the public key is uploaded to the repository | ||||||
|  | host, and the private key must be copied to each server that you want to | ||||||
|  | deploy to.</p> | ||||||
|  | 
 | ||||||
|  | <p>Github has a quite excellent guide on this, much of which (unsurprisingly) | ||||||
|  | overlaps with the SSH key instructions above.</p> | ||||||
|  | 
 | ||||||
|  | <ul> | ||||||
|  | <li><a href="https://help.github.com/articles/managing-deploy-keys">Github Help: Managing Deploy Keys</a></li> | ||||||
|  | </ul> | ||||||
|  | 
 | ||||||
|  | <h3 id="toc_8">Authorisation</h3> | ||||||
|  | 
 | ||||||
|  | <p>The second part of this topic is that our deploy user needs to be authorised | ||||||
|  | to work in the deployment directory, on the server. That means we need to be | ||||||
|  | able to work, ideally without <code>sudo</code> (none of the default Capistrano recipes | ||||||
|  | expect <code>sudo</code> to be available), or for your custom recipes, you will need to | ||||||
|  | have configured <em>passwordless</em> <code>sudo</code>. Configuring <code>sudo</code> to give some users | ||||||
|  | access to come commands under some circumstances is beyond the scope of this | ||||||
|  | documentation, but sufficed to say something like:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>deploy ALL=NOPASSWD:/etc/init.d/mysqld, /etc/init.d/apache2</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>This example would give the user named <code>deploy</code> access to call <code>sudo | ||||||
|  | /etc/init.d/mysql _________</code> and the same for the <code>apache2</code> control script.</p> | ||||||
|  | 
 | ||||||
|  | <p><strong>Granting passwordless sudo should not be done lightly.</strong> It can be dangerous. | ||||||
|  | For example if an unprivilidged user can <em>edit</em> the script that they can run | ||||||
|  | as root, they can easily edit it to do anything they want that is evil. Use | ||||||
|  | this carefully, and ideally architect your systems so that non-privlidged | ||||||
|  | users can restart services, or that services restart <em>themselves</em> when they | ||||||
|  | notice change.</p> | ||||||
|  | 
 | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <!--<div class="container">                                     --> | ||||||
|  |       <!--      <h1 class="title"><a href="/">Capistrano</a></h1>--> | ||||||
|  |       <!--      <a class="extra" href="/">home</a>                    --> | ||||||
|  |       <!--    </div>                                                  --> | ||||||
|  | 
 | ||||||
|  |     <!--    <p><strong>Note:</strong> In the documentation we simply recommend creating a single deployment user, | ||||||
|  | and sharing it between team members. If you know why this is a bad idea (or | ||||||
|  | why this may be against regulations in your jurisdiction in some cases, we | ||||||
|  | assume that you know well enough how to use groups, umasking and setgid bits | ||||||
|  | to make this work reliably for unique logins across team members)</p> | ||||||
|  | 
 | ||||||
|  | <p>To create this deploy user we'll assume something like the following has been | ||||||
|  | done:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>root@remote $ adduser deploy | ||||||
|  | root@remote $ passwd -l deploy</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>The first line creates a completely standard user, it has a home directory, | ||||||
|  | which we'll need in a moment, and has a shell, so it may log in. This needs to | ||||||
|  | be done <strong>on every server in your environment</strong>.</p> | ||||||
|  | 
 | ||||||
|  | <p>The second line <em>locks</em> the user, it changes the user's password to an | ||||||
|  | untypable string, guaranteeing that the user has no password which can be used | ||||||
|  | to log in.</p> | ||||||
|  | 
 | ||||||
|  | <h3 id="toc_0">Authentication</h3> | ||||||
|  | 
 | ||||||
|  | <p>There are two places that we need automated, promptless authentication:</p> | ||||||
|  | 
 | ||||||
|  | <ol> | ||||||
|  | <li><strong>From our workstation/notebook/etc to our servers.</strong> We do this with <strong>SSH | ||||||
|  |  keys</strong>, passphrase protected, ideally, using a <strong>key agent</strong>.</li> | ||||||
|  | <li><strong>From our servers to the repository host</strong>. We do this so that our servers | ||||||
|  |  can check out our application code from Github, or similar and install it | ||||||
|  |  to the servers. This is usually done using <strong>SSH agent forwarding</strong>, HTTP | ||||||
|  |  authentication, or with deploy keys.</li> | ||||||
|  | </ol> | ||||||
|  | 
 | ||||||
|  | <h4 id="toc_1">1.1 SSH keys from workstation to servers</h4> | ||||||
|  | 
 | ||||||
|  | <p><strong>Note:</strong> If you are on Windows, all bets are off, I'd love it if someone | ||||||
|  | could contribute a Windows guide to this, so we can include it here.</p> | ||||||
|  | 
 | ||||||
|  | <p>An SSH key is a mechanism that allows a <em>public</em> half one key to be placed on | ||||||
|  | a server, when we want to authenticate with that server, our SSH client uses | ||||||
|  | the <strong>private</strong> part of that key to negotiate with the server, if the keys are | ||||||
|  | correct, then we need to create the key.</p> | ||||||
|  | 
 | ||||||
|  | <p><strong>Hint:</strong> If you have more than one developer in your team, they should all add their | ||||||
|  | public key to the <code>deploy</code> user's <code>authorized_keys</code> file, that way if someone | ||||||
|  | quits or gets fired, you can remove their key from that file, and the rest of | ||||||
|  | you can keep on shipping!</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ ssh-keygen -t rsa -C 'me@my_email_address.com'</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>You'll be prompted for a passphrase, that's fine. Type one and keep it safe. | ||||||
|  | This passphrase ensures that if your computer is stolen, people still need a | ||||||
|  | passphrase to access your keys, in order to access your servers.</p> | ||||||
|  | 
 | ||||||
|  | <p>To avoid having to type this passphrase every time you need to use a key, most | ||||||
|  | operating systems have a concept of a <em>key agent</em>. This <em>key agent</em> stores SSH | ||||||
|  | keys securely between uses, typically the first time a key is needed in a | ||||||
|  | given time period, the SSH agent will load the key, prompt you for your | ||||||
|  | passphrase and then the key agent will remember the key for a certain amount | ||||||
|  | of time (on OSX it tends to be indefinite, on linux this can vary from 15 | ||||||
|  | minutes updwards.)</p> | ||||||
|  | 
 | ||||||
|  | <p>We can see which keys are loaded in the SSH agent by running <code>ssh-add -l</code></p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ ssh-add -l | ||||||
|  | 2048 af:ce:7e:c5:93:18:39:ff:54:20:7a:2d:ec:05:7c:a5 /Users/me/.ssh/id_rsa (RSA)</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>If you don't see any keys listed, you can simply run <code>ssh-add</code>:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhsot $ ssh-add | ||||||
|  | Identity added: /Users/me/.ssh/id_rsa (/Users/me/.ssh/id_rsa)</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>Typically, ssh-add will ask you for the passphrase when you add a key.</p> | ||||||
|  | 
 | ||||||
|  | <p><strong>Note:</strong> Although it's not mandatory to use an SSH agent (one could simply | ||||||
|  | use an unpassphrased key, and rely on SSH to find the key and exchange it). | ||||||
|  | Using an SSH agent makes things more secure, because we can use a passphrased | ||||||
|  | key without being prompts every time it is used. It <strong>also</strong> allows us to use | ||||||
|  | this same key to access the repository <em>via</em> the server without creating an | ||||||
|  | additional identity.</p> | ||||||
|  | 
 | ||||||
|  | <p>At this point with the key loaded into the agent, we need to put the | ||||||
|  | <strong>public</strong> part of the key into a file on each remote server called | ||||||
|  | <code>/home/users/deploy/.ssh/authorized_keys</code>, to get the contents of that file, | ||||||
|  | we can ask our local key agent for the public parts of the keys it has loaded:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ ssh-add -L | ||||||
|  | ssh-rsa jccXJ/JRfGxnkh/8iL........dbfCH/9cDiKa0Dw8XGAo01mU/w== /Users/me/.ssh/id_rsa</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>This will be a lot longer when you run it, I snipped the output because it | ||||||
|  | looked bad.</p> | ||||||
|  | 
 | ||||||
|  | <p>This line, as one line, needs to make it to the remote server and be added <em>to | ||||||
|  | it's own line</em> of the <code>deploy</code> user's <code>~/.ssh/authorized_keys</code> file. This file | ||||||
|  | then needs to be changed to permission mode <code>0600</code> (owner read/write, group | ||||||
|  | none, other none), in the <code>~/.ssh</code> directory which needs the permissions | ||||||
|  | <code>0700</code> (owner read/write/execute, group none, other none).</p> | ||||||
|  | 
 | ||||||
|  | <p>If you are on linux there often exists a command | ||||||
|  | <a href="http://linux.die.net/man/1/ssh-copy-id"><code>ssh-copy-id</code></a> which streamlines this | ||||||
|  | process, otherwise the worlflow is something like:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ ssh root@remote | ||||||
|  | root@remote $ su - deploy | ||||||
|  | deploy@remote $ cd ~ | ||||||
|  | deploy@remote $ mkdir .ssh | ||||||
|  | deploy@remote $ echo "ssh-rsa jccXJ/JRfGxnkh/8iL........dbfCH/9cDiKa0Dw8XGAo01mU/w== /Users/me/.ssh/id_rsa" >> .ssh/authorized_keys | ||||||
|  | deploy@remote $ chmod 700 .ssh | ||||||
|  | deploy@remote $ chmod 600 .ssh/authorized_keys</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p><strong>Remember:</strong> This needs to be done on every server you want to use, you can | ||||||
|  | use the same key for each one, but only one key per developer is recommended. | ||||||
|  | <em>Private</em> keys are named as such for a reason!</p> | ||||||
|  | 
 | ||||||
|  | <p>If we did all that correctly, we should now be able to do something like this:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ ssh deploy@one-of-my-servers.com 'hostname; uptime' | ||||||
|  | one-of-my-servers.com | ||||||
|  | 19:23:32 up 62 days, 44 min, 1 user, load average: 0.00, 0.01, 0.05</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>That should happen without having to enter a passphrase for your SSH key, or | ||||||
|  | promoting you for an SSH password (which the deploy user doesn't have anyway).</p> | ||||||
|  | 
 | ||||||
|  | <p>Verify that this works for all of your servers, and put your private key | ||||||
|  | somewhere safe. If you're working with multiple team members, it often pays to | ||||||
|  | collect everyone's public keys, indeed if your team is already using SSH keys | ||||||
|  | to access Github, you can reach any user's SSH keys at the following URL:</p> | ||||||
|  | 
 | ||||||
|  | <ul> | ||||||
|  | <li><code>https://github.com/theirusername.keys</code></li> | ||||||
|  | </ul> | ||||||
|  | 
 | ||||||
|  | <p>This can make getting user's keys onto servers much easier, as you can simply | ||||||
|  | <code>curl</code>/<code>wget</code> each user's key into the authorized keys file on the server | ||||||
|  | directly from Github.</p> | ||||||
|  | 
 | ||||||
|  | <blockquote class="twitter-tweet"><p>TIL <a | ||||||
|  | href="https://twitter.com/github">@github</a> exposes the ssh public keys for | ||||||
|  | users. <a href="https://t.co/Wo9g8nxI">https://t.co/Wo9g8nxI</a> Handy for | ||||||
|  | adding devs to servers/repos.</p>— Postmodern (@postmodern_mod3) <a | ||||||
|  | href="https://twitter.com/postmodern_mod3/statuses/300438256200339456">February | ||||||
|  | 10, 2013</a></blockquote> | ||||||
|  | 
 | ||||||
|  | <script async src="//platform.twitter.com/widgets.js" | ||||||
|  | charset="utf-8"></script> | ||||||
|  | 
 | ||||||
|  | <h4 id="toc_2">1.2 From our servers to the repository host</h4> | ||||||
|  | 
 | ||||||
|  | <p>With access from workstations to the servers settled, there is another hop to | ||||||
|  | contend with, which is letting the deploy user get access to the code | ||||||
|  | repository automatically. The options in order of preference:</p> | ||||||
|  | 
 | ||||||
|  | <h5 id="toc_3">1.2.1 SSH Agent Forwarding</h5> | ||||||
|  | 
 | ||||||
|  | <p>As we've already set up an SSH agent, we can use the <em>agent forwarding</em> | ||||||
|  | feature of SSH to make this key agent available to further <em>hops</em>. In short, | ||||||
|  | we can use <strong>our own ssh key</strong> to authenticate ourselves from the server, to | ||||||
|  | Github.</p> | ||||||
|  | 
 | ||||||
|  | <p>Here's how we can check if that works, first get the URL of the repository:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ git config remote.origin.url | ||||||
|  | git@github.com:capistrano/rails3-bootstrap-devise-cancan.git</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>Here we're listing our private (for testing purposes) fork of the | ||||||
|  | rails3-bootstrap-devise-cancan repository forked from the Rails Examples and | ||||||
|  | Tutorials project.</p> | ||||||
|  | 
 | ||||||
|  | <p>We can try to access the repository via our server by doing the following:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'># List SSH keys that are loaded into the agent | ||||||
|  | me@localhost $ ssh-add -l | ||||||
|  | # Make sure they key is loaded if 'ssh-add -l' didn't show anything | ||||||
|  | me@localhost $ ssh-add | ||||||
|  | me@localhost $ ssh -A deploy@one-of-my-servers.com 'git ls-remote git@github.com:capistrano/rails3-bootstrap-devise-cancan.git</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>We first check that the agent has the keys loaded, if not we simply load it, | ||||||
|  | and enter the passphrase when prompted.</p> | ||||||
|  | 
 | ||||||
|  | <p>Finally we use <code>ls-remote</code> from Git to list the remote objects, this is the | ||||||
|  | exact same check that Capistrano does internally before attempting to deploy. | ||||||
|  | The <code>-A</code> option may, or may not be required on your system, it's worth trying | ||||||
|  | it both ways just to know how your system treats agent forwarding by default.</p> | ||||||
|  | 
 | ||||||
|  | <p>From the SSH documentation:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>-A  Enables forwarding of the authentication agent connection.  This can also be | ||||||
|  |     specified on a per-host basis in a configuration file. | ||||||
|  | 
 | ||||||
|  |     Agent forwarding should be enabled with caution.  Users with the ability to | ||||||
|  |     bypass file permissions on the remote host (for the agent's UNIX-domain | ||||||
|  |     socket) can access the local agent through the forwarded connection.  An | ||||||
|  |     attacker cannot obtain key material from the agent, however they can perform | ||||||
|  |     operations on the keys that enable them to authenticate using the identities | ||||||
|  |     loaded into the agent.</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>In laymans terms, you should't use SSH agent forwarding to machines where you | ||||||
|  | don't trust the administrators, as they can can override the permissions on | ||||||
|  | the system and use your keys as if they were you. That said, if you can't | ||||||
|  | trust your server administrators, perhaps they shouldn't have access to your | ||||||
|  | servers!</p> | ||||||
|  | 
 | ||||||
|  | <h5 id="toc_4">1.2.2 HTTP Authentication</h5> | ||||||
|  | 
 | ||||||
|  | <p>In the case of HTTP authentication <strong>be sure to use HTTPS</strong>, otherwise your | ||||||
|  | password will be sent in cleartext over the network, depending what your hosts | ||||||
|  | network infratructure looks like that might be <em>very</em> bad news.</p> | ||||||
|  | 
 | ||||||
|  | <p>Typically when we try and list our remote objects, using the https method from | ||||||
|  | Github, we'll be prompted for a username and password:</p> | ||||||
|  | 
 | ||||||
|  | <h5 id="toc_5">1.2.2.1 With a regular username/password</h5> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ git ls-remote https://github.com/capistrano/rails3-bootstrap-devise-cancan.git | ||||||
|  | Username for 'https://github.com': myownusername | ||||||
|  | Password for 'https://capistrano@github.com':</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>This challenge response prompt doesn't work well for automating things, so | ||||||
|  | there are two ways to get around this depending on your server's host | ||||||
|  | operating system, the first is to use a <code>netrc</code> file, we won't talk about that | ||||||
|  | because the netrc is a global file that doesn't lend itself well to security.</p> | ||||||
|  | 
 | ||||||
|  | <p>The other mechanism, and the reason that its <strong>very</strong> important to always use | ||||||
|  | HTTPS not plain ol' HTTP is to embed the username and password in the URL, | ||||||
|  | note this won't work well if your password has special characters:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ git ls-remote https://capistrano:ourverysecretpassword@github.com/capistrano/rails3-bootstrap-devise-cancan.git | ||||||
|  | 3419812c9f146d9a84b44bcc2c3caef94da54758HEAD | ||||||
|  | 3419812c9f146d9a84b44bcc2c3caef94da54758HEADrefs/heads/master</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>The bigger problem with passwords, whether inlined into the URL, or entered | ||||||
|  | into a <code>netrc</code> file, is that the password gives access to <strong>your entire Github | ||||||
|  | Account</strong> not just to one single repository.</p> | ||||||
|  | 
 | ||||||
|  | <h5 id="toc_6">1.2.2.2 With an OAuth Personal API Token</h5> | ||||||
|  | 
 | ||||||
|  | <p>This mechanism still gives access to <strong>every repository</strong> you can access, but | ||||||
|  | at Github, they recently rolled out a feature called <a href="https://github.com/blog/1509-personal-api-tokens">Personal API | ||||||
|  | Tokens</a> which allow you to | ||||||
|  | do something like this:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>me@localhost $ git ls-remote https://.....................@github.com/capistrano/rails3-bootstrap-devise-cancan.git | ||||||
|  | 3419812c9f146d9a84b44bcc2c3caef94da54758HEAD | ||||||
|  | 3419812c9f146d9a84b44bcc2c3caef94da54758HEADrefs/heads/master</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>Where <code>....</code> is a personal API token, as such:</p> | ||||||
|  | 
 | ||||||
|  | <p><img src="/images/github-personal-api-token-page.png" alt="Github Personal API Token Page"></p> | ||||||
|  | 
 | ||||||
|  | <h5 id="toc_7">1.2.3 Deploy Keys</h5> | ||||||
|  | 
 | ||||||
|  | <p>Deploy keys, a feature of Github, and some other platforms allow you to | ||||||
|  | generate a <strong>second</strong> set of SSH keys for the connection between Github and | ||||||
|  | the servers themselves.</p> | ||||||
|  | 
 | ||||||
|  | <p>Slightly perversely in this case the public key is uploaded to the repository | ||||||
|  | host, and the private key must be copied to each server that you want to | ||||||
|  | deploy to.</p> | ||||||
|  | 
 | ||||||
|  | <p>Github has a quite excellent guide on this, much of which (unsurprisingly) | ||||||
|  | overlaps with the SSH key instructions above.</p> | ||||||
|  | 
 | ||||||
|  | <ul> | ||||||
|  | <li><a href="https://help.github.com/articles/managing-deploy-keys">Github Help: Managing Deploy Keys</a></li> | ||||||
|  | </ul> | ||||||
|  | 
 | ||||||
|  | <h3 id="toc_8">Authorisation</h3> | ||||||
|  | 
 | ||||||
|  | <p>The second part of this topic is that our deploy user needs to be authorised | ||||||
|  | to work in the deployment directory, on the server. That means we need to be | ||||||
|  | able to work, ideally without <code>sudo</code> (none of the default Capistrano recipes | ||||||
|  | expect <code>sudo</code> to be available), or for your custom recipes, you will need to | ||||||
|  | have configured <em>passwordless</em> <code>sudo</code>. Configuring <code>sudo</code> to give some users | ||||||
|  | access to come commands under some circumstances is beyond the scope of this | ||||||
|  | documentation, but sufficed to say something like:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-bash'>deploy ALL=NOPASSWD:/etc/init.d/mysqld, /etc/init.d/apache2</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>This example would give the user named <code>deploy</code> access to call <code>sudo | ||||||
|  | /etc/init.d/mysql _________</code> and the same for the <code>apache2</code> control script.</p> | ||||||
|  | 
 | ||||||
|  | <p><strong>Granting passwordless sudo should not be done lightly.</strong> It can be dangerous. | ||||||
|  | For example if an unprivilidged user can <em>edit</em> the script that they can run | ||||||
|  | as root, they can easily edit it to do anything they want that is evil. Use | ||||||
|  | this carefully, and ideally architect your systems so that non-privlidged | ||||||
|  | users can restart services, or that services restart <em>themselves</em> when they | ||||||
|  | notice change.</p> | ||||||
|  |                                            --> | ||||||
|  | 
 | ||||||
|  |     <!--</div> [> /container <]                                     --> | ||||||
|  | 
 | ||||||
|  |   <div class="row"> | ||||||
|  |   <div class="large-4 columns"> | ||||||
|  |     <ul> | ||||||
|  |     <li><a href="/about">About Capistrano</a></li> | ||||||
|  |     <li><a href="https://github.com/capistrano/capistrano/blob/master/CONTRIBUTING">Contributing</a></li> | ||||||
|  |     <li><a href="https://rubygems.org/gems/capistrano/versions">Releases</a></li> | ||||||
|  |     <li><a href="/upgrading">Upgrading</a></li> | ||||||
|  |     <li><a href="/security">Security</a></li> | ||||||
|  |     </ul> | ||||||
|  |   </div> | ||||||
|  | 
 | ||||||
|  |   <div class="large-4 columns"> | ||||||
|  |     <ul> | ||||||
|  |       <li><a href="http://stackoverflow.com/questions/tagged/capistrano">StackOverflow</a></li> | ||||||
|  |       <li><a href="https://groups.google.com/forum/#!forum/capistrano">Mailing List</a></li> | ||||||
|  |       <li><a href=".... ">Commercial Support</a></li> | ||||||
|  |     </ul> | ||||||
|  |   </div> | ||||||
|  | 
 | ||||||
|  |   <div class="large-4 columns"> | ||||||
|  |     <ul> | ||||||
|  |       <li><a href="//twitter.com/capistranorb"><i class="foundicon-twitter"></i></a></li> | ||||||
|  |       <li><a href="//github.com/capistrano"><i class="foundicon-github"></i></a></li> | ||||||
|  |     </ul> | ||||||
|  |   </div> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   <script src="/js/prism.js"></script> | ||||||
|  |   <script src="/js/prism.ruby.js"></script> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
|  | @ -16,6 +16,36 @@ | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
| 
 | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       var _gauges = _gauges || []; | ||||||
|  |       (function() { | ||||||
|  |         var t   = document.createElement('script'); | ||||||
|  |         t.type  = 'text/javascript'; | ||||||
|  |         t.async = true; | ||||||
|  |         t.id    = 'gauges-tracker'; | ||||||
|  |         t.setAttribute('data-site-id', '51c83c32613f5d7df70000bc'); | ||||||
|  |         t.src = '//secure.gaug.es/track.js'; | ||||||
|  |         var s = document.getElementsByTagName('script')[0]; | ||||||
|  |         s.parentNode.insertBefore(t, s); | ||||||
|  |       })(); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       setTimeout(function(){var a=document.createElement("script"); | ||||||
|  |       var b=document.getElementsByTagName("script")[0]; | ||||||
|  |       a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0017/6418.js?"+Math.floor(new Date().getTime()/3600000); | ||||||
|  |       a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script> | ||||||
|  |       (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||||||
|  |       (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||||||
|  |       m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||||||
|  |       })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | ||||||
|  | 
 | ||||||
|  |       ga('create', 'UA-41970098-1', 'capistranorb.com'); | ||||||
|  |       ga('send', 'pageview'); | ||||||
|  |     </script> | ||||||
|     <div class="top-bar"> |     <div class="top-bar"> | ||||||
|   <a href="/" class="brand"> |   <a href="/" class="brand"> | ||||||
|     <img src="/images/CapistranoLogo.png" /> |     <img src="/images/CapistranoLogo.png" /> | ||||||
|  | @ -33,28 +63,28 @@ | ||||||
|   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> |   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Getting Started</h5> |   <h5>Getting Started</h5> | ||||||
|   <li><a href="/documentation/getting-started/installation/index.html">Installation</a></li> |   <li><a href="/documentation/getting-started/installation/">Installation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/preparing-your-application/index.html">Preparing Your Application</a></li> |   <li><a href="/documentation/getting-started/preparing-your-application/">Preparing Your Application</a></li> | ||||||
|   <li><aj href="/documentation/getting-started/authentication-and-authorisation/index.html">Authentication & Authorisation</a></li> |   <li><a href="/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/cold-start/index.html">Cold Start</a></li> |   <li><a href="/documentation/getting-started/cold-start/">Cold Start</a></li> | ||||||
|   <li><a href="/documentation/getting-started/rollbacks/index.html">Rollbacks</a></li> |   <li><a href="/documentation/getting-started/rollbacks/">Rollbacks</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Troubleshooting</h5> |   <h5>Troubleshooting</h5> | ||||||
|   <li><a href="/documentation/troubleshooting/authentication/index.html">SCM (Git) Authentication</a></li> |   <li><a href="/documentation/troubleshooting/authentication/">SCM (Git) Authentication</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/connectivity/index.html">Connectivity</a></li> |   <li><a href="/documentation/troubleshooting/connectivity/">Connectivity</a></li> | ||||||
|   <!--<li><a href="/documentation/troubleshooting/gateway-servers/index.html">Gateway Servers</a></li>--> |   <!--<li><a href="/documentation/troubleshooting/gateway-servers/">Gateway Servers</a></li>--> | ||||||
|   <li><a href="/documentation/troubleshooting/agent-forwarding/index.html">Agent Forwarding</a></li> |   <li><a href="/documentation/troubleshooting/agent-forwarding/">Agent Forwarding</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/sudo-password/index.html">`sudo` Password</a></li> |   <li><a href="/documentation/troubleshooting/sudo-password/">`sudo` Password</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/index.html">RVM, `rbenv` And `nvm`</a></li> |   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/">RVM, `rbenv` And `nvm`</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>FAQ</h5> |   <h5>FAQ</h5> | ||||||
|   <li><a |   <li><a | ||||||
|     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/index.html">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> |     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> | ||||||
|   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/index.html">Should I Use Capistrano To Provision My Servers?</a></li> |   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/">Should I Use Capistrano To Provision My Servers?</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Power Use-Cases</h5> |   <h5>Power Use-Cases</h5> | ||||||
|   <li><a href="/documentation/power-use-cases/integration-with-rake/index.html">Integration With Rake</a></li> |   <li><a href="/documentation/power-use-cases/integration-with-rake/">Integration With Rake</a></li> | ||||||
|   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/index.html">Driving Tools Such As <em>Chef Solo</em></a></li> |   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/">Driving Tools Such As <em>Chef Solo</em></a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Recent Announcements</h5> |   <h5>Recent Announcements</h5> | ||||||
|    |    | ||||||
|  |  | ||||||
|  | @ -16,6 +16,36 @@ | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
| 
 | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       var _gauges = _gauges || []; | ||||||
|  |       (function() { | ||||||
|  |         var t   = document.createElement('script'); | ||||||
|  |         t.type  = 'text/javascript'; | ||||||
|  |         t.async = true; | ||||||
|  |         t.id    = 'gauges-tracker'; | ||||||
|  |         t.setAttribute('data-site-id', '51c83c32613f5d7df70000bc'); | ||||||
|  |         t.src = '//secure.gaug.es/track.js'; | ||||||
|  |         var s = document.getElementsByTagName('script')[0]; | ||||||
|  |         s.parentNode.insertBefore(t, s); | ||||||
|  |       })(); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       setTimeout(function(){var a=document.createElement("script"); | ||||||
|  |       var b=document.getElementsByTagName("script")[0]; | ||||||
|  |       a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0017/6418.js?"+Math.floor(new Date().getTime()/3600000); | ||||||
|  |       a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script> | ||||||
|  |       (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||||||
|  |       (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||||||
|  |       m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||||||
|  |       })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | ||||||
|  | 
 | ||||||
|  |       ga('create', 'UA-41970098-1', 'capistranorb.com'); | ||||||
|  |       ga('send', 'pageview'); | ||||||
|  |     </script> | ||||||
|     <div class="top-bar"> |     <div class="top-bar"> | ||||||
|   <a href="/" class="brand"> |   <a href="/" class="brand"> | ||||||
|     <img src="/images/CapistranoLogo.png" /> |     <img src="/images/CapistranoLogo.png" /> | ||||||
|  | @ -33,28 +63,28 @@ | ||||||
|   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> |   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Getting Started</h5> |   <h5>Getting Started</h5> | ||||||
|   <li><a href="/documentation/getting-started/installation/index.html">Installation</a></li> |   <li><a href="/documentation/getting-started/installation/">Installation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/preparing-your-application/index.html">Preparing Your Application</a></li> |   <li><a href="/documentation/getting-started/preparing-your-application/">Preparing Your Application</a></li> | ||||||
|   <li><aj href="/documentation/getting-started/authentication-and-authorisation/index.html">Authentication & Authorisation</a></li> |   <li><a href="/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/cold-start/index.html">Cold Start</a></li> |   <li><a href="/documentation/getting-started/cold-start/">Cold Start</a></li> | ||||||
|   <li><a href="/documentation/getting-started/rollbacks/index.html">Rollbacks</a></li> |   <li><a href="/documentation/getting-started/rollbacks/">Rollbacks</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Troubleshooting</h5> |   <h5>Troubleshooting</h5> | ||||||
|   <li><a href="/documentation/troubleshooting/authentication/index.html">SCM (Git) Authentication</a></li> |   <li><a href="/documentation/troubleshooting/authentication/">SCM (Git) Authentication</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/connectivity/index.html">Connectivity</a></li> |   <li><a href="/documentation/troubleshooting/connectivity/">Connectivity</a></li> | ||||||
|   <!--<li><a href="/documentation/troubleshooting/gateway-servers/index.html">Gateway Servers</a></li>--> |   <!--<li><a href="/documentation/troubleshooting/gateway-servers/">Gateway Servers</a></li>--> | ||||||
|   <li><a href="/documentation/troubleshooting/agent-forwarding/index.html">Agent Forwarding</a></li> |   <li><a href="/documentation/troubleshooting/agent-forwarding/">Agent Forwarding</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/sudo-password/index.html">`sudo` Password</a></li> |   <li><a href="/documentation/troubleshooting/sudo-password/">`sudo` Password</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/index.html">RVM, `rbenv` And `nvm`</a></li> |   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/">RVM, `rbenv` And `nvm`</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>FAQ</h5> |   <h5>FAQ</h5> | ||||||
|   <li><a |   <li><a | ||||||
|     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/index.html">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> |     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> | ||||||
|   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/index.html">Should I Use Capistrano To Provision My Servers?</a></li> |   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/">Should I Use Capistrano To Provision My Servers?</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Power Use-Cases</h5> |   <h5>Power Use-Cases</h5> | ||||||
|   <li><a href="/documentation/power-use-cases/integration-with-rake/index.html">Integration With Rake</a></li> |   <li><a href="/documentation/power-use-cases/integration-with-rake/">Integration With Rake</a></li> | ||||||
|   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/index.html">Driving Tools Such As <em>Chef Solo</em></a></li> |   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/">Driving Tools Such As <em>Chef Solo</em></a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Recent Announcements</h5> |   <h5>Recent Announcements</h5> | ||||||
|    |    | ||||||
|  | @ -71,7 +101,7 @@ | ||||||
|   here have parallels in Python, or PHP applications |   here have parallels in Python, or PHP applications | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <h2 id="toc_0">1. Commit your application to some externally available source control hosting provider.</h2> | <h3 id="toc_0">1. Commit your application to some externally available source control hosting provider.</h3> | ||||||
| 
 | 
 | ||||||
| <p>If you are not doing already, you should host your code somewhere with a | <p>If you are not doing already, you should host your code somewhere with a | ||||||
| provuder such as Github, BitBucket, Codeplane, or repositoryhosting.com.</p> | provuder such as Github, BitBucket, Codeplane, or repositoryhosting.com.</p> | ||||||
|  | @ -83,7 +113,7 @@ contribute if you know these tools well, we don't and don't want to force our | ||||||
| miscomprehended notions upon anyone. | miscomprehended notions upon anyone. | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <h2 id="toc_1">2. Move secrets out of the repository.</h2> | <h3 id="toc_1">2. Move secrets out of the repository.</h3> | ||||||
| 
 | 
 | ||||||
| <div class="alert-box alert"> | <div class="alert-box alert"> | ||||||
| If you've accidentally committed state secrets to the repository, you might | If you've accidentally committed state secrets to the repository, you might | ||||||
|  | @ -109,7 +139,7 @@ $ echo config/database.yml >> .gitignore</code></pre> | ||||||
| <p>This should be done for any other secret files, we'll create the production | <p>This should be done for any other secret files, we'll create the production | ||||||
| version of the file when we deploy, and symlink it into place.</p> | version of the file when we deploy, and symlink it into place.</p> | ||||||
| 
 | 
 | ||||||
| <h2 id="toc_2">3. Initialize Capistrano in your application.</h2> | <h3 id="toc_2">3. Initialize Capistrano in your application.</h3> | ||||||
| 
 | 
 | ||||||
| <div> | <div> | ||||||
|   <pre data-line=''><code class='language-bash'>$ cd my-project |   <pre data-line=''><code class='language-bash'>$ cd my-project | ||||||
|  | @ -130,6 +160,125 @@ $ cap install</code></pre> | ||||||
|             └── tasks</code></pre> |             └── tasks</code></pre> | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
|  | <h3 id="toc_3">4. Configure your server addresses in the generated files.</h3> | ||||||
|  | 
 | ||||||
|  | <p>We'll just work with the staging environment here, so you can pretend that | ||||||
|  | <code>config/deploy/production.rb</code> doesn't exist, for the most part that's yoru | ||||||
|  | business.</p> | ||||||
|  | 
 | ||||||
|  | <p>Capistrano breaks down common tasks into a notion of <em>roles</em>, that is, taking | ||||||
|  | a typical Rails application that we have roughly speaking three roles, <code>web</code>, | ||||||
|  | <code>app</code>, and <code>db</code>.</p> | ||||||
|  | 
 | ||||||
|  | <p>It can be confusing, as the boundary of web and app servers is a bit blurry if | ||||||
|  | using <a href="">Passenger</a> with Apache, which in effect embeds your app server in the | ||||||
|  | web server (embeds Passenger in the Apache process itself), confusingly | ||||||
|  | Passenger can also be used in modes where this isn't true, so we'll ignore | ||||||
|  | that for the time being, and if you know the difference (i.e you are using | ||||||
|  | nginx as your web server, and puma/unicorn, or similar for your app server, | ||||||
|  | that should be fine) we can assume that they're the same, which is pretty | ||||||
|  | common.</p> | ||||||
|  | 
 | ||||||
|  | <p>The example file generated will look something like this:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-ruby'>set :stage, :staging | ||||||
|  | 
 | ||||||
|  | # Simple Role Syntax | ||||||
|  | # ================== | ||||||
|  | # Supports bulk-adding hosts to roles, the primary | ||||||
|  | # server in each group is considered to be the first | ||||||
|  | # unless any hosts have the primary property set. | ||||||
|  | role :app, %w{example.com} | ||||||
|  | role :web, %w{example.com} | ||||||
|  | role :db,  %w{example.com} | ||||||
|  | 
 | ||||||
|  | # Extended Server Syntax | ||||||
|  | # ====================== | ||||||
|  | # This can be used to drop a more detailed server | ||||||
|  | # definition into the server list. The second argument | ||||||
|  | # something that quacks like a has can be used to set | ||||||
|  | # extended properties on the server. | ||||||
|  | server 'example.com', roles: %w{web app}, my_property: :my_value | ||||||
|  | 
 | ||||||
|  | # set :rails_env, :staging</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>Both the simple role, and extended server syntaxes result in one or more | ||||||
|  | servers for each role being defined. The <code>app</code> and <code>db</code> roles are just | ||||||
|  | placeholders, if you are using the <code>capistrano/rails-*</code> addons (more on | ||||||
|  | that later) then they have a meaning, but if you are deploying something | ||||||
|  | simpler, feel free to delete them if they're meaningless to you.</p> | ||||||
|  | 
 | ||||||
|  | <p>The extended server syntax exists to allow the definition of arbitrary server | ||||||
|  | properties; it's there incase people want to build the server list more | ||||||
|  | comprehensively from something like the <em>EC2</em> command line tools, and want to | ||||||
|  | use the extended properties for something that makes sense in their | ||||||
|  | environment.</p> | ||||||
|  | 
 | ||||||
|  | <p>Servers can be defined in a bunch of ways, the following shows defining two | ||||||
|  | servers, one where we set the username, and another where we set the port. | ||||||
|  | These host strings are parsed and expanded out in to the equivilent of the | ||||||
|  | server line after the comment:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-ruby'>role :all, %w{hello@world.com example.com:1234} | ||||||
|  | # ...is the same as doing... | ||||||
|  | server 'world.com' roles: [:web], user: 'hello' | ||||||
|  | server 'example.com', roles: [:web], port: 1234</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <h3 id="toc_4">5. Set the shared information in <code>deploy.rb</code>.</h3> | ||||||
|  | 
 | ||||||
|  | <p>The <code>deploy.rb</code> is a place where the configuration common to each environment | ||||||
|  | can be specified, normally the <em>repository URL</em> and the <em>user as whom to | ||||||
|  | deploy</em> are specified here.</p> | ||||||
|  | 
 | ||||||
|  | <p>The generated sample file starts with the following, and is followed by a few | ||||||
|  | self-documenting, commented-out configuration options, feel free to play with | ||||||
|  | them a little:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-ruby'>set :application, 'my app name' | ||||||
|  | set :repo, 'git@example.com:me/my_repo.git' | ||||||
|  | ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>Here we'd set the name of the application, ideally in a way that's safe for | ||||||
|  | filenames on your target operating system.</p> | ||||||
|  | 
 | ||||||
|  | <p>Second we set the repository URL, this <em>MUST</em> be somewhere that the server we | ||||||
|  | are deploying to can reach.</p> | ||||||
|  | 
 | ||||||
|  | <p>Here's how this might look in a typical example, note that we'll cover | ||||||
|  | authentication in the next chapter, for now we'll assume this repository is | ||||||
|  | open source, we'll take an example application from the <a href="http://railsapps.github.io/">Rails Examples and | ||||||
|  | Tutorials</a> site; there we'll find maintained a | ||||||
|  | handful of typical Rails apps with typical dependencies.</p> | ||||||
|  | 
 | ||||||
|  | <p>The Rails application they host, which uses Devise (for authentication) and | ||||||
|  | Cancan (for authorization) along side Twitter Bootstrap for assets has been | ||||||
|  | forked to the Capistrano repository, but you can find the (unchanged) original | ||||||
|  | <a href="https://github.com/RailsApps/rails3-bootstrap-devise-cancan">here</a>.</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-ruby'>set :application, 'rails3-bootstrap-devise-cancan-demo' | ||||||
|  | set :repo, 'https://github.com/capistrano/rails3-bootstrap-devise-cancan' | ||||||
|  | set :branch, 'master'</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>I've simplified the <code>:branch</code> varaible to simply be a <code>set</code> varaible, not a | ||||||
|  | question prompt, as this repository only has a master branch.</p> | ||||||
|  | 
 | ||||||
|  | <h2 id="toc_5">Roundup</h2> | ||||||
|  | 
 | ||||||
|  | <p><strong>At this point Capistrano knows where to find our servers, and where to find | ||||||
|  | our code.</strong></p> | ||||||
|  | 
 | ||||||
|  | <p>We've not covered how we authorise our servers to check out our code (there | ||||||
|  | are three pretty good ways of doing that with Git), nor have we determined how | ||||||
|  | to authorise Capistrano on our servers yet.</p> | ||||||
|  | 
 | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|  | @ -144,7 +293,7 @@ $ cap install</code></pre> | ||||||
|   here have parallels in Python, or PHP applications |   here have parallels in Python, or PHP applications | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <h2 id="toc_0">1. Commit your application to some externally available source control hosting provider.</h2> | <h3 id="toc_0">1. Commit your application to some externally available source control hosting provider.</h3> | ||||||
| 
 | 
 | ||||||
| <p>If you are not doing already, you should host your code somewhere with a | <p>If you are not doing already, you should host your code somewhere with a | ||||||
| provuder such as Github, BitBucket, Codeplane, or repositoryhosting.com.</p> | provuder such as Github, BitBucket, Codeplane, or repositoryhosting.com.</p> | ||||||
|  | @ -156,7 +305,7 @@ contribute if you know these tools well, we don't and don't want to force our | ||||||
| miscomprehended notions upon anyone. | miscomprehended notions upon anyone. | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <h2 id="toc_1">2. Move secrets out of the repository.</h2> | <h3 id="toc_1">2. Move secrets out of the repository.</h3> | ||||||
| 
 | 
 | ||||||
| <div class="alert-box alert"> | <div class="alert-box alert"> | ||||||
| If you've accidentally committed state secrets to the repository, you might | If you've accidentally committed state secrets to the repository, you might | ||||||
|  | @ -182,7 +331,7 @@ $ echo config/database.yml >> .gitignore</code></pre> | ||||||
| <p>This should be done for any other secret files, we'll create the production | <p>This should be done for any other secret files, we'll create the production | ||||||
| version of the file when we deploy, and symlink it into place.</p> | version of the file when we deploy, and symlink it into place.</p> | ||||||
| 
 | 
 | ||||||
| <h2 id="toc_2">3. Initialize Capistrano in your application.</h2> | <h3 id="toc_2">3. Initialize Capistrano in your application.</h3> | ||||||
| 
 | 
 | ||||||
| <div> | <div> | ||||||
|   <pre data-line=''><code class='language-bash'>$ cd my-project |   <pre data-line=''><code class='language-bash'>$ cd my-project | ||||||
|  | @ -202,6 +351,125 @@ $ cap install</code></pre> | ||||||
|     └── capistrano |     └── capistrano | ||||||
|             └── tasks</code></pre> |             └── tasks</code></pre> | ||||||
| </div> | </div> | ||||||
|  | 
 | ||||||
|  | <h3 id="toc_3">4. Configure your server addresses in the generated files.</h3> | ||||||
|  | 
 | ||||||
|  | <p>We'll just work with the staging environment here, so you can pretend that | ||||||
|  | <code>config/deploy/production.rb</code> doesn't exist, for the most part that's yoru | ||||||
|  | business.</p> | ||||||
|  | 
 | ||||||
|  | <p>Capistrano breaks down common tasks into a notion of <em>roles</em>, that is, taking | ||||||
|  | a typical Rails application that we have roughly speaking three roles, <code>web</code>, | ||||||
|  | <code>app</code>, and <code>db</code>.</p> | ||||||
|  | 
 | ||||||
|  | <p>It can be confusing, as the boundary of web and app servers is a bit blurry if | ||||||
|  | using <a href="">Passenger</a> with Apache, which in effect embeds your app server in the | ||||||
|  | web server (embeds Passenger in the Apache process itself), confusingly | ||||||
|  | Passenger can also be used in modes where this isn't true, so we'll ignore | ||||||
|  | that for the time being, and if you know the difference (i.e you are using | ||||||
|  | nginx as your web server, and puma/unicorn, or similar for your app server, | ||||||
|  | that should be fine) we can assume that they're the same, which is pretty | ||||||
|  | common.</p> | ||||||
|  | 
 | ||||||
|  | <p>The example file generated will look something like this:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-ruby'>set :stage, :staging | ||||||
|  | 
 | ||||||
|  | # Simple Role Syntax | ||||||
|  | # ================== | ||||||
|  | # Supports bulk-adding hosts to roles, the primary | ||||||
|  | # server in each group is considered to be the first | ||||||
|  | # unless any hosts have the primary property set. | ||||||
|  | role :app, %w{example.com} | ||||||
|  | role :web, %w{example.com} | ||||||
|  | role :db,  %w{example.com} | ||||||
|  | 
 | ||||||
|  | # Extended Server Syntax | ||||||
|  | # ====================== | ||||||
|  | # This can be used to drop a more detailed server | ||||||
|  | # definition into the server list. The second argument | ||||||
|  | # something that quacks like a has can be used to set | ||||||
|  | # extended properties on the server. | ||||||
|  | server 'example.com', roles: %w{web app}, my_property: :my_value | ||||||
|  | 
 | ||||||
|  | # set :rails_env, :staging</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>Both the simple role, and extended server syntaxes result in one or more | ||||||
|  | servers for each role being defined. The <code>app</code> and <code>db</code> roles are just | ||||||
|  | placeholders, if you are using the <code>capistrano/rails-*</code> addons (more on | ||||||
|  | that later) then they have a meaning, but if you are deploying something | ||||||
|  | simpler, feel free to delete them if they're meaningless to you.</p> | ||||||
|  | 
 | ||||||
|  | <p>The extended server syntax exists to allow the definition of arbitrary server | ||||||
|  | properties; it's there incase people want to build the server list more | ||||||
|  | comprehensively from something like the <em>EC2</em> command line tools, and want to | ||||||
|  | use the extended properties for something that makes sense in their | ||||||
|  | environment.</p> | ||||||
|  | 
 | ||||||
|  | <p>Servers can be defined in a bunch of ways, the following shows defining two | ||||||
|  | servers, one where we set the username, and another where we set the port. | ||||||
|  | These host strings are parsed and expanded out in to the equivilent of the | ||||||
|  | server line after the comment:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-ruby'>role :all, %w{hello@world.com example.com:1234} | ||||||
|  | # ...is the same as doing... | ||||||
|  | server 'world.com' roles: [:web], user: 'hello' | ||||||
|  | server 'example.com', roles: [:web], port: 1234</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <h3 id="toc_4">5. Set the shared information in <code>deploy.rb</code>.</h3> | ||||||
|  | 
 | ||||||
|  | <p>The <code>deploy.rb</code> is a place where the configuration common to each environment | ||||||
|  | can be specified, normally the <em>repository URL</em> and the <em>user as whom to | ||||||
|  | deploy</em> are specified here.</p> | ||||||
|  | 
 | ||||||
|  | <p>The generated sample file starts with the following, and is followed by a few | ||||||
|  | self-documenting, commented-out configuration options, feel free to play with | ||||||
|  | them a little:</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-ruby'>set :application, 'my app name' | ||||||
|  | set :repo, 'git@example.com:me/my_repo.git' | ||||||
|  | ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>Here we'd set the name of the application, ideally in a way that's safe for | ||||||
|  | filenames on your target operating system.</p> | ||||||
|  | 
 | ||||||
|  | <p>Second we set the repository URL, this <em>MUST</em> be somewhere that the server we | ||||||
|  | are deploying to can reach.</p> | ||||||
|  | 
 | ||||||
|  | <p>Here's how this might look in a typical example, note that we'll cover | ||||||
|  | authentication in the next chapter, for now we'll assume this repository is | ||||||
|  | open source, we'll take an example application from the <a href="http://railsapps.github.io/">Rails Examples and | ||||||
|  | Tutorials</a> site; there we'll find maintained a | ||||||
|  | handful of typical Rails apps with typical dependencies.</p> | ||||||
|  | 
 | ||||||
|  | <p>The Rails application they host, which uses Devise (for authentication) and | ||||||
|  | Cancan (for authorization) along side Twitter Bootstrap for assets has been | ||||||
|  | forked to the Capistrano repository, but you can find the (unchanged) original | ||||||
|  | <a href="https://github.com/RailsApps/rails3-bootstrap-devise-cancan">here</a>.</p> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <pre data-line=''><code class='language-ruby'>set :application, 'rails3-bootstrap-devise-cancan-demo' | ||||||
|  | set :repo, 'https://github.com/capistrano/rails3-bootstrap-devise-cancan' | ||||||
|  | set :branch, 'master'</code></pre> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <p>I've simplified the <code>:branch</code> varaible to simply be a <code>set</code> varaible, not a | ||||||
|  | question prompt, as this repository only has a master branch.</p> | ||||||
|  | 
 | ||||||
|  | <h2 id="toc_5">Roundup</h2> | ||||||
|  | 
 | ||||||
|  | <p><strong>At this point Capistrano knows where to find our servers, and where to find | ||||||
|  | our code.</strong></p> | ||||||
|  | 
 | ||||||
|  | <p>We've not covered how we authorise our servers to check out our code (there | ||||||
|  | are three pretty good ways of doing that with Git), nor have we determined how | ||||||
|  | to authorise Capistrano on our servers yet.</p> | ||||||
|                                            --> |                                            --> | ||||||
| 
 | 
 | ||||||
|     <!--</div> [> /container <]                                     --> |     <!--</div> [> /container <]                                     --> | ||||||
|  |  | ||||||
|  | @ -16,6 +16,36 @@ | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
| 
 | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       var _gauges = _gauges || []; | ||||||
|  |       (function() { | ||||||
|  |         var t   = document.createElement('script'); | ||||||
|  |         t.type  = 'text/javascript'; | ||||||
|  |         t.async = true; | ||||||
|  |         t.id    = 'gauges-tracker'; | ||||||
|  |         t.setAttribute('data-site-id', '51c83c32613f5d7df70000bc'); | ||||||
|  |         t.src = '//secure.gaug.es/track.js'; | ||||||
|  |         var s = document.getElementsByTagName('script')[0]; | ||||||
|  |         s.parentNode.insertBefore(t, s); | ||||||
|  |       })(); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       setTimeout(function(){var a=document.createElement("script"); | ||||||
|  |       var b=document.getElementsByTagName("script")[0]; | ||||||
|  |       a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0017/6418.js?"+Math.floor(new Date().getTime()/3600000); | ||||||
|  |       a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script> | ||||||
|  |       (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||||||
|  |       (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||||||
|  |       m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||||||
|  |       })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | ||||||
|  | 
 | ||||||
|  |       ga('create', 'UA-41970098-1', 'capistranorb.com'); | ||||||
|  |       ga('send', 'pageview'); | ||||||
|  |     </script> | ||||||
|     <div class="top-bar"> |     <div class="top-bar"> | ||||||
|   <a href="/" class="brand"> |   <a href="/" class="brand"> | ||||||
|     <img src="/images/CapistranoLogo.png" /> |     <img src="/images/CapistranoLogo.png" /> | ||||||
|  | @ -33,28 +63,28 @@ | ||||||
|   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> |   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Getting Started</h5> |   <h5>Getting Started</h5> | ||||||
|   <li><a href="/documentation/getting-started/installation/index.html">Installation</a></li> |   <li><a href="/documentation/getting-started/installation/">Installation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/preparing-your-application/index.html">Preparing Your Application</a></li> |   <li><a href="/documentation/getting-started/preparing-your-application/">Preparing Your Application</a></li> | ||||||
|   <li><aj href="/documentation/getting-started/authentication-and-authorisation/index.html">Authentication & Authorisation</a></li> |   <li><a href="/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/cold-start/index.html">Cold Start</a></li> |   <li><a href="/documentation/getting-started/cold-start/">Cold Start</a></li> | ||||||
|   <li><a href="/documentation/getting-started/rollbacks/index.html">Rollbacks</a></li> |   <li><a href="/documentation/getting-started/rollbacks/">Rollbacks</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Troubleshooting</h5> |   <h5>Troubleshooting</h5> | ||||||
|   <li><a href="/documentation/troubleshooting/authentication/index.html">SCM (Git) Authentication</a></li> |   <li><a href="/documentation/troubleshooting/authentication/">SCM (Git) Authentication</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/connectivity/index.html">Connectivity</a></li> |   <li><a href="/documentation/troubleshooting/connectivity/">Connectivity</a></li> | ||||||
|   <!--<li><a href="/documentation/troubleshooting/gateway-servers/index.html">Gateway Servers</a></li>--> |   <!--<li><a href="/documentation/troubleshooting/gateway-servers/">Gateway Servers</a></li>--> | ||||||
|   <li><a href="/documentation/troubleshooting/agent-forwarding/index.html">Agent Forwarding</a></li> |   <li><a href="/documentation/troubleshooting/agent-forwarding/">Agent Forwarding</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/sudo-password/index.html">`sudo` Password</a></li> |   <li><a href="/documentation/troubleshooting/sudo-password/">`sudo` Password</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/index.html">RVM, `rbenv` And `nvm`</a></li> |   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/">RVM, `rbenv` And `nvm`</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>FAQ</h5> |   <h5>FAQ</h5> | ||||||
|   <li><a |   <li><a | ||||||
|     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/index.html">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> |     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> | ||||||
|   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/index.html">Should I Use Capistrano To Provision My Servers?</a></li> |   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/">Should I Use Capistrano To Provision My Servers?</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Power Use-Cases</h5> |   <h5>Power Use-Cases</h5> | ||||||
|   <li><a href="/documentation/power-use-cases/integration-with-rake/index.html">Integration With Rake</a></li> |   <li><a href="/documentation/power-use-cases/integration-with-rake/">Integration With Rake</a></li> | ||||||
|   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/index.html">Driving Tools Such As <em>Chef Solo</em></a></li> |   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/">Driving Tools Such As <em>Chef Solo</em></a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Recent Announcements</h5> |   <h5>Recent Announcements</h5> | ||||||
|    |    | ||||||
|  | @ -73,7 +103,7 @@ without much previous setup.</p> | ||||||
| unprepared server, covering all aspects of Github access, as well as | unprepared server, covering all aspects of Github access, as well as | ||||||
| privisioning the server using <em>Chef Solo</em> and Capistrano with <em>Rake</em>.</p> | privisioning the server using <em>Chef Solo</em> and Capistrano with <em>Rake</em>.</p> | ||||||
| 
 | 
 | ||||||
| <h4 id="toc_0"> Show Notes</h4> | <h4 id="toc_0">Show Notes</h4> | ||||||
| 
 | 
 | ||||||
| <p>The <em>Chef Solo</em> recipes can be reached at [this repository at | <p>The <em>Chef Solo</em> recipes can be reached at [this repository at | ||||||
| Github][capistrano-chef-solo-example-recipes], they rely on a fairly new | Github][capistrano-chef-solo-example-recipes], they rely on a fairly new | ||||||
|  | @ -112,7 +142,7 @@ without much previous setup.</p> | ||||||
| unprepared server, covering all aspects of Github access, as well as | unprepared server, covering all aspects of Github access, as well as | ||||||
| privisioning the server using <em>Chef Solo</em> and Capistrano with <em>Rake</em>.</p> | privisioning the server using <em>Chef Solo</em> and Capistrano with <em>Rake</em>.</p> | ||||||
| 
 | 
 | ||||||
| <h4 id="toc_0"> Show Notes</h4> | <h4 id="toc_0">Show Notes</h4> | ||||||
| 
 | 
 | ||||||
| <p>The <em>Chef Solo</em> recipes can be reached at [this repository at | <p>The <em>Chef Solo</em> recipes can be reached at [this repository at | ||||||
| Github][capistrano-chef-solo-example-recipes], they rely on a fairly new | Github][capistrano-chef-solo-example-recipes], they rely on a fairly new | ||||||
|  |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								_site/images/github-personal-api-token-page.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								_site/images/github-personal-api-token-page.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 23 KiB | 
|  | @ -16,6 +16,36 @@ | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
| 
 | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       var _gauges = _gauges || []; | ||||||
|  |       (function() { | ||||||
|  |         var t   = document.createElement('script'); | ||||||
|  |         t.type  = 'text/javascript'; | ||||||
|  |         t.async = true; | ||||||
|  |         t.id    = 'gauges-tracker'; | ||||||
|  |         t.setAttribute('data-site-id', '51c83c32613f5d7df70000bc'); | ||||||
|  |         t.src = '//secure.gaug.es/track.js'; | ||||||
|  |         var s = document.getElementsByTagName('script')[0]; | ||||||
|  |         s.parentNode.insertBefore(t, s); | ||||||
|  |       })(); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       setTimeout(function(){var a=document.createElement("script"); | ||||||
|  |       var b=document.getElementsByTagName("script")[0]; | ||||||
|  |       a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0017/6418.js?"+Math.floor(new Date().getTime()/3600000); | ||||||
|  |       a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script> | ||||||
|  |       (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||||||
|  |       (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||||||
|  |       m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||||||
|  |       })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | ||||||
|  | 
 | ||||||
|  |       ga('create', 'UA-41970098-1', 'capistranorb.com'); | ||||||
|  |       ga('send', 'pageview'); | ||||||
|  |     </script> | ||||||
|     <div class="top-bar"> |     <div class="top-bar"> | ||||||
|   <a href="/" class="brand"> |   <a href="/" class="brand"> | ||||||
|     <img src="/images/CapistranoLogo.png" /> |     <img src="/images/CapistranoLogo.png" /> | ||||||
|  | @ -33,28 +63,28 @@ | ||||||
|   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> |   <li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Getting Started</h5> |   <h5>Getting Started</h5> | ||||||
|   <li><a href="/documentation/getting-started/installation/index.html">Installation</a></li> |   <li><a href="/documentation/getting-started/installation/">Installation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/preparing-your-application/index.html">Preparing Your Application</a></li> |   <li><a href="/documentation/getting-started/preparing-your-application/">Preparing Your Application</a></li> | ||||||
|   <li><aj href="/documentation/getting-started/authentication-and-authorisation/index.html">Authentication & Authorisation</a></li> |   <li><a href="/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a></li> | ||||||
|   <li><a href="/documentation/getting-started/cold-start/index.html">Cold Start</a></li> |   <li><a href="/documentation/getting-started/cold-start/">Cold Start</a></li> | ||||||
|   <li><a href="/documentation/getting-started/rollbacks/index.html">Rollbacks</a></li> |   <li><a href="/documentation/getting-started/rollbacks/">Rollbacks</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Troubleshooting</h5> |   <h5>Troubleshooting</h5> | ||||||
|   <li><a href="/documentation/troubleshooting/authentication/index.html">SCM (Git) Authentication</a></li> |   <li><a href="/documentation/troubleshooting/authentication/">SCM (Git) Authentication</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/connectivity/index.html">Connectivity</a></li> |   <li><a href="/documentation/troubleshooting/connectivity/">Connectivity</a></li> | ||||||
|   <!--<li><a href="/documentation/troubleshooting/gateway-servers/index.html">Gateway Servers</a></li>--> |   <!--<li><a href="/documentation/troubleshooting/gateway-servers/">Gateway Servers</a></li>--> | ||||||
|   <li><a href="/documentation/troubleshooting/agent-forwarding/index.html">Agent Forwarding</a></li> |   <li><a href="/documentation/troubleshooting/agent-forwarding/">Agent Forwarding</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/sudo-password/index.html">`sudo` Password</a></li> |   <li><a href="/documentation/troubleshooting/sudo-password/">`sudo` Password</a></li> | ||||||
|   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/index.html">RVM, `rbenv` And `nvm`</a></li> |   <li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/">RVM, `rbenv` And `nvm`</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>FAQ</h5> |   <h5>FAQ</h5> | ||||||
|   <li><a |   <li><a | ||||||
|     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/index.html">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> |     href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/">Why Does Something Work In An SSH Session, But Not In Capistrano?</a></li> | ||||||
|   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/index.html">Should I Use Capistrano To Provision My Servers?</a></li> |   <li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/">Should I Use Capistrano To Provision My Servers?</a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Power Use-Cases</h5> |   <h5>Power Use-Cases</h5> | ||||||
|   <li><a href="/documentation/power-use-cases/integration-with-rake/index.html">Integration With Rake</a></li> |   <li><a href="/documentation/power-use-cases/integration-with-rake/">Integration With Rake</a></li> | ||||||
|   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/index.html">Driving Tools Such As <em>Chef Solo</em></a></li> |   <li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/">Driving Tools Such As <em>Chef Solo</em></a></li> | ||||||
|   <li class="divider"></li> |   <li class="divider"></li> | ||||||
|   <h5>Recent Announcements</h5> |   <h5>Recent Announcements</h5> | ||||||
|    |    | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ body { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| h1, h2, h3, h4, h5, h6 { | h1, h2, h3, h4, h5, h6 { | ||||||
|  |   font-weight: 400; | ||||||
|   font-family: 'Enriqueta', serif; |   font-family: 'Enriqueta', serif; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,314 @@ | ||||||
|  | --- | ||||||
|  | title: Authentication & Authorisation | ||||||
|  | layout: default | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | **Note:** In the documentation we simply recommend creating a single deployment user, | ||||||
|  | and sharing it between team members. If you know why this is a bad idea (or | ||||||
|  | why this may be against regulations in your jurisdiction in some cases, we | ||||||
|  | assume that you know well enough how to use groups, umasking and setgid bits | ||||||
|  | to make this work reliably for unique logins across team members) | ||||||
|  | 
 | ||||||
|  | To create this deploy user we'll assume something like the following has been | ||||||
|  | done: | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     root@remote $ adduser deploy | ||||||
|  |     root@remote $ passwd -l deploy | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | The first line creates a completely standard user, it has a home directory, | ||||||
|  | which we'll need in a moment, and has a shell, so it may log in. This needs to | ||||||
|  | be done **on every server in your environment**. | ||||||
|  | 
 | ||||||
|  | The second line *locks* the user, it changes the user's password to an | ||||||
|  | untypable string, guaranteeing that the user has no password which can be used | ||||||
|  | to log in. | ||||||
|  | 
 | ||||||
|  | ### Authentication | ||||||
|  | 
 | ||||||
|  | There are two places that we need automated, promptless authentication: | ||||||
|  | 
 | ||||||
|  |   1. **From our workstation/notebook/etc to our servers.** We do this with **SSH | ||||||
|  |      keys**, passphrase protected, ideally, using a **key agent**. | ||||||
|  |   2. **From our servers to the repository host**. We do this so that our servers | ||||||
|  |      can check out our application code from Github, or similar and install it | ||||||
|  |      to the servers. This is usually done using **SSH agent forwarding**, HTTP | ||||||
|  |      authentication, or with deploy keys. | ||||||
|  | 
 | ||||||
|  | #### 1.1 SSH keys from workstation to servers | ||||||
|  | 
 | ||||||
|  | **Note:** If you are on Windows, all bets are off, I'd love it if someone | ||||||
|  | could contribute a Windows guide to this, so we can include it here. | ||||||
|  | 
 | ||||||
|  | An SSH key is a mechanism that allows a *public* half one key to be placed on | ||||||
|  | a server, when we want to authenticate with that server, our SSH client uses | ||||||
|  | the **private** part of that key to negotiate with the server, if the keys are | ||||||
|  | correct, then we need to create the key. | ||||||
|  | 
 | ||||||
|  | **Hint:** If you have more than one developer in your team, they should all add their | ||||||
|  | public key to the `deploy` user's `authorized_keys` file, that way if someone | ||||||
|  | quits or gets fired, you can remove their key from that file, and the rest of | ||||||
|  | you can keep on shipping! | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     me@localhost $ ssh-keygen -t rsa -C 'me@my_email_address.com' | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | You'll be prompted for a passphrase, that's fine. Type one and keep it safe. | ||||||
|  | This passphrase ensures that if your computer is stolen, people still need a | ||||||
|  | passphrase to access your keys, in order to access your servers. | ||||||
|  | 
 | ||||||
|  | To avoid having to type this passphrase every time you need to use a key, most | ||||||
|  | operating systems have a concept of a *key agent*. This *key agent* stores SSH | ||||||
|  | keys securely between uses, typically the first time a key is needed in a | ||||||
|  | given time period, the SSH agent will load the key, prompt you for your | ||||||
|  | passphrase and then the key agent will remember the key for a certain amount | ||||||
|  | of time (on OSX it tends to be indefinite, on linux this can vary from 15 | ||||||
|  | minutes updwards.) | ||||||
|  | 
 | ||||||
|  | We can see which keys are loaded in the SSH agent by running `ssh-add -l` | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     me@localhost $ ssh-add -l | ||||||
|  |     2048 af:ce:7e:c5:93:18:39:ff:54:20:7a:2d:ec:05:7c:a5 /Users/me/.ssh/id_rsa (RSA) | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | If you don't see any keys listed, you can simply run `ssh-add`: | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     me@localhsot $ ssh-add | ||||||
|  |     Identity added: /Users/me/.ssh/id_rsa (/Users/me/.ssh/id_rsa) | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | Typically, ssh-add will ask you for the passphrase when you add a key. | ||||||
|  | 
 | ||||||
|  | **Note:** Although it's not mandatory to use an SSH agent (one could simply | ||||||
|  | use an unpassphrased key, and rely on SSH to find the key and exchange it). | ||||||
|  | Using an SSH agent makes things more secure, because we can use a passphrased | ||||||
|  | key without being prompts every time it is used. It **also** allows us to use | ||||||
|  | this same key to access the repository *via* the server without creating an | ||||||
|  | additional identity. | ||||||
|  | 
 | ||||||
|  | At this point with the key loaded into the agent, we need to put the | ||||||
|  | **public** part of the key into a file on each remote server called | ||||||
|  | `/home/users/deploy/.ssh/authorized_keys`, to get the contents of that file, | ||||||
|  | we can ask our local key agent for the public parts of the keys it has loaded: | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     me@localhost $ ssh-add -L | ||||||
|  |     ssh-rsa jccXJ/JRfGxnkh/8iL........dbfCH/9cDiKa0Dw8XGAo01mU/w== /Users/me/.ssh/id_rsa | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | This will be a lot longer when you run it, I snipped the output because it | ||||||
|  | looked bad. | ||||||
|  | 
 | ||||||
|  | This line, as one line, needs to make it to the remote server and be added *to | ||||||
|  | it's own line* of the `deploy` user's `~/.ssh/authorized_keys` file. This file | ||||||
|  | then needs to be changed to permission mode `0600` (owner read/write, group | ||||||
|  | none, other none), in the `~/.ssh` directory which needs the permissions | ||||||
|  | `0700` (owner read/write/execute, group none, other none). | ||||||
|  | 
 | ||||||
|  | If you are on linux there often exists a command | ||||||
|  | [`ssh-copy-id`](http://linux.die.net/man/1/ssh-copy-id) which streamlines this | ||||||
|  | process, otherwise the worlflow is something like: | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     me@localhost $ ssh root@remote | ||||||
|  |     root@remote $ su - deploy | ||||||
|  |     deploy@remote $ cd ~ | ||||||
|  |     deploy@remote $ mkdir .ssh | ||||||
|  |     deploy@remote $ echo "ssh-rsa jccXJ/JRfGxnkh/8iL........dbfCH/9cDiKa0Dw8XGAo01mU/w== /Users/me/.ssh/id_rsa" >> .ssh/authorized_keys | ||||||
|  |     deploy@remote $ chmod 700 .ssh | ||||||
|  |     deploy@remote $ chmod 600 .ssh/authorized_keys | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | **Remember:** This needs to be done on every server you want to use, you can | ||||||
|  | use the same key for each one, but only one key per developer is recommended. | ||||||
|  | *Private* keys are named as such for a reason! | ||||||
|  | 
 | ||||||
|  | If we did all that correctly, we should now be able to do something like this: | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     me@localhost $ ssh deploy@one-of-my-servers.com 'hostname; uptime' | ||||||
|  |     one-of-my-servers.com | ||||||
|  |     19:23:32 up 62 days, 44 min, 1 user, load average: 0.00, 0.01, 0.05 | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | That should happen without having to enter a passphrase for your SSH key, or | ||||||
|  | promoting you for an SSH password (which the deploy user doesn't have anyway). | ||||||
|  | 
 | ||||||
|  | Verify that this works for all of your servers, and put your private key | ||||||
|  | somewhere safe. If you're working with multiple team members, it often pays to | ||||||
|  | collect everyone's public keys, indeed if your team is already using SSH keys | ||||||
|  | to access Github, you can reach any user's SSH keys at the following URL: | ||||||
|  | 
 | ||||||
|  |  * `https://github.com/theirusername.keys` | ||||||
|  | 
 | ||||||
|  | This can make getting user's keys onto servers much easier, as you can simply | ||||||
|  | `curl`/`wget` each user's key into the authorized keys file on the server | ||||||
|  | directly from Github. | ||||||
|  | 
 | ||||||
|  | <blockquote class="twitter-tweet"><p>TIL <a | ||||||
|  | href="https://twitter.com/github">@github</a> exposes the ssh public keys for | ||||||
|  | users. <a href="https://t.co/Wo9g8nxI">https://t.co/Wo9g8nxI</a> Handy for | ||||||
|  | adding devs to servers/repos.</p>— Postmodern (@postmodern_mod3) <a | ||||||
|  | href="https://twitter.com/postmodern_mod3/statuses/300438256200339456">February | ||||||
|  | 10, 2013</a></blockquote> | ||||||
|  | <script async src="//platform.twitter.com/widgets.js" | ||||||
|  | charset="utf-8"></script> | ||||||
|  | 
 | ||||||
|  | #### 1.2 From our servers to the repository host | ||||||
|  | 
 | ||||||
|  | With access from workstations to the servers settled, there is another hop to | ||||||
|  | contend with, which is letting the deploy user get access to the code | ||||||
|  | repository automatically. The options in order of preference: | ||||||
|  | 
 | ||||||
|  | ##### 1.2.1 SSH Agent Forwarding | ||||||
|  | 
 | ||||||
|  | As we've already set up an SSH agent, we can use the *agent forwarding* | ||||||
|  | feature of SSH to make this key agent available to further *hops*. In short, | ||||||
|  | we can use **our own ssh key** to authenticate ourselves from the server, to | ||||||
|  | Github. | ||||||
|  | 
 | ||||||
|  | Here's how we can check if that works, first get the URL of the repository: | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     me@localhost $ git config remote.origin.url | ||||||
|  |     git@github.com:capistrano/rails3-bootstrap-devise-cancan.git | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | Here we're listing our private (for testing purposes) fork of the | ||||||
|  | rails3-bootstrap-devise-cancan repository forked from the Rails Examples and | ||||||
|  | Tutorials project. | ||||||
|  | 
 | ||||||
|  | We can try to access the repository via our server by doing the following: | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     # List SSH keys that are loaded into the agent | ||||||
|  |     me@localhost $ ssh-add -l | ||||||
|  |     # Make sure they key is loaded if 'ssh-add -l' didn't show anything | ||||||
|  |     me@localhost $ ssh-add | ||||||
|  |     me@localhost $ ssh -A deploy@one-of-my-servers.com 'git ls-remote git@github.com:capistrano/rails3-bootstrap-devise-cancan.git | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | We first check that the agent has the keys loaded, if not we simply load it, | ||||||
|  | and enter the passphrase when prompted. | ||||||
|  | 
 | ||||||
|  | Finally we use `ls-remote` from Git to list the remote objects, this is the | ||||||
|  | exact same check that Capistrano does internally before attempting to deploy. | ||||||
|  | The `-A` option may, or may not be required on your system, it's worth trying | ||||||
|  | it both ways just to know how your system treats agent forwarding by default. | ||||||
|  | 
 | ||||||
|  | From the SSH documentation: | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |      -A  Enables forwarding of the authentication agent connection.  This can also be | ||||||
|  |          specified on a per-host basis in a configuration file. | ||||||
|  | 
 | ||||||
|  |          Agent forwarding should be enabled with caution.  Users with the ability to | ||||||
|  |          bypass file permissions on the remote host (for the agent's UNIX-domain | ||||||
|  |          socket) can access the local agent through the forwarded connection.  An | ||||||
|  |          attacker cannot obtain key material from the agent, however they can perform | ||||||
|  |          operations on the keys that enable them to authenticate using the identities | ||||||
|  |          loaded into the agent. | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | In laymans terms, you should't use SSH agent forwarding to machines where you | ||||||
|  | don't trust the administrators, as they can can override the permissions on | ||||||
|  | the system and use your keys as if they were you. That said, if you can't | ||||||
|  | trust your server administrators, perhaps they shouldn't have access to your | ||||||
|  | servers! | ||||||
|  | 
 | ||||||
|  | ##### 1.2.2 HTTP Authentication | ||||||
|  | 
 | ||||||
|  | In the case of HTTP authentication **be sure to use HTTPS**, otherwise your | ||||||
|  | password will be sent in cleartext over the network, depending what your hosts | ||||||
|  | network infratructure looks like that might be *very* bad news. | ||||||
|  | 
 | ||||||
|  | Typically when we try and list our remote objects, using the https method from | ||||||
|  | Github, we'll be prompted for a username and password: | ||||||
|  | 
 | ||||||
|  | ##### 1.2.2.1 With a regular username/password | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     me@localhost $ git ls-remote https://github.com/capistrano/rails3-bootstrap-devise-cancan.git | ||||||
|  |     Username for 'https://github.com': myownusername | ||||||
|  |     Password for 'https://capistrano@github.com': | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | This challenge response prompt doesn't work well for automating things, so | ||||||
|  | there are two ways to get around this depending on your server's host | ||||||
|  | operating system, the first is to use a `netrc` file, we won't talk about that | ||||||
|  | because the netrc is a global file that doesn't lend itself well to security. | ||||||
|  | 
 | ||||||
|  | The other mechanism, and the reason that its **very** important to always use | ||||||
|  | HTTPS not plain ol' HTTP is to embed the username and password in the URL, | ||||||
|  | note this won't work well if your password has special characters: | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     me@localhost $ git ls-remote https://capistrano:ourverysecretpassword@github.com/capistrano/rails3-bootstrap-devise-cancan.git | ||||||
|  |     3419812c9f146d9a84b44bcc2c3caef94da54758HEAD | ||||||
|  |     3419812c9f146d9a84b44bcc2c3caef94da54758HEADrefs/heads/master | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | The bigger problem with passwords, whether inlined into the URL, or entered | ||||||
|  | into a `netrc` file, is that the password gives access to **your entire Github | ||||||
|  | Account** not just to one single repository. | ||||||
|  | 
 | ||||||
|  | ##### 1.2.2.2 With an OAuth Personal API Token | ||||||
|  | 
 | ||||||
|  | This mechanism still gives access to **every repository** you can access, but | ||||||
|  | at Github, they recently rolled out a feature called [Personal API | ||||||
|  | Tokens](https://github.com/blog/1509-personal-api-tokens) which allow you to | ||||||
|  | do something like this: | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  |     me@localhost $ git ls-remote https://.....................@github.com/capistrano/rails3-bootstrap-devise-cancan.git | ||||||
|  |     3419812c9f146d9a84b44bcc2c3caef94da54758HEAD | ||||||
|  |     3419812c9f146d9a84b44bcc2c3caef94da54758HEADrefs/heads/master | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | Where `....` is a personal API token, as such: | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ##### 1.2.3 Deploy Keys | ||||||
|  | 
 | ||||||
|  | Deploy keys, a feature of Github, and some other platforms allow you to | ||||||
|  | generate a **second** set of SSH keys for the connection between Github and | ||||||
|  | the servers themselves. | ||||||
|  | 
 | ||||||
|  | Slightly perversely in this case the public key is uploaded to the repository | ||||||
|  | host, and the private key must be copied to each server that you want to | ||||||
|  | deploy to. | ||||||
|  | 
 | ||||||
|  | Github has a quite excellent guide on this, much of which (unsurprisingly) | ||||||
|  | overlaps with the SSH key instructions above. | ||||||
|  | 
 | ||||||
|  |  * [Github Help: Managing Deploy Keys](https://help.github.com/articles/managing-deploy-keys) | ||||||
|  | 
 | ||||||
|  | ### Authorisation | ||||||
|  | 
 | ||||||
|  | The second part of this topic is that our deploy user needs to be authorised | ||||||
|  | to work in the deployment directory, on the server. That means we need to be | ||||||
|  | able to work, ideally without `sudo` (none of the default Capistrano recipes | ||||||
|  | expect `sudo` to be available), or for your custom recipes, you will need to | ||||||
|  | have configured *passwordless* `sudo`. Configuring `sudo` to give some users | ||||||
|  | access to come commands under some circumstances is beyond the scope of this | ||||||
|  | documentation, but sufficed to say something like: | ||||||
|  | 
 | ||||||
|  | {% prism bash %} | ||||||
|  | deploy ALL=NOPASSWD:/etc/init.d/mysqld, /etc/init.d/apache2 | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | This example would give the user named `deploy` access to call `sudo | ||||||
|  | /etc/init.d/mysql _________` and the same for the `apache2` control script. | ||||||
|  | 
 | ||||||
|  | **Granting passwordless sudo should not be done lightly.** It can be dangerous. | ||||||
|  | For example if an unprivilidged user can *edit* the script that they can run | ||||||
|  | as root, they can easily edit it to do anything they want that is evil. Use | ||||||
|  | this carefully, and ideally architect your systems so that non-privlidged | ||||||
|  | users can restart services, or that services restart *themselves* when they | ||||||
|  | notice change. | ||||||
|  | 
 | ||||||
|  | @ -8,7 +8,7 @@ layout: default | ||||||
|   here have parallels in Python, or PHP applications |   here have parallels in Python, or PHP applications | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| ## 1. Commit your application to some externally available source control hosting provider. | ### 1. Commit your application to some externally available source control hosting provider. | ||||||
| 
 | 
 | ||||||
| If you are not doing already, you should host your code somewhere with a | If you are not doing already, you should host your code somewhere with a | ||||||
| provuder such as Github, BitBucket, Codeplane, or repositoryhosting.com. | provuder such as Github, BitBucket, Codeplane, or repositoryhosting.com. | ||||||
|  | @ -20,7 +20,7 @@ contribute if you know these tools well, we don't and don't want to force our | ||||||
| miscomprehended notions upon anyone. | miscomprehended notions upon anyone. | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| ## 2. Move secrets out of the repository. | ### 2. Move secrets out of the repository. | ||||||
| 
 | 
 | ||||||
| <div class="alert-box alert"> | <div class="alert-box alert"> | ||||||
| If you've accidentally committed state secrets to the repository, you might | If you've accidentally committed state secrets to the repository, you might | ||||||
|  | @ -46,7 +46,7 @@ parallel concept of ignored files) | ||||||
| This should be done for any other secret files, we'll create the production | This should be done for any other secret files, we'll create the production | ||||||
| version of the file when we deploy, and symlink it into place. | version of the file when we deploy, and symlink it into place. | ||||||
| 
 | 
 | ||||||
| ## 3. Initialize Capistrano in your application. | ### 3. Initialize Capistrano in your application. | ||||||
| 
 | 
 | ||||||
| {% prism bash %} | {% prism bash %} | ||||||
|     $ cd my-project |     $ cd my-project | ||||||
|  | @ -66,3 +66,122 @@ This will create a bunch of files, the important ones are: | ||||||
|       └── capistrano |       └── capistrano | ||||||
|               └── tasks |               └── tasks | ||||||
| {% endprism %} | {% endprism %} | ||||||
|  | 
 | ||||||
|  | ### 4. Configure your server addresses in the generated files. | ||||||
|  | 
 | ||||||
|  | We'll just work with the staging environment here, so you can pretend that | ||||||
|  | `config/deploy/production.rb` doesn't exist, for the most part that's yoru | ||||||
|  | business. | ||||||
|  | 
 | ||||||
|  | Capistrano breaks down common tasks into a notion of *roles*, that is, taking | ||||||
|  | a typical Rails application that we have roughly speaking three roles, `web`, | ||||||
|  | `app`, and `db`. | ||||||
|  | 
 | ||||||
|  | It can be confusing, as the boundary of web and app servers is a bit blurry if | ||||||
|  | using [Passenger]() with Apache, which in effect embeds your app server in the | ||||||
|  | web server (embeds Passenger in the Apache process itself), confusingly | ||||||
|  | Passenger can also be used in modes where this isn't true, so we'll ignore | ||||||
|  | that for the time being, and if you know the difference (i.e you are using | ||||||
|  | nginx as your web server, and puma/unicorn, or similar for your app server, | ||||||
|  | that should be fine) we can assume that they're the same, which is pretty | ||||||
|  | common. | ||||||
|  | 
 | ||||||
|  | The example file generated will look something like this: | ||||||
|  | 
 | ||||||
|  | {% prism ruby %} | ||||||
|  |     set :stage, :staging | ||||||
|  | 
 | ||||||
|  |     # Simple Role Syntax | ||||||
|  |     # ================== | ||||||
|  |     # Supports bulk-adding hosts to roles, the primary | ||||||
|  |     # server in each group is considered to be the first | ||||||
|  |     # unless any hosts have the primary property set. | ||||||
|  |     role :app, %w{example.com} | ||||||
|  |     role :web, %w{example.com} | ||||||
|  |     role :db,  %w{example.com} | ||||||
|  | 
 | ||||||
|  |     # Extended Server Syntax | ||||||
|  |     # ====================== | ||||||
|  |     # This can be used to drop a more detailed server | ||||||
|  |     # definition into the server list. The second argument | ||||||
|  |     # something that quacks like a has can be used to set | ||||||
|  |     # extended properties on the server. | ||||||
|  |     server 'example.com', roles: %w{web app}, my_property: :my_value | ||||||
|  | 
 | ||||||
|  |     # set :rails_env, :staging | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | Both the simple role, and extended server syntaxes result in one or more | ||||||
|  | servers for each role being defined. The `app` and `db` roles are just | ||||||
|  | placeholders, if you are using the `capistrano/rails-*` addons (more on | ||||||
|  | that later) then they have a meaning, but if you are deploying something | ||||||
|  | simpler, feel free to delete them if they're meaningless to you. | ||||||
|  | 
 | ||||||
|  | The extended server syntax exists to allow the definition of arbitrary server | ||||||
|  | properties; it's there incase people want to build the server list more | ||||||
|  | comprehensively from something like the *EC2* command line tools, and want to | ||||||
|  | use the extended properties for something that makes sense in their | ||||||
|  | environment. | ||||||
|  | 
 | ||||||
|  | Servers can be defined in a bunch of ways, the following shows defining two | ||||||
|  | servers, one where we set the username, and another where we set the port. | ||||||
|  | These host strings are parsed and expanded out in to the equivilent of the | ||||||
|  | server line after the comment: | ||||||
|  | 
 | ||||||
|  | {% prism ruby %} | ||||||
|  |   role :all, %w{hello@world.com example.com:1234} | ||||||
|  |   # ...is the same as doing... | ||||||
|  |   server 'world.com' roles: [:web], user: 'hello' | ||||||
|  |   server 'example.com', roles: [:web], port: 1234 | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | ### 5. Set the shared information in `deploy.rb`. | ||||||
|  | 
 | ||||||
|  | The `deploy.rb` is a place where the configuration common to each environment | ||||||
|  | can be specified, normally the *repository URL* and the *user as whom to | ||||||
|  | deploy* are specified here. | ||||||
|  | 
 | ||||||
|  | The generated sample file starts with the following, and is followed by a few | ||||||
|  | self-documenting, commented-out configuration options, feel free to play with | ||||||
|  | them a little: | ||||||
|  | 
 | ||||||
|  | {% prism ruby %} | ||||||
|  |     set :application, 'my app name' | ||||||
|  |     set :repo, 'git@example.com:me/my_repo.git' | ||||||
|  |     ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp } | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | Here we'd set the name of the application, ideally in a way that's safe for | ||||||
|  | filenames on your target operating system. | ||||||
|  | 
 | ||||||
|  | Second we set the repository URL, this *MUST* be somewhere that the server we | ||||||
|  | are deploying to can reach. | ||||||
|  | 
 | ||||||
|  | Here's how this might look in a typical example, note that we'll cover | ||||||
|  | authentication in the next chapter, for now we'll assume this repository is | ||||||
|  | open source, we'll take an example application from the [Rails Examples and | ||||||
|  | Tutorials](http://railsapps.github.io/) site; there we'll find maintained a | ||||||
|  | handful of typical Rails apps with typical dependencies. | ||||||
|  | 
 | ||||||
|  | The Rails application they host, which uses Devise (for authentication) and | ||||||
|  | Cancan (for authorization) along side Twitter Bootstrap for assets has been | ||||||
|  | forked to the Capistrano repository, but you can find the (unchanged) original | ||||||
|  | [here](https://github.com/RailsApps/rails3-bootstrap-devise-cancan). | ||||||
|  | 
 | ||||||
|  | {% prism ruby %} | ||||||
|  |     set :application, 'rails3-bootstrap-devise-cancan-demo' | ||||||
|  |     set :repo, 'https://github.com/capistrano/rails3-bootstrap-devise-cancan' | ||||||
|  |     set :branch, 'master' | ||||||
|  | {% endprism %} | ||||||
|  | 
 | ||||||
|  | I've simplified the `:branch` varaible to simply be a `set` varaible, not a | ||||||
|  | question prompt, as this repository only has a master branch. | ||||||
|  | 
 | ||||||
|  | ## Roundup | ||||||
|  | 
 | ||||||
|  | **At this point Capistrano knows where to find our servers, and where to find | ||||||
|  | our code.** | ||||||
|  | 
 | ||||||
|  | We've not covered how we authorise our servers to check out our code (there | ||||||
|  | are three pretty good ways of doing that with Git), nor have we determined how | ||||||
|  | to authorise Capistrano on our servers yet. | ||||||
|  |  | ||||||
|  | @ -10,9 +10,7 @@ It covers using Capistrano to install an example Rails project on a previously | ||||||
| unprepared server, covering all aspects of Github access, as well as | unprepared server, covering all aspects of Github access, as well as | ||||||
| privisioning the server using *Chef Solo* and Capistrano with *Rake*. | privisioning the server using *Chef Solo* and Capistrano with *Rake*. | ||||||
| 
 | 
 | ||||||
| 
 | #### Show Notes | ||||||
| 
 |  | ||||||
| #### Show Notes |  | ||||||
| 
 | 
 | ||||||
| The *Chef Solo* recipes can be reached at [this repository at | The *Chef Solo* recipes can be reached at [this repository at | ||||||
| Github][capistrano-chef-solo-example-recipes], they rely on a fairly new | Github][capistrano-chef-solo-example-recipes], they rely on a fairly new | ||||||
|  |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								images/github-personal-api-token-page.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								images/github-personal-api-token-page.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 23 KiB | 
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lee Hambley
						Lee Hambley