Automatically push master branch code to demo server

  |   Source

I have two VPSs (Virtual Private Server).

One is used as a version control repository. It runs both Gitolite and Fossil.

The second is a "normal" LAMP server. I want to use that to demonstrate the code I have created and have pushed to the version control server. But I only want that code to get run on this server if it is in the master branch of the repository of the project I am working on.

This post will explain how setup the demo server to automate the creation and setup of a new website and then connect the version control server to the demo server so it will automatically update the code running on the demo server when code is checked into the master branch of the repository.

The Environment:

The Version Control Server (VServer)

  • Ubuntu 12.04 LTS
  • Has 3 users: root, normal and gitolite
  • Running Gitolite

The Demonstration Server (DServer)

  • Ubuntu 12.04 LTS
  • Has 3 users: root, normal and git
  • Running LAMP stack
  • Git is installed
  • ACL is installed

Checklist of software and setup:

Setup the PC

Git (and optionally Git-Flow) is installed on PC

Setup the VServer

Install and setup gitolite

You should be able to create new repositories on VServer through gitolite-admin on your PC.

Setup the DServer

Install and setup git:

sudo apt-get install git

Create git group and user:

sudo adduser \
--system \
--shell /bin/bash \
--gecos 'git version control' \
--group \
--disabled-password \
--home /home/git \
git

Install and setup ACL (Access Control List):

sudo apt-get install acl

Edit /etc/fstab and add "acl" to the end of the options list

Reboot DServer

Add the git group to the www directory:

setfacl -m group:git:rwx /var/www

As the git user:

Add a repositories directory

Set up SSH ability from the VServer to the DServer:

As the gitolite user on the VServer:

Create a ssh key for DServer

scp public key to DServer

Check that it works

See the Create SSH Keys post for more information about creating ssh keys.

Edit git user to only use git-shell:

sudo vim /etc/passwd

Change /bin/sh to /usr/bin/git-shell (or wherever git-shell is)

Copy the following scripts -

Into "normal user" /bin directory on DServer and make both of them executable.

mkvirtualserver

#!/bin/bash
# This script is used to create virtual hosts.
# This script assumes the following:
# 1) This is a Debian/Ubuntu OS and Bash 4.x or higher is installed
# 2) The Apache defaults are in place but they can be changed in the script
#    Base dir is /var/www
#    Log dir is /var/log/apache2
#    Apache user is www-data
# 3) Git is installed
# 4) ACL is installed
# 5) There is a git user and
# 6) There is a /home/git/repositories directory
# But #2-6 can be changed in the script
# This uses the a2ensite command which is usually only available on
# Debian/Ubuntu systems.

# NOTE! Change the <your domain> in the third prompt to your domain

# Set up the default parameters
read -e -p "Enter the web home directory:" -i "/var/www" homedir
read -e -p "Enter the git repository base directory:" -i "/home/git/repositories" gitdir
read -e -p "Enter the domain name for the server:" -i "<your domain>" sn
read -e -p "Enter the Project name:" -i "" proj

if [ -z "$proj" ]; then
  echo "Project name cannot be blank!"
  exit
fi


# Create the web directory and a index.php test file
cd $homedir
mkdir $proj
cd $homedir/$proj
mkdir "public_html"

# Set the owner and change permissions
chown -R www-data:www-data $homedir/$proj/
chmod -R '750' $homedir/$proj/public_html

# Setup the permissions so git can write to website
setfacl -Rm d:u:www-data:rwx,u:git:rwx $homedir/$proj

# Create the git directory and a bare git repository
cd $gitdir
mkdir $proj.git
cd $gitdir/$proj.git
git init --bare
cat >hooks/post-receive <<EOF
#!/bin/bash
GIT_WORK_TREE=$homedir/$proj/public_html git checkout -f
EOF

chmod ug+x hooks/post-receive

chown -R git:git $gitdir/$proj.git

# Create a directory for your apache errors log
mkdir /var/log/apache2/$proj/

# Creation the file with VirtualHost configuration in /etc/apache2/site-available/
echo "<VirtualHost *:80>
        ServerAdmin webadmin@localhost
        ServerName $proj.$sn
        ServerAlias www.$proj.$sn

        DocumentRoot $homedir/$proj/public_html/
        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>
        <Directory $homedir/$proj/public_html/>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride None
                Order allow,deny
                allow from all
        </Directory>

        ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/

        <Directory "'/usr/lib/cgi-bin'">
                AllowOverride None
                Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                Order allow,deny
                Allow from all
        </Directory>

        ErrorLog /var/log/apache2/$proj/error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn

        CustomLog /var/log/apache2/$proj/access.log combined

    Alias /doc/ "'/usr/share/doc/'"

    <Directory "'/usr/share/doc/'">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>

</VirtualHost>" > /etc/apache2/sites-available/$proj

# Add the host to the hosts file
echo 127.0.0.1 $proj.$sn >> /etc/hosts

# Enable the site
a2ensite $proj

# Reload Apache2
service apache2 reload

rmvirtualserver

#!/bin/bash
# This script is used to remove virtual hosts.
# This script assumes the following:
# 1) This is a Debian/Ubuntu OS and Bash 4.x or higher is installed
# 2) The Apache defaults are in place but they can be changed in the script
#    Base dir is /var/www
#    Log dir is /var/log/apache2
#    Apache user is www-data
# 3) Git is installed
# 4) ACL is installed
# 5) There is a git user and
# 6) There is a /home/git/repositories directory
# But #2-6 can be changed in the script
# This uses the a2dissite command which is usually only available on
# Debian/Ubuntu systems.

# NOTE! Change the <your domain> in the fourth prompt to your domain
# Set up the default parameters
read -e -p "Enter the web home directory:" -i "/var/www" homedir
read -e -p "Enter the web log directory:" -i "/var/log/apache2" logdir
read -e -p "Enter the git repository base directory:" -i "/home/git/repositories" gitdir
read -e -p "Enter the domain name for the server:" -i "<your domain>" sn
read -e -p "Enter the Project name:" -i "" PROJECT

if [ -z "$PROJECT" ]; then
  echo "Project name cannot be blank!"
  exit
fi

# Remove the website and logs
if rm -rf $homedir/$PROJECT; then
  echo "Deleted $homedir/$PROJECT"
else
  echo "WARNING: $homedir/$PROJECT was not removed!"
fi

if rm -rf $logdir/$PROJECT; then
  echo "Deleted $logdir/$PROJECT"
else
  echo "WARNING: $logdir/$PROJECT was not removed!"
fi

a2dissite $PROJECT

if rm -rf /etc/apache2/sites-available/$PROJECT; then
  echo "Deleted /etc/apache2/sites-available/$PROJECT"
else
  echo "WARNING: /etc/apache2/sites-available/$PROJECT was not removed!"
fi

# Remove the git repository
if rm -rf $gitdir/$PROJECT.git; then
  echo "Deleted $gitdir/$PROJECT.git"
else
  echo "WARNING: $gitdir/$PROJECT.git was not removed!"
fi

# Remove the hosts entry
gitrepo="127.0.0.1 $PROJECT.$sn"
#echo "gitrepo: $gitrepo"
if sed -i "/$gitrepo/d" /etc/hosts; then
  echo "Deleted $gitrepo from /etc/hosts file"
else
  echo "WARNING: $gitrepo was not removed!"
fi

# Reload Apache
service apache2 reload

Into gitolite /support directory on VServer and make setupmasterpush executable.:

post-receive

#!/bin/bash
while read oldrev newrev refname
do
  branch=$(git rev-parse --symbolic --abbrev-ref $refname)
  if [ "master" == "$branch" ]; then
    git push origin master
  fi
done

setupmasterpush

#!/bin/bash
# This script is used to setup the repository to push code
# from the master branch only to the "Production" server.
# This script assumes the following:
# 1) Gitolite is installed
# 2) There is a gitolite user and
# 3) There is a /home/gitolite/repositories directory
# 4) There is a /home/gitolite/support directory and the
#    post-receive file is there

# Make sure you change the <hostname> parameter

# Set up the default parameters
HOSTNAME="<hostname>"

read -e -p "Enter the Project name:" -i "" PROJECT

if [ -z "$PROJECT" ]; then
  echo "Project name cannot be blank!"
  exit
fi

cd /home/gitolite/repositories/$PROJECT.git

cp ../../support/post-receive hooks/.
chmod ug+x hooks/post-receive

git remote add origin $HOSTNAME:repositories/$PROJECT.git

git push -u origin master

Development Workflow

So, the workflow would be something like this:

Important: Create a short but descriptive name for the project and use that as the name for the directory the code is under AND the name of the repositories AND the name of the website.

On the PC, start the project. Create a directory with the Project Name. Write the code and commit it to the local git repository.

Using Gitolite, create the remote repository using the Project Name. Add the remote repository to the local repository. Push the develop and master branches.

When you are ready to demo the code:

On the DServer:

login as "normal" user
cd bin
sudo ./mkvirtualserver  // and give the Project Name at the prompt

On the VServer:

login as "normal" user
su gitolite
cd support
./setupmasterpush  // and give the Project Name at the prompt

The post-receive hook on the VServer will only fire if there is a change to the master branch so make a change to the README file or some other unimportant file and add/commit/push it. The code will be pushed to the VServer and the VServer will push the code to the DServer and git will copy the code from the repo to the website directory.

Refresh the browser and you should see the site.

Comments powered by Disqus