Deploy an Application to the Remote Server

With Git prepared on both the local workstation and on the remote server, I can now deploy my application.

Defining a Remote Repository

In order to deploy an application from my development workstation to istarelworkshop.com, I need to configure the application repository on my workstation such that is can communicate with the repository on the production server.

Here is the current configuration for the Istarel Workshop application:

markf$ cd ~/Sites/iw
markf$ cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true

Now I configure this repository with user and path information on the remote Git repository. (Note that the 1158 in the remote declaration is the port, for cases where ssh is not listening to its standard port 22.)

markf$ git remote add istarelworkshop 
       ssh://git@www.istarelworkshop.com:1158/var/git/iw
markf$ cat .git/config

If I look at the configuration for the local repository now, I see the definition for "istarelworkshop".

markf$ cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
[remote "istarelworkshop"]
	url = ssh://git@www.istarelworkshop.com:1158/var/git/iw
	fetch = +refs/heads/*:refs/remotes/istarelworkshop/*

Cloning a Bare Repository

With the description of the remote repository done, I can now deploy the application.

markf$ git push istarelworkshop master

I am not done yet, though. The repositorities I set up on istarelworkshop.com are bare repositories; that is, they contain all the branches and history but are not a working repository. I need to clone that bare repository to the appropriate location on istarelworkshop.com. In an earlier article, I showed how to set up Apache2 virtual hosts. The first such host has its base directory at /var/www/istarelworkshop.com. I need to take the bare repository and clone it to that location.

markf$ ssh markf@www.istarelworkshop.com
iwuser$ cd /var/www
iwuser$ sudo git clone /var/git/iw istarelworkshop.com
iwuser$ sudo chown -R www-data:www-data istarelworkshop.com

Configure the Remote Application

Back when I set up the local repository, I made sure that certain key configuration files were not part of the repository. This is important because every server is different, and the key paths and identities used on my local workstation are quite different from the Ubuntu VPS I deployed. So, I need to create those configuration files on istarelworkshop.com.

iwuser$ sudo su - www-data
$ bash
www-data$ cd /var/www/istarelworkshop.com
www-data$ mkdir conf && cd conf
www-data$ vi ApplicationConstants.php

Listing: /var/www/istarelworkshop.com/conf/ApplicationConstants.php

<?php

# Fundamental Application Mode
define('IN_PRODUCTION', 1);             # 0 = Development, 1 = Production

# Application Directories
define('APPL_ROOT_DIR', '/');
define('APPL_RSRC_DIR', '/var/www/istarelworkshop.com/rsrc/');

# Istarel Workshop Frameworks Directory
if (! defined('FRAMEWORK_DIR'))
   define('FRAMEWORK_DIR', '/var/www/istarelworkshop.com/fw/');

# Supplemental Directories Required by Application Frameworks Classes
define('APPL_IMG_DIR', APPL_ROOT_DIR . 'img/');
define('APPL_LIB_DIR', APPL_ROOT_DIR . 'lib/');

# Define the Application Database attributes
define('DB_TYPE',       'pgsql');
define('DB_HOST',       'localhost');
define('DB_NAME',       'iw');
define('DB_USERNAME',   'iwdb');
define('DB_PASSWORD',   'secret');

?>

The application framework uses Apache's mod_rewrite system to power the Front Controller. I need to create an .htaccess file at the root of the repository to ensure that proper routing happens.

Listing: /var/www/istarelworkshop.com/.htaccess

RewriteEngine On
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

Install and Configure Git on the Server

On the Ubuntu server I have for Istarel Workshop, the package manager is called Aptitude. Much like MacPorts, installing Git is a single Unix command.

markf$ ssh iwuser@www.istarelworkshop.com
iwuser$ sudo aptitude install git-core

Establish a Git Unix User

On the remote (production) server, I want to establish git as a Unix user responsible for the management of the Git repositories.

iwuser$ sudo adduser git
Adding user `git' ...
Adding new group `git' (1002) ...
Adding new user `git' (1001) with group `git' ...
Creating home directory `/home/git' ...
Copying files from `/etc/skel' ...
Enter new UNIX password: secret
Retype new UNIX password: secret

The idea here is to have it possible for multiple remote users work with the repository on istarelworkshop.com. As such, I will create a .ssh directory for the git user and create an authorized keys file.

iwuser$ sudo su - git
git$ mkdir .ssh
git$ chmod 700 .ssh
git$ touch /home/git/.ssh/authorized_keys
git$ exit

Anyone who intends to contribute to the repository must append their public ssh key to authorized_keys (a task often handled by the server administrator, to whom the developers send their public ssh key). This makes it possible, for example, to push changes to the repository without having to log in to the remote server as the git user.

iwuser$ sudo cat ~/.ssh/authorized_keys >> /home/git/.ssh/authorized_keys

At this point, git is a "normal" Unix user in every way, including having the default bash shell with which to execute commands. One key security principle is to allow users to perform only those activities necessary to their job. For the git user, that means I want to apply a special shell that only permits Git commands.

iwuser$ sudo chsh -s /usr/bin/git-shell git

Prepare the remote repository

The parent directory for the git repositories will be owned by me, but all the git directories will be owned by git. To deploy the application that runs istarelworkshop.com, I need two such respositories: iw for the application, and fw for Istarel Workshop Application Framework with which the application is built. In each directory, I establish a bare repository.

iwuser$ sudo mkdir /var/git
iwuser$ sudo chown `whoami` /var/git
iwuser$ cd /var/git
iwuser$ mkdir iw && cd iw
iwuser$ git --bare init
iwuser$ sudo chown -R git:git .
iwuser$ cd /var/git
iwuser$ mkdir fw && cd fw
iwuser$ git --bare init
iwuser$ sudo chown -R git:git .

Install and Use Git Locally

Git is a powerful, flexible version control simple, one I find more intuitive than Subversion. Once again, I use MacPorts to install Git, and then I supply some global configuration settings.

markf$ sudo port install git-core
markf$ git config --global user.name "Mark Fenoglio"
markf$ git config --global user.email markf@istarelworkshop.com
markf$ git config --global color.diff auto
markf$ git config --global color.status auto
markf$ git config --global color.branch auto

The first two Git configuration commands set important defaults for identifying the author of changes to the repository. The last three commands define what colors to use when Git presents information in the console.

Create the Initial Git Repository

markf$ cd ~/Sites/iw
markf$ git init
Initialized empty Git repository in /Users/markf/Sites/iw/.git/

Ignoring Mac OS X Finder Detritus

One nuisance in Mac OS X when working with version control systems is (normally hidden) .DS_Store files created by the Finder. Git allows you to globally ignore files.

markf$ git config --global core.excludesfile ~/.gitignore
markf$ echo .DS_Store >> ~/.gitignore

Exclude Files from Version Control

In addition to being able to ignore certain files regardless of context, you can also ignore files for a specific Git repository. One common example of this is configuration files where the values of certain parameters will be different between development (local) and production (remote) environments.

markf$ cd ~/Sites/iw
markf$ vi .git/info/exclude
conf/ApplicationConstants.php
httpd.conf
install/conf/sh.conf
install/php/config.php

Initial Repository

Now that the appropriate files will not be part of the repository, I can create its initial version.

markf$ git add .
markf$ git commit -m "[install] initial repository"

The . in the first command is a wildcard that means add all non-ignored files to the current batch of changes. The -m switch on the commit command is the message to be included as the changes are committed to the repository.