Setup a Git Server and Deploy with Git Hooks on Ubuntu 18.04

Introduction

In this post we look at the process of setting up a Git repository on a DigitalOcean droplet running Ubuntu 18.04. After setting up the repository, we create a server side hook to automatically deploy a successful git push to a web server. A non-root user with no sudo permissions will be used to create the Git repository. The Git user will also be granted read and write permissions on the website for a successful deployment. After the process of setting up and deploying the repository is complete, we will disable interactive shell for the Git user.

Prerequisites

In order to follow along in this post, you will require the following:

  • A server running on Ubuntu 18.04 or higher
  • A user with sudo permissions to connect to the server using SSH. We will use this user to setup the Git user.
  • An installation of Git on the server
  • A directory to deploy the Git repository on a successful git push

Login to Server Using SSH Keys

Using SSH (Secure SHell) log into your DigitalOcean server. You can SSH the server using either the server IP address or your domain name.

  • Using an IP address

        ssh kagundajm@23.45.90.11 -i ~/.ssh/kagundajm-droplet
    
  • Using a domain name. You must configure your domain to point to DigitalOcean before you using the domain name.

        ssh kagundajm@droplet.com -i ~/.ssh/kagundajm-droplet
    

Create Git Repository Owner

Create non sudo git user with a disabled password. Logins will only be possible using SSH keys and not passwords.

  sudo adduser --disabled-password git

Create File For Authorized SSH Keys

Switch user to the newly create repository owner

sudo su git

Move to home directory of the repository owner

cd

Create directory for SSH key files with read, write and execute for the owner

mkdir ~/.ssh 

chmod 700 ~/.ssh

Create authorized keys file with read/write permissions for the owner

touch ~/.ssh/authorized_keys 

chmod 600 ~/.ssh/authorized_keys

Create your project repository folder. This step has to be repeated for all the projects you want to host as repositories.

mkdir project.git 

cd project.git

git init --bare

--bare creates a storage space for your repository or a repository without a working directory.

Copy User Public SSH Key to Clipboard

From your local computer, copy and add public keys for any users you would like to access the private git server.

  • If using a Mac, run

    pbcopy < ~/.ssh/kagundajm-droplet.pub
    

    The above command will copy the contents of the public SSH key file to the clipboard. Remember to replace ~/.ssh/kagundajm-droplet.pub with your user’s SSH public key

  • You can also open your SSH public key with your text editor, select all the contents of the file and copy the contents to the clipboard

Append SSH Key to Git Server Authorized Keys

Back on your Git server, open ~/.ssh/authorized_keys with your favorite text editor.

 vi ~/.ssh/authorized_keys

Append the contents of the key file we copied in the previous step at the end of the file.

Save the file and and close the text editor.

Managing Multiple SSH keys on Your Local Computer

In situations where you have multiple SSH keys on your local computer, then you can specify the configuration file to use on the command line.

GIT_SSH_COMMAND='ssh -i ~/.ssh/kagundajm-rsa' git push website

Using this approach would require specifying the key every time you are executing a Git push command.

A better alternative would be to create a custom SSH configuration file. Using a configuration file, we will assign an alias name to our remote connection and use this name when accessing these remote computers. This is the approach we will adopt.

Using your preferred Editor, open your custom configuration file

vim ~/.ssh/config

Append the following to the configuration file:

Host website
    Hostname droplet.com
    User git
    IdentityFile ~/.ssh/kagundajm_droplet_rsa
    IdentitiesOnly yes

Note that indentation is not required but is used here to make it easier to read the available options within the file. Also you can assign Host any name you prefer; in this instance our Host is named web.

Save the changes and exit.

By default, the SSH configuration file does not exist. If a new file was created, make sure to grant read/write permissions to the owner no permissions to the group and anyone else (others).

chmod 600 ~/.ssh/config

Now the git user can use SSH connections to ssh into the server, push, pull or even clone from the repository using commands like the following:

    ssh website

    git clone website:project.git

    git push website

Add Remote Git Repository to Local Git Config

On your local computer, you may be in one of two scenarios. Either you have an existing git repository or you are creating a new repository. In this post, we will be using website as the name of our remote directory but you can use any name you prefer.

  • if you already have an existing local repository.

    • add the remote git project directory to the local .git/config.

      git remote add website website:project.git
      
    • Push the contents of the local repository to the remote one.

      git push website +master:refs/heads/master
      

    website is the name of the remote repository we want to add

    master:refs/heads/master is a refspec that can be used for fetching.

    The format for the refspec is +<src>:<dest> with the + being optional.

  • if it is a new git repository you are setting up, then use run the following commands from the Terminal.

      git init
    
      git add .
    
      git commit -m 'initial commit'
    
      git remote add website website:project.git
    
      git push website master
    

Any future changes you make locally can now be uploaded to the remote repository simply by running

git push website

Also take note that we are using git@droplet.com user and not the user you normally use to login to your droplet.

Git Server Side Hook to Deploy to Web Server on Successful Git Push

Git hooks are custom scripts that Git executes when certain actions occur. There are client side and server side hooks. These hooks are stored in .git/hooks folder. In automatically updating our web server, we will use post-receive server side hook.

Make sure you are using the user you used to create git user

Create your project’s folder on the web server

sudo mkdir /var/www/project01

Change group ownership of web folder to git:www-data.

sudo chown -R git:www-data /var/www/project01

Grant write permissions on the folder to the new owner and group

sudo chmod -R ug+rwx /var/www/project01/

Make all new files and subdirectories created within project01 inherit the folder’s group id (www-data) of the directory rather than the group ID of the user who created the file/directory.

sudo chmod g+s /var/www/project01

Now that we have setup the project folder on the web server, switch back to git user

sudo su git

Move to root of your git project

cd ~/project.git

Create a post-receive hook that will checkout your latest push to the web server

vi hooks/post-receive

Update the hooks/post-receive file with the following:

#!/bin/bash

GIT_WORK_TREE=/var/www/projects.droplet.com git checkout -f

Save the changes and exit.

Make hooks/post-receive file executable

chmod +x hooks/post-receive

A successful git push will now trigger the post-receive hook which will copy the latest contents of the repository to your web server.

Prevent Git Users Interactive Login Into the Server

Using SSH to login to a server also provides an interactive shell access to the remote Git users. To restrict the users to only Git-related activities for managing the repositories, we need to replace the shells assigned to git-shell which is a more restrictive shell.

List the available shells to determine whether git-shell is already included among the shells.

cat /etc/shells

If git-shell is not listed, find out where it is located.

which git-shell

Take note of the displayed git-shell path

Open /etc/shells with your text Editor

sudo vim /etc/shells

Append the path to /etc/shells

Save the changes and close the text editor.

Edit the shell for Git users to git-shell

sudo chsh git -s $(which git-shell)

Note you can always change back to the default bash shell for the Git user by running

sudo chsh git -s $(which bash)

Now all Git users will only use SSH connections to push and pull Git repositories.

References

  1. HOWTO setup a private git server on Ubuntu 18.04
  2. 4.4 Git on the Server - Setting Up the Server
  3. A git Primer
  4. Using Git to manage a web site
  5. How To Set Up Automatic Deployment with Git with a VPS