CSC309: Deploying the Right Way

The first assignment in CSC309 this semester has some rather strange methods for deploying the website: we're required to submit an Amazon Machine Image (AMI) with Apache httpd serving the website and, while optional, we're also expected to use VNC to remote into our production server and develop the site using the included Firefox and Eclipse programs.

I've decided to adopt some 12-factor philosophies to make this process a bit less painful...

  • Version control with git
  • git push deploys

...which allows me to develop the site on my local machine and only requires a single command to deploy.

Set up the EC2 instance

First, make sure you have an SSH key pair configured on AWS. You can either create your own and import it, or create a new one in the AWS console:

https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#KeyPairs:

Next, launch a new EC2 instance of the AMI that De Lara provides:

https://console.aws.amazon.com/ec2/home?region=us-east-1#launchAmi=ami-cafc53a2

  1. Choose the t2.micro instance type (or t2.small if you have cash to spare)

  2. Click Next until you get to Step 6: Configure Security Group

  3. Create a new security group, name it something like csc309-a1, and allow SSH access from anywhere:

    Security Group
  4. Then go ahead and click Review and Launch, then Launch.

    Note: AWS will warn you that Your security group, csc309-a1, is open to the world. Just ignore that; all this means is that port 22 (ssh) is open to the entire internet.

After a minute or so, your instance will be running and you can connect via SSH. The AWS console will tell you to use a command like...

ssh -i your-private-key.pem ubuntu@<PUBLIC_IP>

...but you should set your default SSH key:

# SSH will automatically use the key ~/.ssh/id_rsa
Spencers-MacBook$ chmod 400 your-private-key.pem
Spencers-MacBook$ mv your-private-key.pem ~/.ssh/id_rsa

This will later allow us to push to the Git remote.

Use Git

Once our EC2 instance is set up, let's put our code under version control.

Create a Git repository

On your local computer, initialize Git in your project directory:

Spencers-MacBook$ cd path/to/csc309-a1/ # enter your project directory
Spencers-MacBook$ git init # initialize git
Spencers-MacBook$ git add . # add all existing files
Spencers-MacBook$ git commit -m 'First commit' # make your first commit

Create a Git remote on the server

Once you've created your Git repo, we need to set up our EC2 instance as a Git remote.

Log into the instance and create a bare Git repository:

Spencers-MacBook$ ssh ubuntu@<PUBLIC_IP>
ubuntu@ip-1-2-3-4:~$ git init --bare ~/csc309-a1.git

(Where PUBLIC_IP is the public IP address of your instance)

Then on your local machine, add the remote:

Spencers-MacBook$ git remote add aws ubuntu@<PUBLIC_IP>:csc309-a1.git

And make your first push:

# git will use your private key ~/.ssh/id_rsa
Spencers-MacBook$ git push -u aws master

If all went well, you should now be able to see your commit history on your EC2 instance:

ubuntu@ip-1-2-3-4:~/csc309-a1.git/$ git log --pretty=oneline

That git log command should output something like this:

141ea38b4391c22f0ac9be232c9f70439c55f515 First commit

Configure a Git hook to deploy the site

Now that we can push code to the server, the final step is to create a Git hook that will deploy your site whenever you do a git push.

On your EC2 instance, create the post-receive script:

ubuntu@ip-1-2-3-4:~$ nano ~/csc309-a1.git/hooks/post-receive
#!/bin/bash -l
GIT_REPO=$HOME/csc309-a1.git
TMP_GIT_CLONE=$HOME/tmp/csc309-a1
PUBLIC_WWW=/var/www/html
# Clone the bare repo into a temporary repo with a working copy
git clone $GIT_REPO $TMP_GIT_CLONE
# Enter the working directory
cd $TMP_GIT_CLONE
# Copy the site to the apache directory, ignoring specific files
echo "Copying site to $PUBLIC_WWW ..."
if [ -r .rsyncexclude ]; then
rsync --archive --delete --exclude-from=.rsyncexclude . $PUBLIC_WWW
else
rsync --archive --delete . $PUBLIC_WWW
fi
echo "Done copying!"
# Remove the temporary repo
cd ~
rm -rf $TMP_GIT_CLONE

And set it to be executable:

ubuntu@ip-1-2-3-4:~$ chmod 775 ~/csc309-a1.git/hooks/post-receive

Optionally, you can create a file called .rsyncexclude in the root of your repository to exclude certain files from being copied to the web server. Example .rsyncexclude:

# Files ignored by rsync when copying the site to /var/www/html/.
# All files in /var/www/html/ will be DELETED except for the files listed below.
# This file
/.rsyncexclude
# Git files
/.git
/.gitignore
# Ruby files for local testing
/.ruby-version
/Gemfile
/Gemfile.lock
/Rakefile
# README file
/README.md
# Files preserved in /var/www/html/
/phpversion.php

Deploying

Finally, we can deploy our site with one simple command on our local machine:

Spencers-MacBook$ git push aws

To view the site, you need to open an SSH tunnel:

Spencers-MacBook$ ssh ubuntu@<PUBLIC_IP> -L 8080:localhost:80

Then open http://localhost:8080 in your browser. Alternatively, add TCP port 80 to your EC2 instance security group inbound rules and open http://<PUBLIC_IP> in your browser

Conclusion

This seems like a lot of configuration for a simple static website, but I'd much rather do this over developing my site on the production server. Ideally, it'd be better to use something like Dokku, but unfortunately that's not possible since we're required to use Apache httpd. Maybe assignment 2...

I hope this helped someone!