The Shed


Installing stagit on OpenBSD

This blog-post is, more or less, a copy and paste of this wonderful blog-post by poptart. This serves as a reference for myself, when I inevitably forget where I put all my config files. I do show a couple of things the original post did not, and I also explain how I set it up with my config, which is running httpd and relayd.

Setting up stagit

Firstly, we install the stagit package.

          
          $ pkg_add stagit
          
          

Then, we create the new user and group. The _git user will have its home directory at /var/git/repos .

        
        $ groupadd -g 998 _git
        $ mkdir -p -m 774 /var/git/repos
        $ mkdir -p -m 774 /var/git/repos/template
        $ useradd -u 998 -g 998 -L daemon -c "git backend user" -d /var/git/repos \
        -s /usr/local/bin/git-shell _git
        $ chown _git:_git /var/git/repos
        
        

Now, we will set up ssh for our new _git user. We create the .ssh folder and set up permissions. I chose to simply copy the public key I had already configured from an existing user.

          
          $ mkdir -m 700 /var/git/repos
          $ cp ~/.ssh/authorized_keys /var/git/repos
          $ chmod 600 /var/git/repos/authorized_keys
          
          

We will set up a global config file, where we define some constants, which will make our set up easier to configure later on. We create the file /var/git/config.rc with the content:

        
        GIT_HOME="/var/git/repos"
        WWW_HOME="/var/www/htdocs/git.example.com"
        CLONE_URI="_git@git.example.com"
        DEFAULT_OWNER="youruser"
        DEFAULT_DESCRIPTION="default description"
        GIT_USER="_git"
        
        
We now change the owner of the config file to root.
        
          $ chown root:wheel /var/git/config.rc
        
        

We now make a post-receive hook. This will update our repository every time a push is made. Create this file in /var/git/repos/template/post-receive, if that's where you put the tempalte directory.

        
        #!/bin/sh
        # Author: Cale "poptart" Black
        # License: MIT

        set -euf

        . /var/git/config.rc

        export LC_CTYPE='en_US.UTF-8'
        src="$(pwd)"
        name=$(basename "$src")
        dst="$WWW_HOME/$(basename "$name" '.git')"
        mkdir -p "$dst"
        cd "$dst" || exit 1

        echo "[stagit] building $dst"
        /usr/local/bin/stagit "$src"

        echo "[stagit] linking $dst"
        ln -sf log.html index.html
        ln -sf ../style.css style.css
        ln -sf ../logo.png logo.png
        
        
The script needs to be made executable.
        
        $ chmod +x /var/git/repos/template/post-receive
        
        

This script will generate the index file, which we use to browse all of our different repositories. Save it as /usr/local/bin/stagit-gen-index

        
        #!/bin/sh 
        # Author: Cale "poptart" Black
        # License: MIT

        set -eu

        . /var/git/config.rc
        stagit-index "$GIT_HOME"/*.git > "$WWW_HOME/index.html"
        
        

This final script will create a new, empty repository. Save it as /usr/local/bin/stagit-newrepo

        
        #!/bin/sh
        # Author: Cale "poptart" Black
        # License: MIT

        set -eu

        . /var/git/config.rc

        e_log() {
            printf '%s\n' "$*"
        }

        e_err() {
            printf '%s\n' "$*" >&2
        }

        e_exit() {
            e_err "$*"
            exit 1
        }

        DESC=""
        REPO=""

        if [ $# -gt 1 ]; then
                DESC="$2"
        else
                DESC="$DEFAULT_DESCRIPTION"
        fi

        if [ $# -eq 0 ]; then
                e_exit "not enough args"
        else
                REPO="$(basename "$1")"
        fi

        git init --bare "$GIT_HOME/$REPO.git"
        cp "$GIT_HOME/template/post-receive" "$GIT_HOME/$REPO.git/hooks/post-receive"
        echo "$CLONE_URI/$REPO.git" > "$GIT_HOME/$REPO.git/url"
        echo "$DEFAULT_OWNER" > "$GIT_HOME/$REPO.git/owner"
        if [ -n "$DESC" ]; then
                echo "$DESC" > "$GIT_HOME/$REPO.git/description"
        else
                echo "this is a placeholder" > "$GIT_HOME/$REPO.git/description"
         fi
        chmod u+x "$GIT_HOME/$REPO.git/hooks/post-receive"
        mkdir "$WWW_HOME/$REPO"
        /usr/local/bin/stagit-gen-index
        
        
The permissions for these scripts are set.
        
        $ chmod +x /usr/local/bin/stagit-newrepo
        $ chmod +x /var/git/repos/template
        $ chown _git:_git /var/www/htdocs/git
        
        

To be able to run these scripts as the git user, we will add these lines to /etc/doas.conf. They will allow any user in the gitadmins group to execute these scripts.

          
          permit nopass :gitadmins as _git cmd /usr/local/bin/stagit-newrepo
          permit nopass :gitadmins as _git cmd /usr/local/bin/stagit-gen-index
          
          
Alternatively, if we just want out user to be able to run the script, we can instead add these lines.
          
          permit nopass youruser as _git cmd /usr/local/bin/stagit-newrepo
          permit nopass youruser as _git cmd /usr/local/bin/stagit-gen-index
          
          

Configuring httpd and relayd

It is now time to configure httpd and relayd. Firstly, to see how to set up httpd and relayd to handle subdomains and use TLS, see this lovely article by adyxax. I have a couple different web servers running, all served by httpd using relayd. To show how this is set up, I have an example here with the git server running on port 8081 with the address git.example.com and another service on port 8080 with the address example.com. This is the content of /etc/relayd.conf:

        
        table  { 127.0.0.1 }
        table  { 127.0.0.1 }

        http protocol "wwwsecure" {
        tls keypair "example.com"

        return error

        ...
        (lots of header configs)
        ...

        pass request quick header "Host" value "example.com" forward to 
        pass request quick header "Host" value "git.example.com" forward to 
        }

        relay "wwwsecure" {
        listen on 0.0.0.0 port 443 tls
        protocol wwwsecure
        forward to  port 8080
        forward to  port 8081
        }
        
        

Finally, this is how /etc/httpd.conf is configured for these different services.

        
        server "example.com" {
        listen on * port 80
        alias "www.example.com"
        alias "git.example.com"
        location "/.well-known/acme-challenge/*" {
                root "/acme"
                request strip 2
        }
        location * {
                block return 301 "https://$HTTP_HOST$REQUEST_URI"
        }
        }

        server "example.com" {
            listen on * port 8080
            location * {
                    root "/htdocs/example.com/"
            }
        }

        server "git.example.com" {
            listen on * port 8081
            location * {
                    root "/htdocs/git.example.com/"
            }
        }
        
        

Now, just restart httpd and relayd and test it out.