# How to make a git server/website ## Basic ssh server Every repository on the server will be owned by a git user. ```sh useradd -m git ``` Create a new directory to store the repositories owned by the git user. ```sh mkdir /srv/git chown git:git /srv/git ``` Login as the git user so the new repositories will be owned by him. ```sh su git cd /srv/git ``` ### Creating a repository They will be stored as bare, meaning we will only store the `.git` folder not the actual files (called the *workspace*) to save space. It's a convention to to suffix a bare repository with the `.git` extension. ```sh mkdir repo.git cd repo.git git init --bare ``` Or clone a distant one: ```sh git clone --bare ``` > Look at the content of a bare repository and the `.git` directory in a regular one > to convince yourself that they're the same. ### SSH Authentication You could add a password for the git user but it's ultimately safer to user a key pair. If you don't know what that is you generate it with `ssh-keygen`. Follow the steps and it will create `id_rsa` (private key) and `id_rsa.pub` (public key) in `~/.ssh`. On your server you append your **public** key to `/home/git/.ssh/authorized_keys` At this point you should be able to login as the git user via ssh ```sh ssh git@ ``` You can clone from your server. ```sh git clone git@:/srv/git/.git ``` ## Better server interaction with git-shell Permitting the git user to have a regular shell can be too permissive, we would like to restrict him to a few repository actions, like creation/deletion, importing (clone), listing. ``` sh echo $(which git-shell) >> /etc/shells` # Register the git-shell as a valid shell chsh -s $(which git-shell) git # Change the shell of the git user ``` If you try to ssh as the git user, you will be greeted with something along the line of: ``` fatal: Interactive git shell is not enabled. hint: ~/git-shell-commands should exist and have read and execute access. Connection to closed. ``` As suggested by the hint we have to create the directory `/home/git/git-shell-commands` and put the commands (executable) available to the git user. ```sh #!/bin/sh [ $# -ne 1 ] && echo "Usage: $0 repository" && exit 1 repo_path="/srv/git/$1.git" [ -d "$repo_path" ] && echo "$0: Error: $repo_path already exist" && exit 2 mkdir "$repo_path" git -C "$repo_path" init --bare ``` This script create a new repository in `/srv/git`. Put it under `git-shell-commands/create` and make it executable then try to ssh as the git user once again. You will be prompted with `git> `, you can only execute the `create ` and `exit` command. > You can probably create the `delete`, `import` and `list` scripts yourself. > If you add a `help` script, it will be ran at the beginning of the connection. > It can be used to add a greeting message. ## Allow anyone to clone with git-daemon Cloning with ssh is fine but only the people with ssh access can do it, we would like anyone to clone. git-daemon does precisely that, after running it you will be able to run `git clone git:///` ```sh git daemon --reuseaddr --base-path=/srv/git/ /srv/git/ ``` Follow the instruction of [this](https://git-scm.com/book/en/v2/Git-on-the-Server-Git-Daemon) tutorial if you want to know how to make it a service ### Public/private repository You may want to introduce a public/private distinction for your repositories. A simple way to do this is by creating a `public` directory in `/srv/git` which will contain symbolic link to the repository in `/srv/git`. ``` /srv/git/ |- foo.git/ |- bar.git/ |- qux.git/ |- public/ |- foo.git -> /srv/git/foo.git |- bar.git -> /srv/git/bar.git ``` > Change the git daemon to only serve the public repositories > `git daemon --reuseaddr --base-path=/srv/git/public /srv/git/public`. > Add a `publish` and `unpublish` script in `git-shell-commands/`. ## Generate a static website Here we will create a site that look's like [this](https://git.suckless.org) with [nginx](https://nginx.org), [stagit](https://git.codemadness.org/stagit/) and a few scripts. If you don't like the minimalist appearance of the site, [here](https://git.wiki.kernel.org/index.php/Interfaces,_frontends,_and_tools#Web_Interfaces) is a list of alternatives. ### nginx ``` server { root /var/www/git; # where our website's files will be located index index.html; # It's a convention to put it in a git. subdomain. server_name git. www.git.; location / { try_files $uri $uri/ =404; } } ``` Put this configuration file in `/etc/nginx/sites-available`. Enable the site `ln -s /etc/nginx/sites-available /etc/nginx/sites-enable` ### stagit Stagit is pretty small tool so it won't take long to install it from sources. ``` git clone git://git.codemadness.org/stagit cd stagit make make install ``` * `stagit /path/to/repository`. - generate a static pages for a repository in the current directory. * `stagit-index repo1 repo2 repo3 > index.html` - generate an index for multiple repositories. > Read the man page of both of these commands for more information #### git hooks Git hooks are scripts located in `/.git/hooks` that will be run on a certain action. The hook we're interested in is `post-receive`, it will be ran after someone pushes to the repository. We can use it to regenerate the repository's pages and the website's index. ```sh #!/bin/sh # Insert repo_name variable here # -- replace with repo_name=name [ -z "$repo_name" ] && exit 1 [ ! -d "/srv/git/public/$repo_name.git" ] && exit repo_web_path="/var/www/git/$repo_name" mkdir -p "$repo_web_path" cd "$repo_web_path" || exit 1 stagit "/srv/git/$repo_name.git" stagit-index /srv/git/public/* > /var/www/git/index.html ``` This is a template for the `post-receive` hook. Every time you publish a repository you can change his `post-receive` hook. ```sh post_receive_path="/hooks/post-receive" sed '/REPO_NAME/ c repo_name='"$repo" < post-receive.template > "$post_receive_path" chmod +x "$post_receive_path" "$post_receive_path" ``` > Add this code to your `publish` script ## Sources * [Setting up \*Your Own\* Git Server](https://www.youtube.com/watch?v=ju9loeXNVW0) * [Git book - setting up the server](https://git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server) * [Git book - git daemon](https://git-scm.com/book/en/v2/Git-on-the-Server-Git-Daemon) * [stagit README](https://git.codemadness.org/stagit/file/README.html) * [git-shell man](https://git-scm.com/docs/git-shell.html)