Keeping in line with my policy of low memory overhead, I do not want to waste several hundred megabytes on a git repository manager, such as Gitlab or Bitbucket. If you get back to Git basics, you can set up a Git repository with no additional overhead.
Basics
Let’s get back to basics, what is Git? Git is a distributed version control system, which means it’s just a bunch of files on disk. Git is fairly protocol-agnostic, so it can transfer data over HTTP, FTP or the Git protocol. Often, the Git protocol is used in conjunction with ssh
, which handles the transport layer encryption and authentication. Whenever you see a command line git clone git@git:repo
, you are most likely using Git+SSH.
This guide assumes you know how SSH public-private key authentication works. If not, follow this tutorial on Digital Ocean.
Setup
Git+SSH
To set up a Git+SSH server, so you can clone/commit etc. via SSH is fairly simple. Create a single Unix user, through which all users will authenticate based on their password. To make it a bit more user-friendly and secure, do the following steps:
-
Create a Git user.
groupadd git useradd -g git -m -d /srv/git -s /usr/bin/git-shell -c "Git User" git
There are several aspects which are important in this command:
-
-m -d /srv/git
This creates a home directory for thegit
user which will store all the repositories. Since you can use relative paths with SSH, this allows you to put a repository in/srv/git/repo1
and clone it withgit clone [email protected]:repo1
. No need to use full paths. -
-s /usr/bin/git-shell
is a purpose built shell for Git use only. Remember, SSH normally grants you a login shell, which allows you to do everything on a system what a non-root user can, which is a lot! Thegit-shell
only allows clients to execute Git related commands.
Tip: You might need to add
/usr/bin/git-shell
to the list of allowed shells (often found at/etc/shells
) to allow logins usinggit-shell
. This depends on your distribution. -
-
Make sure the
git
user home directory is owned by thegit
user:chown git: /srv/git
-
Add public keys for the users to the
git
user’sauthorized_keys file
:mkdir /srv/git/.ssh chmod 700 /srv/git/.ssh echo 'ssh-rsa AAAAB3NzaC1yc2EAA...ZGXMchiG0K4aNp5= [email protected]' >> /srv/git/.ssh/authorized_keys chmod 600 /srv/git/.ssh/authorized_keys chown -R git: /srv/git/.ssh
Make sure you end up with the following permissions:
drwx------ 2 git git 4096 nov 23 2015 .ssh -rw------- 1 git git 218 nov 23 2015 .ssh/authorized_keys
Tip: if you have problems logging on using Git, test if you can log on with a normal SSH client. Make sure the permissions for the
.ssh/
directory andauthorized_keys
file exactly match the ones stated above. -
Create a Git repository on the server. You need to create a ‘bare’ Git repository to allow operations over SSH.
cd /srv/git git init --bare repoName chown -R git: repoName
-
Clone and work with the repo!
You can now work with the repository by using the git remote [email protected]:repoName
, for example with:
git clone [email protected]:repoName
git remote add origin [email protected]:repoName
HTTP Browsing
So now we have a basic Git server running, we can enhance it a bit by allowing read-only HTTP browsing of the repositories for easy access. Since I already have an Apache HTTP server with PHP running, I decided to use GitList. The stable GitList version at time of writing is 0.5.0.
-
Download GitList
wget https://s3.amazonaws.com/gitlist/gitlist-0.5.0.tar.gz
-
Untar it in your webroot or other directory which is accessible by your webserver
cd /var/www/ tar -zxvf /home/user/Downloads/gitlist-0.5.0.tar.gz
-
Copy the
config.ini-example
file toconfig.ini
and change the following parameters:[git] repositories[] = '/srv/git'; [date] timezone = 'Europe/Amsterdam'
-
Make sure the Git repository directory is readable by the webserver user. The easiest way to do this is by adding the webserver user to the
git
Unix group:usermod -G git www-data
-
Browse to the GitList page (probably at http://git.example.com/gitlist/)
-
Optionally, add authentication and SSL. Use this Apache config as a guide:
<VirtualHost 192.0.2.10:443> ServerAdmin admin@git.example.com ServerName git.example.com DocumentRoot /var/www/gitlist/ SSLEngine on SSLProtocol all -SSLv2 SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM SSLCertificateFile /etc/apache2/ssl/git.example.com.crt SSLCertificateKeyFile /etc/apache2/ssl/git.example.com.key SSLCACertificateFile /etc/apache2/ssl/git.example.com_ca.crt ErrorLog ${APACHE_LOG_DIR}/git.example.com_error.log CustomLog ${APACHE_LOG_DIR}/git.example.com_access.log combined LogLevel warn <Directory /var/www/gitlist> Options MultiViews FollowSymLinks AllowOverride all Order allow,deny allow from all AuthName "GitList" AuthType Basic AuthBasicProvider ldap AuthLDAPURL ldap://ldap.example.com/dc=example,dc=com?uid AuthLDAPGroupAttribute memberUid AuthLDAPGroupAttributeIsDN off Require ldap-group cn=git,ou=Group,dc=example,dc=com </Directory> </VirtualHost> # Upstep to SSL <Virtualhost *:80> ServerAdmin admin@mtak.nl ServerName git.example.com Redirect 301 / https://git.example.com/ </VirtualHost>
Read-only HTTP clones
As a mechanism to deploy software, it might come in handy to have read-only access to the repository for certain servers. I use this mechanism to deploy Puppet code accross the network.
-
Set up Apache HTTPd with the appropriate config:
Alias "/puppet-readonly.git" "/srv/git/puppet.git/" <Directory /srv/git/puppet.git/> AuthName "Puppet git repository" AuthType Basic AuthUserFile /etc/apache2/puppet.git.htpasswd Require valid-user </Directory>
-
Create a
.htpasswd
file for authenticationhtpasswd -c /etc/apache2/puppet.git.htpasswd user1
-
When Git clones or pulls a repository over SSH, it discovers references and packs dynamically. This cannot be done over HTTP, so you need to make sure a list up these is updated every time you push changes to the repository. This can be automated by using Git hooks. Uncomment the
exec git update-server-info
line in the repository’shooks/post-update.sample
file and rename it tohooks/post-update
less /srv/git/puppet/hooks/post-update #!/bin/sh # # An example hook script to prepare a packed repository for use over # dumb transports. # # To enable this hook, rename this file to "post-update". exec git update-server-info
-
Push a change to the repository to check if the Git hook works.
update-server-info
should change the following files in the repository:objects/info/packs info/refs
-
Access the Git repository through the following url:
git clone https://user1:[email protected]/puppet-readonly.git