public
Last active — forked from aronwoost/README.md

Deploy your site with git

  • Download Gist
README.md
Markdown

Deploy your site with git

This gist assumes:

  • you have a local git repo
  • with an online remote repository (github / bitbucket etc)
  • and a cloud server (Rackspace cloud / Amazon EC2 etc)
    • your (PHP) scripts are served from /var/www/html/
    • your webpages are executed by apache
    • apache's home directory is /var/www/
    • (this describes a pretty standard apache setup on Redhat / Ubuntu / CentOS / Amazon AMI etc)

you should be able to do the same with Java, Perl, RoR, JSP etc. however you'll need to recreate the (rather simple) PHP script

1 - On your local machine

Here we add the deployment script and push it to the origin, the deployment script runs git commands to PULL from the origin thus updating your server

Grab a deployment script for your site

See deploy.php

Add, commit and push this to github

git add deploy.php
git commit -m 'Added the git deployment script'
git push -u origin master

2 - On your server

Here we install and setup git on the server, we also create an SSH key so the server can talk to the origin without using passwords etc

Install git...

After you've installed git, make sure it's a relatively new version - old scripts quickly become problematic as github / bitbucket / whatever will have the latests and greatest, if you don't have a recent version you'll need to figure out how to upgrade it :-)

git --version

...on CentOS 5.6

# Add a nice repo
rpm -Uvh http://repo.webtatic.com/yum/centos/5/latest.rpm
# Install git
yum install --enablerepo=webtatic git-all

...using generic yum

sudo yum install git-core

Setup git

git config --global user.name "Server"
git config --global user.email "server@server.com"

Create an ssh directory for the apache user

sudo mkdir /var/www/.ssh
sudo chown -R apache:apache /var/www/.ssh/

Generate a deploy key for apache user

sudo -Hu apache ssh-keygen -t rsa # choose "no passphrase"
sudo cat /var/www/.ssh/id_rsa.pub

3 - On your origin (github / bitbucket)

Here we add the SSH key to the origin to allow your server to talk without passwords. In the case of GitHub we also setup a post-receive hook which will automatically call the deploy URL thus triggering a PULL request from the server to the origin

GitHub instructions

Add the SSH key to your user

  1. https://github.com/settings/ssh
  2. Create a new key
  3. Paste the deploy key you generated on the server

Set up service hook

  1. https://github.com/oodavid/server.com/admin/hooks
  2. Select the Post-Receive URL service hook
  3. Enter the URL to your deployment script - http://server.com/deploy.php
  4. Click Update Settings

Bitbucket instructions

Add the SSH key to your account

  1. https://bitbucket.org/account/ssh-keys/
  2. Create a new key
  3. Paste the deploy key you generated on the server

Set up service hook

  1. Go to: Repo > Admin > Services
  2. Select "POST"
  3. Add the URL to your deployment script - http://server.com/deploy.php
  4. Save

Thanks to DrewAPicture in the comments for this one

4 - On the Server

Here we clone the origin repo into a chmodded /var/www/html folder

Pull from origin

sudo chown -R apache:apache /var/www/html
sudo -Hu apache git clone git@github.com:you/server.git /var/www/html

Rejoice!

Now you're ready to go :-)

Some notes

  • Navigate the the deployment script to trigger a pull and see the output:
    • http://server.com/deploy.php
    • this is useful for debugging too ;-)
    • When you push to GitHub your site will automatically ping the above url (and pull your code)
    • When you push to Bitbucket you will need to manually ping the above url
    • It would be trivial to setup another repo on your server for different branches (develop, release-candidate etc) - repeat most of the steps but checkout a branch after pulling the repo down

Sources

deploy.php
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
<?php
/**
* GIT DEPLOYMENT SCRIPT
*
* Used for automatically deploying websites via github or bitbucket, more deets here:
*
* https://gist.github.com/1809044
*/
 
// The commands
$commands = array(
'echo $PWD',
'whoami',
'git pull',
'git status',
'git submodule sync',
'git submodule update',
'git submodule status',
);
 
// Run the commands for output
$output = '';
foreach($commands AS $command){
// Run it
$tmp = shell_exec($command);
// Output
$output .= "<span style=\"color: #6BE234;\">\$</span> <span style=\"color: #729FCF;\">{$command}\n</span>";
$output .= htmlentities(trim($tmp)) . "\n";
}
 
// Make it pretty for manual user access (and why not?)
?>
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>GIT DEPLOYMENT SCRIPT</title>
</head>
<body style="background-color: #000000; color: #FFFFFF; font-weight: bold; padding: 0 10px;">
<pre>
. ____ . ____________________________
|/ \| | |
[| <span style="color: #FF0000;">&hearts; &hearts;</span> |] | Git Deployment Script v0.1 |
|___==___| / &copy; oodavid 2012 |
|____________________________|
 
<?php echo $output; ?>
</pre>
</body>
</html>

FYI, I got this to work using BitBucket pretty easily. They may have made allowances for POST requests in the last few months.

On BitBucket, went to the Repo > Admin > Services. Selected POST, dropped in my URL and saved it. Seems to be working as expected.

Thanks for the script, it makes my life a lot easier.

Glad it helped you out - the real trick for me was getting it so that Apache could play nicely with git...

Thanks! it works well for me on shared hosting, without keys!

Just a heads up. It would be smart to add git reset --hard HEAD in the commands before git pull. If for some reason your working directory is dirty (files changed, log files created etc) then the deploy will fail. Resetting the HEAD to the last commit will prevent a deploy failure.

Do you worry about security of the deploy.php script? Is there any harm is someone hits that script, or anything malicious they can do?

got stuck here, any ideas on how to change permissions?

root@staging ~]# sudo -Hu apache ssh-keygen -t rsa # choose "no passphrase"
Generating public/private rsa key pair.
Enter file in which to save the key (/var/www/.ssh/id_rsa): githubkey
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
open githubkey failed: Permission denied.
Saving the key failed: githubkey.

I created a key by skipping the create directory but now i get


[root@staging ~]# sudo -Hu apache git clone git@github.com:weblance2/primary-trunk.git /var/www/html/
fatal: destination path '/var/www/html' already exists and is not an empty directory.

as @mattbanks says, no security?

This might interest you: JamesBrooks/git-runner (with the git-runner-deploy gem).

I got this working but am missing why I created SSH keys?

If I understand the script correctly anyone can hit the URL (http://server.com/deploy.php) and it will execute a git pull. How is the difference detected between the GitHub WebHook service and a random visitor or a web crawler?

I think I will do some more digging, I found https://github.com/Coppertino/github-webhook with a similar function but more advanced options like IP filtering and SSH/FTP support.

I've rewrote this gist and created a 'normal' repository for it. Check it out!

It features:

  • easy configuration
  • no need to create the clone on the server first, it's doing that automatically
  • basic security (through obscurity) so the script can't be triggered by anyone except the one who knows the secret
  • update the code using non-master branch
  • delete files that are no longer in the repository (DANGEROUS!)
  • ignore certain files/directories when updating
  • error detection: if any step prior to deploy fails, nothing is changed
  • stamp the deployed code version
  • backup the target prior to deploy

If this is all "local" why not just use native git? using a "working tree" and a "bare repo"?

https://gist.github.com/4597331
http://stackoverflow.com/questions/5283262/what-is-a-git-work-tree-why-have-i-never-needed-to-set-this-as-an-env-var-why

Also things like branch, and other useful into are already coming over in the payload from the github post-receive hook, https://help.github.com/articles/post-receive-hooks not sure why those are passed in via $_GET

Awesome, thanks! Just a heads-up, on Ubuntu my user was www-data, not apache.

@mattbanks, @natxet: RE: security: Two things I usually do is to rename the script to {randomstring}.php, and modify it not to expose the username for all to see. Another option is to restrict referrer access to the script via htaccess.

I agree with @zanematthew. This method seems like overkill for what can be accomplished with a post-receive hook and a bare repo on the target server. Or am I missing something?

Already had ssh keys for my server because was pulling in changes manually. I'm using this in development and works perfect for me. Thanks!

This is only when my server is on PHP really? At same I can't to build another for Python, it's cool this congrats. Still I not test this, but I think so it will function... thanks.

In my case I needed to change (etc/passwd) [Centos 6.2]

apache:x:502:503:Apache server:/:/sbin/nologin
To
apache:x:502:503:Apache server:/var/www:/sbin/nologin

Another PHP tool for the job. A bit more elaborate one.

https://github.com/Perennials/apache-git-sync-tool

I've found and recommend this: http://magephp.com/

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.