# How to make your own git server/website ## Server setup We're going to create a `git` user and group, will be used for accessing our git repositories without needing to be root. ```sh useradd -m git mkdir /srv/git chown git:git /srv/git ``` The repositories will be stored as bare, this mean that we will only store the `.git` folder to save space. >To create a bare repo: `git init --bare` >To clone a repo as bare: `git clone bare ` You can either add a password for the git user or put your ssh public key in `/home/git/.ssh/authentication_keys` and disable password authentication for ssh. You can now clone from your server with `git clone git@:/srv/git/` ## Better server interaction with git-shell Permit the git user to have a regular shell can be a security issue, we would like that to restrict him to a few action, like creating/deleting a repository, importing a repository, listing the repo currently stored Make the git-shell a valid shell `echo $(which git-shell) >> /etc/shells` Change the shell of the git user `chsh -s $(which git-shell) git` 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) that the git user is allowed to execute in. Here is a script to create a repo: ```sh #!/bin/sh [ $# -ne 1 ] && echo "Usage: $0 name" && 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 ``` Put it under `git-shell-commands/create` and make it executable then try to ssh as the git user once again. You should have a prompt like `git> `, you can call the `create` command with a repo name as the first argument and it should create a new repository for you. ## Allow anyone to clone with git-daemon The git daemon will allow annone to clone your repos with something like `git clone git:///` `git daemon --reuseaddr --base-path=/srv/git/ /srv/git/` and that's it You should make it a service in your service supervisor, example with systemctl: ``` [Unit] Description=Start Git Daemon [Service] ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/srv/git/ /srv/git/ Restart=always RestartSec=500ms StandardOutput=syslog StandardError=syslog SyslogIdentifier=git-daemon User=git Group=git [Install] WantedBy=multi-user.target ``` Put it in `/etc/systemctl/system/git-daemon.service` and run `systemctl enable git-daemon` then `systemctl start git-daemon`. ### Public/private repo You may want to introduce a distiction of which repo is public and which is private A simple way to do this is by creating a `public` directory in `/srv/git` which will contain symbolic link to the repo in `/srv/git` ``` /srv/git |- foo.git |- bar.git |- qux.git |- public |- foo.git -> /srv/git/foo.git |- bar.git -> /srv/git/bar.git ``` You can change the git daemon to only serve the public repositories `git daemon --reuseaddr --base-path=/srv/git/public /srv/git/public` ## 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 minimalistic appearence of the site, [here](https://git.wiki.kernel.org/index.php/Interfaces,_frontends,_and_tools#Web_Interfaces) is a list of alternative. Install nginx (on Debian based distro): `apt install nginx` Create a basic configuration file for your site: ``` server { root /var/www/git; index index.html index.htm; server_name git. www.git.; location / { try_files $uri $uri/ =404; } } ``` It's a convention to put it in a `git.` subdomain. `systemctl enable nginx && systemctl start nginx` Install stagit: ``` git clone git://git.codemadness.org/stagit cd stagit make make install ``` To generate a static page for a repo `stagit /path/to/repo`. To generate an index for multiple repositories `stagit-index repo1 repo2 repo3 > index.html` Here is a script to generate a site for all repo in `/srv/git/public` ```sh #!/bin/sh repos=$(find /srv/git/public/ -type l) current=$(pwd) for repo in $repos; do repo_name=$(basename "$repo" | sed 's/\.git//') repo_static_path="/var/www/git/$repo_name" mkdir -p "$repo_static_path" cd "$repo_static_path" || exit 1 echo "git://cacharle.xyz/$repo_name" > "$repo/url" stagit "$repo" ln -sf "$repo_static_path/log.html" "$repo_static_path/index.html" echo "Generated $repo_static_path" done echo "Creating index" stagit-index $repos > /var/www/git/index.html cd "$current" || exit 1 chown -R git:git /srv/git ``` There is more smart ways to handle this to rebuild the webpages each time someone pushes to the repo with [git hooks](https://git.codemadness.org/stagit/file/README.html#l92). ## 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 - Static website generator for git repository](https://git.codemadness.org/stagit/) * [git-shell man](https://git-scm.com/docs/git-shell.html)