git-selfhost

Self-hosted git server with auto-regenerating static stagit frontend
git clone git://git.deurzen.net/git-selfhost.git
Log | Files | Refs | README

commit e9161791555dd2c8105fe0561e66bb05a46a8e75
Author: deurzen <max@deurzen.net>
Date:   Tue, 24 May 2022 22:41:43 +0200

initial commit

Diffstat:
Afavicon.png | 0
Agenerate.sh | 25+++++++++++++++++++++++++
Agit-daemon.service | 24++++++++++++++++++++++++
Alogo.png | 0
Anew-repo | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anginx.conf | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apost-receive | 32++++++++++++++++++++++++++++++++
Astyle.css | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 425 insertions(+), 0 deletions(-)

diff --git a/favicon.png b/favicon.png Binary files differ. diff --git a/generate.sh b/generate.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +GITDIR="/srv/git" +WEBDIR="/var/www/html" + +stagit-index "${GITDIR}/"*/ > "${WEBDIR}/index.html" + +# make files per repo +for repo in "${GITDIR}/"*/; do + # strip .git suffix + REPO_DIR=$(basename "${repo}") + REPO_NAME=$(basename "${repo}" ".git") + printf "%s... " "${REPO_NAME}" + + mkdir -p "${WEBDIR}/${REPO_NAME}" + cd "${WEBDIR}/${REPO_NAME}" || continue + stagit -c ".cache" "${GITDIR}/${REPO_DIR}" + + ln -sf log.html index.html + ln -sf ../style.css style.css + ln -sf ../logo.png logo.png + ln -sf ../favicon.png favicon.png + + echo "done" +done diff --git a/git-daemon.service b/git-daemon.service @@ -0,0 +1,24 @@ +# https://git-scm.com/book/en/v2/Git-on-the-Server-Git-Daemon +# at: /etc/systemd/system/git-daemon.service +# +# systemctl enable --now git-daemon +# + +[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 diff --git a/logo.png b/logo.png Binary files differ. diff --git a/new-repo b/new-repo @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +set -Eeo pipefail + +DOMAIN="git.mydomain.net" +OWNER="<owner name>" + +if ! [ $# -eq 3 ]; then + >&2 echo "invalid number of arguments" + echo "new-repo: add a new git repo" + echo "usage: new-repo <private|public> <name> <description>" + exit 1 +fi + +if [[ "$1" == "private" ]]; then + PRIVATE=1 + unset PUBLIC +elif [[ "$1" == "public" ]]; then + PUBLIC=1 +else + >&2 echo "invalid first argument: $1" + echo "new-repo: add a new git repo" + echo "usage: new-repo <private|public> <name> <description>" + exit 1 +fi +shift + +NAME="$1" +shift + +DESCRIPTION="$@" + +while (( "$#" )); do + case "$1" in + -h|--help) + echo "new-repo: add a new git repo" + echo "usage: new-repo <private|public> <name> <description>" + exit + ;; + -*|--*=) + >&2 echo "new-repo: invalid option $1" + exit 1 + ;; + *) + shift + ;; + esac +done + +sudo su git -s /bin/bash <<EOF +mkdir /srv/git/${NAME}.git && cd /srv/git/${NAME}.git && git init --bare +test $PUBLIC && touch /srv/git/${NAME}.git/git-daemon-export-ok +echo "$DESCRIPTION" >| /srv/git/${NAME}.git/description +echo "$OWNER" >| /srv/git/${NAME}.git/owner +echo "git://${DOMAIN}/${NAME}.git" >| /srv/git/${NAME}.git/url +cp ~/post-receive /srv/git/${NAME}.git/hooks/post-receive +echo "" +echo "generating static pages" +cd /var/www/html && ./generate.sh +echo "" +echo "push to: ${DOMAIN}:/srv/git/${NAME}.git" +echo "config:" +echo '[remote "self"]' +echo " url = self1:/srv/git/${NAME}.git" +echo ' fetch = +refs/heads/*:refs/remotes/self/*' +echo "" +echo "pull from: git@${DOMAIN}/${NAME}.git" +EOF diff --git a/nginx.conf b/nginx.conf @@ -0,0 +1,85 @@ +user www-data; +worker_processes auto; +pid /run/nginx.pid; +include /etc/nginx/modules-enabled/*.conf; + +events { + worker_connections 768; + # multi_accept on; +} + +http { + + ## + # Basic Settings + ## + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + # server_tokens off; + + # server_names_hash_bucket_size 64; + # server_name_in_redirect off; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ## + # SSL Settings + ## + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE + ssl_prefer_server_ciphers on; + + ## + # Logging Settings + ## + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + ## + # Gzip Settings + ## + + gzip on; + + # gzip_vary on; + # gzip_proxied any; + # gzip_comp_level 6; + # gzip_buffers 16 8k; + # gzip_http_version 1.1; + # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + ## + # Virtual Host Configs + ## + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} + + +#mail { +# # See sample authentication script at: +# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript +# +# # auth_http localhost/auth.php; +# # pop3_capabilities "TOP" "USER"; +# # imap_capabilities "IMAP4rev1" "UIDPLUS"; +# +# server { +# listen localhost:110; +# protocol pop3; +# proxy on; +# } +# +# server { +# listen localhost:143; +# protocol imap; +# proxy on; +# } +#} diff --git a/post-receive b/post-receive @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +if [ $(git rev-parse --is-bare-repository) = true ]; then + REPOSITORY_BASENAME=$(basename "$PWD") +else + REPOSITORY_BASENAME=$(basename $(readlink -nf "$PWD"/..)) +fi + +REPOSITORY_NAME=${REPOSITORY_BASENAME%.git} + +GITDIR="/srv/git" +WEBDIR="/var/www/html" + +FORCE=0 +while read -r old new ref; do + HASREVS=$(git rev-list "$old" "^$new" | sed 1q) + if test -n "$HASREVS"; then + FORCE=1 + break + fi +done + +if test "$FORCE" = "1"; then + rm -rf "${WEBDIR}/${REPOSITORY_NAME}" +fi + +cd /var/www/html || exit 1 + +echo '' +echo 'generating static pages' +./generate.sh +echo '' diff --git a/style.css b/style.css @@ -0,0 +1,192 @@ +body { + color: #000; + background-color: #fff; + font-family: monospace; +} + +h1, h2, h3, h4, h5, h6 { + font-size: 1em; + margin: 0; +} + +img, h1, h2 { + vertical-align: middle; +} + +img { + border: 0; +} + +a:target { + background-color: #ccc; +} + +a.d, +a.h, +a.i, +a.line { + text-decoration: none; +} + +#blob a { + color: #555; +} + +#blob a:hover { + color: blue; + text-decoration: none; +} + +#index { + table-layout: fixed; +} + +table thead td { + font-weight: bold; +} + +table td { + padding: 0 0.4em; +} + +#content table td +{ + white-space: nowrap; + vertical-align: top; +} + +#content tbody table td +{ + white-space: nowrap; +} + +#branches tr:hover td, +#tags tr:hover td, +#index tr:hover td, +#log tr:hover td, +#files tr:hover td { + background-color: #eee; +} + +#index tr td:nth-child(2), +#tags tr td:nth-child(3), +#branches tr td:nth-child(3), +#log tr td:nth-child(2) { + white-space: normal; +} + +td.num { + text-align: right; +} + +.desc { + color: #555; +} + +hr { + border: 0; + border-top: 1px solid #555; + height: 1px; +} + +pre { + font-family: monospace; +} + +pre a.h { + color: #00a; +} + +.A, +span.i, +pre a.i { + color: #070; +} + +.D, +span.d, +pre a.d { + color: #e00; +} + +pre a.h:hover, +pre a.i:hover, +pre a.d:hover { + text-decoration: none; +} + +@media (max-width: 768px) { + #content { + width: 100%; + overflow-x: auto; + -ms-overflow-style: -ms-autohiding-scrollbar; + padding-bottom: 8px; + } + + #tags tr td:nth-child(3), + #branches tr td:nth-child(3), + #log tr td:nth-child(2) { + white-space: nowrap; + } + + #index tr td:nth-child(2) { + min-width: 300px; + } + + #index { + border-collapse: collapse; + } + + #index tbody td { + padding-top: .5em; + padding-bottom: .5em; + } +} + +@media (prefers-color-scheme: dark) { + body { + background-color: #000; + color: #bdbdbd; + } + hr { + border-color: #222; + } + a { + color: #56c8ff; + } + a:target { + background-color: #222; + } + .desc { + color: #aaa; + } + #blob a { + color: #555; + } + #blob a:target { + color: #eee; + } + #blob a:hover { + color: #56c8ff; + } + pre a.h { + color: #00cdcd; + } + .A, + span.i, + pre a.i { + color: #00cd00; + } + .D, + span.d, + pre a.d { + color: #cd0000; + } + #branches tr:hover td, + #tags tr:hover td, + #index tr:hover td, + #log tr:hover td, + #files tr:hover td { + background-color: #111; + } +}