January 18, 2014

Git, NGINX, web development and deploy-by-push (part 1)

I work as a web developer (please, help?) and what I want from my environment/servers is reliability and a fast and easy deployment method. I found a combination of tools that will do the job just as I want: Git, NGINX and some shell scripts.

The idea behind this is to be able to clone a git repository which would contain a particular web page, work on that repository and then push the changes back to the server, triggering an automatic deploy.
Of course, we don't want to trigger a blind git operation that will wipe out who-knows-what.
There is something more. Sometimes, because of WordPress bugs  or bad karma, some web pages get infected with those crappy PHP viruses. That is something I want to be able to fix in a few seconds, without restoring old backups nor doing any kind of manual cleaning.

I managed to get all those things, and I'd like to share it here. Hopefully you'll find it useful.

Here is how. Start by installing NGINX and Gitolite. Don't configure anything yet, just install them. I'll wait while you're dealing with your favorite package manager.


Are you done? Ok, let's move on.

You'll notice that (probably) the Gitolite package created a git user/group. If it didn't, create them. This is an important step, so don't skip it! But keep one thing in mind. The $HOME of the git user will be the path where repositories are going to be saved. You're free to set that path to whatever you want. I'll set mine to /srv/git. You'll also have to setup a password, set the right permissions/ownership, set some basic git stuff and generate a SSH key. I won't set a passphrase for the SSH key, but you are free to set one if you wish so.

$ usermod -d /srv/git git
$ passwd git
$ chown -R git:git /srv/git
$ chmod -R u+rwx /srv/git
$ chmod -R go-rwx /srv/git
$ su - git
$ ssh-keygen -t rsa -C "git@alexandernst.com"
$ git config --global user.email "git@alexandernst.com"
$ git config --global user.name "Git System"
$ git config --global push.default simple

Next step is to setup Gitolite itself. It's done with a command that will create the required folders structure and the admin repository.

$ gitolite setup -pk /srv/git/.ssh/id_rsa.pub

$ pwd
/srv/git

$ tree -a -L 2
.
|-- .bash_history
|-- .gitconfig
|-- .gitolite
|   |-- conf
|   |-- hooks
|   |-- keydir
|   `-- logs
|-- .gitolite.rc
|-- .local
|   `-- share
|-- .ssh
|   |-- authorized_keys
|   |-- id_rsa
|   `-- id_rsa.pub
|-- projects.list
`-- repositories
    |-- gitolite-admin.git
    `-- testing.git

11 directories, 7 files

You'll be using the admin repository to add and/or delete repositories and users. And for that, you'll need to clone that repository, edit the config file inside and push it.

$ git clone git@localhost:gitolite-admin

Note: If the cloning process asked you for the git user password instead of using the key you just generated or if you got a warning saying that you cloned an empty repository, then you did something wrong. SSH is extremely picky with permissions, so triple-check that you followed the exact commands I wrote. Only the git user should be able to RWX the $HOME path. Both the group and others should not have any access at all to that directory.

$ tree -a -L 2
.
|-- .bash_history
|-- .gitconfig
|-- .gitolite
|   |-- conf
|   |-- hooks
|   |-- keydir
|   `-- logs
|-- .gitolite.rc
|-- .local
|   `-- share
|-- .ssh
|   |-- authorized_keys
|   |-- id_rsa
|   |-- id_rsa.pub
|   `-- known_hosts
|-- gitolite-admin
|   `-- .git
|   |-- conf
|   `-- keydir
|-- projects.list
`-- repositories
    |-- gitolite-admin.git
    `-- testing.git

15 directories, 8 files

$ cd gitolite-admin
$ cat conf/gitolite.conf
repo gitolite-admin
    RW+     =   id_rsa

repo testing
    RW+     =   @all

I won't be explaining in depth how to configure Gitolite. If you want to learn everything about it, go to Gitolite's docs and read them. I'll just show you what I did and what works for me.

My conf file looks like this.

@projects = random_stuff more_stuff
@projects = yet_more_stuff

repo gitolite-admin
    RW+     =   @all

repo @projects
    RW+     =   @all

Note that I'm granting both read and write access to all the keys that I have added (keep reading, I'll get to this in a moment). Maybe this won't fit your needs, or maybe it will. Configure your Gitolite instance as you want.

After editing the config file, as I already said earlier, you need to push it back to Gitolite's admin repository.

$ git status
        modified:   conf/gitolite.conf
$ git commit -am "Grant RW to @all"
        1 file changed, 4 insertions(+), 2 deletions(-)
$ git push

After each push, Gitolite will scan your conf file and detect all the changes you did. Which means that if you added/deleted repositories, Gitolite will create/delete them, if you changed permissions, Gitolite will apply those changes, etc...

Now that we are done with Gitolite's basic setup, we need to add some users, because... yeah... if we can't clone/push from/to the server, what's the point of having one? 

Go to your machine and generate a SSH key the same way you did for the git user. Then copy the public (.pub) key to the server, inside the keydir folder, inside the Gitolite admin repository.

$ scp /home/alexandernst/.ssh/id_rsa.pub git@alexandernst.com:/srv/git/gitolite-admin/keydir/alexandernst.pub

Note that I copied my key from my machine to my server, where I installed Gitolite, but I changed the name of my key from id_rsa.pub to alexandernst.pub.

Now go back to the server and add the key you just copied.

$ git status
        keydir/alexandernst.pub
$ git add keydir/alexandernst.pub
$ git commit -am "Add alexandernst user"
        1 file changed, 1 insertion(+)
$ git push

From now on you should be able to clone the admin repository on your machine and add/delete users/repositories.

I'll be writing a second post about how to actually setup Gitolite and NGINX for push deploy as this post already looks quite long.