From ac89b3c715fd3eddca7898e069ee04498c1a1ba2 Mon Sep 17 00:00:00 2001 From: Jesper Jensen Date: Fri, 24 Apr 2026 23:36:52 +0200 Subject: INITIAL COMMIT --- .dockerignore | 2 ++ Dockerfile | 45 +++++++++++++++++++++++++++++++++++++++++++++ auth.conf | 10 ++++++++++ cgitrc | 18 ++++++++++++++++++ create-repo.sh | 43 +++++++++++++++++++++++++++++++++++++++++++ entrypoint.sh | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ git-http-backend.cgi | 8 ++++++++ healthz | 1 + lighttpd.conf | 43 +++++++++++++++++++++++++++++++++++++++++++ sshd_config | 17 +++++++++++++++++ 10 files changed, 237 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 auth.conf create mode 100644 cgitrc create mode 100644 create-repo.sh create mode 100644 entrypoint.sh create mode 100644 git-http-backend.cgi create mode 100644 healthz create mode 100644 lighttpd.conf create mode 100644 sshd_config diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5dc1898 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +demo/ +.git/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d92efca --- /dev/null +++ b/Dockerfile @@ -0,0 +1,45 @@ +FROM alpine:3.22.4 + +RUN apk add --no-cache \ + cgit \ + git \ + git-daemon \ + lighttpd \ + lighttpd-mod_auth \ + openssh-server \ + tini + +RUN addgroup -g 1000 -S git \ + && adduser -u 1000 -S -D -G git -h /var/lib/git -s /usr/bin/git-shell git \ + && adduser git tty\ + && passwd -u git \ + && mkdir -p \ + /etc/git-host/secrets \ + /usr/local/libexec \ + /var/lib/git \ + /run/git-host/secrets \ + /run/lighttpd \ + /run/sshd \ + /var/tmp/lighttpd \ + /var/www/localhost/htdocs \ + && chown -R git:git /var/lib/git + +COPY entrypoint.sh /usr/local/bin/entrypoint.sh +COPY git-http-backend.cgi /usr/local/libexec/git-http-backend.cgi +COPY create-repo.sh /usr/local/bin/create-repo +COPY sshd_config /etc/ssh/sshd_config +COPY cgitrc /etc/cgitrc +COPY lighttpd.conf /etc/lighttpd/lighttpd.conf +COPY auth.conf /etc/lighttpd/auth.conf +COPY healthz /var/www/localhost/htdocs/healthz + +RUN chmod 0755 /usr/local/bin/entrypoint.sh /usr/local/libexec/git-http-backend.cgi /usr/local/bin/create-repo \ + && chown git:git /var/lib/git /run/lighttpd /var/tmp/lighttpd /var/www/localhost/htdocs \ + && chmod 0755 /run/git-host /run/git-host/secrets \ + && grep -q "^git:" /etc/passwd \ + && lighttpd -tt -f /etc/lighttpd/lighttpd.conf + +EXPOSE 8080 2222 +VOLUME ["/var/lib/git"] + +ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/entrypoint.sh"] diff --git a/auth.conf b/auth.conf new file mode 100644 index 0000000..39c7550 --- /dev/null +++ b/auth.conf @@ -0,0 +1,10 @@ +auth.backend = "htpasswd" +auth.backend.htpasswd.userfile = "/run/git-host/secrets/htpasswd" + +$HTTP["querystring"] =~ "(^|&)service=git-receive-pack(&|$)" { + auth.require = ("" => ("method" => "basic", "realm" => "Git Host", "require" => "valid-user")) +} + +$HTTP["url"] =~ "^/git/.*/git-receive-pack$" { + auth.require = ("" => ("method" => "basic", "realm" => "Git Host", "require" => "valid-user")) +} diff --git a/cgitrc b/cgitrc new file mode 100644 index 0000000..02c5e8e --- /dev/null +++ b/cgitrc @@ -0,0 +1,18 @@ +css=/cgit.css +logo=/cgit.png +favicon=/favicon.ico +scan-path=/var/lib/git +remove-suffix=1 +enable-http-clone=1 +snapshots=tar.gz zip +root-title=Repositories +root-desc=Simple Git host +section-from-path=1 +clone-url=http://$HTTP_HOST/git/%n.git +clone-url=ssh://git@$HTTP_HOST:%n.git +about-filter=/usr/lib/cgit/filters/about-formatting.sh +enable-log-filecount=1 +enable-log-linecount=1 +enable-commit-graph=1 +max-stats=quarter +virtual-root=/cgit/ diff --git a/create-repo.sh b/create-repo.sh new file mode 100644 index 0000000..5bc213a --- /dev/null +++ b/create-repo.sh @@ -0,0 +1,43 @@ +#!/bin/sh +set -eu + +GIT_REPO_ROOT="${GIT_REPO_ROOT:-/var/lib/git}" +GIT_USER="${GIT_USER:-git}" +GIT_GROUP="${GIT_GROUP:-git}" + +usage() { + echo "usage: create-repo [description]" >&2 + echo "example: create-repo myrepo 'My application repository'" >&2 + exit 64 +} + +[ "$#" -ge 1 ] || usage + +name="$1" +description="${2:-Unnamed repository}" + +case "${name}" in + */* | .* | *" "* | *".."* ) + echo "invalid repository name: ${name}" >&2 + exit 64 + ;; +esac + +case "${name}" in + *.git) repo_name="${name}" ;; + *) repo_name="${name}.git" ;; +esac + +repo_path="${GIT_REPO_ROOT}/${repo_name}" + +if [ -e "${repo_path}" ]; then + echo "repository already exists: ${repo_path}" >&2 + exit 1 +fi + +install -d -o "${GIT_USER}" -g "${GIT_GROUP}" "${repo_path}" +git init --bare "${repo_path}" >/dev/null +printf '%s\n' "${description}" > "${repo_path}/description" +chown -R "${GIT_USER}:${GIT_GROUP}" "${repo_path}" + +echo "created ${repo_path}" diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..3737a7e --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,50 @@ +#!/bin/sh +set -Eeuo pipefail + +# Copy over the secrets to fix permissions +mkdir -p /run/git-host/secrets +cp /etc/git-host/secrets/authorized_keys /run/git-host/secrets/authorized_keys +cp /etc/git-host/secrets/htpasswd /run/git-host/secrets/htpasswd +cp /etc/git-host/secrets/ssh_host_ed25519_key /run/git-host/secrets/ssh_host_ed25519_key +cp /etc/git-host/secrets/ssh_host_ed25519_key.pub /run/git-host/secrets/ssh_host_ed25519_key.pub +cp /etc/git-host/secrets/ssh_host_rsa_key /run/git-host/secrets/ssh_host_rsa_key +cp /etc/git-host/secrets/ssh_host_rsa_key.pub /run/git-host/secrets/ssh_host_rsa_key.pub +chown -R root:root /run/git-host/secrets +chown root:git /run/git-host/secrets/authorized_keys +chown root:git /run/git-host/secrets/htpasswd +chown root:root /run/git-host/secrets/ssh_host_ed25519_key +chown root:root /run/git-host/secrets/ssh_host_ed25519_key.pub +chown root:root /run/git-host/secrets/ssh_host_rsa_key +chown root:root /run/git-host/secrets/ssh_host_rsa_key.pub +chmod 0755 /run/git-host /run/git-host/secrets +chmod 0640 /run/git-host/secrets/authorized_keys +chmod 0640 /run/git-host/secrets/htpasswd +chmod 0600 /run/git-host/secrets/ssh_host_ed25519_key +chmod 0644 /run/git-host/secrets/ssh_host_ed25519_key.pub +chmod 0600 /run/git-host/secrets/ssh_host_rsa_key +chmod 0644 /run/git-host/secrets/ssh_host_rsa_key.pub + +# Validate +/usr/sbin/sshd -t -f /etc/ssh/sshd_config +lighttpd -tt -f /etc/lighttpd/lighttpd.conf + +# Start servers +/usr/sbin/sshd -D -e -f /etc/ssh/sshd_config & +sshd_pid=$! + +lighttpd -D -f /etc/lighttpd/lighttpd.conf & +lighttpd_pid=$! + +# Wait for them to end, kill if either does +terminate() { + kill "${sshd_pid}" "${lighttpd_pid}" 2>/dev/null || true +} + +trap terminate INT TERM + +status=0 +wait -n "${sshd_pid}" "${lighttpd_pid}" || status=$? +terminate +wait "${sshd_pid}" 2>/dev/null || true +wait "${lighttpd_pid}" 2>/dev/null || true +exit "${status}" diff --git a/git-http-backend.cgi b/git-http-backend.cgi new file mode 100644 index 0000000..960ebc0 --- /dev/null +++ b/git-http-backend.cgi @@ -0,0 +1,8 @@ +#!/bin/sh +set -eu + +export GIT_PROJECT_ROOT="${GIT_PROJECT_ROOT:-/var/lib/git}" +export GIT_HTTP_EXPORT_ALL="${GIT_HTTP_EXPORT_ALL:-1}" +export HOME="${HOME:-/home/git}" + +exec /usr/libexec/git-core/git-http-backend diff --git a/healthz b/healthz new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/healthz @@ -0,0 +1 @@ +ok diff --git a/lighttpd.conf b/lighttpd.conf new file mode 100644 index 0000000..cd9d562 --- /dev/null +++ b/lighttpd.conf @@ -0,0 +1,43 @@ +server.modules = ( + "mod_alias", + "mod_auth", + "mod_authn_file", + "mod_cgi", + "mod_rewrite", + "mod_setenv" +) + +server.bind = "0.0.0.0" +server.port = 8080 +server.username = "git" +server.groupname = "git" +server.document-root = "/var/www/localhost/htdocs" +server.pid-file = "/run/lighttpd/lighttpd.pid" + +index-file.names = ("index.html") + +alias.url = ( + "/cgit.cgi" => "/usr/share/webapps/cgit/cgit.cgi", + "/cgit.css" => "/usr/share/webapps/cgit/cgit.css", + "/cgit.png" => "/usr/share/webapps/cgit/cgit.png", + "/cgit" => "/usr/share/webapps/cgit/cgit.cgi", + "/favicon.ico" => "/usr/share/webapps/cgit/favicon.ico", + "/robots.txt" => "/usr/share/webapps/cgit/robots.txt", + "/git" => "/usr/local/libexec/git-http-backend.cgi" +) + +url.rewrite-once = ( + "^/$" => "/cgit" +) + +cgi.assign = ( + ".cgi" => "" +) + +setenv.add-environment = ( + "CGIT_CONFIG" => "/etc/cgitrc", + "GIT_PROJECT_ROOT" => "/var/lib/git", + "GIT_HTTP_EXPORT_ALL" => "1" +) + +include "/etc/lighttpd/auth.conf" diff --git a/sshd_config b/sshd_config new file mode 100644 index 0000000..3b5c369 --- /dev/null +++ b/sshd_config @@ -0,0 +1,17 @@ +Port 2222 +ListenAddress 0.0.0.0 +HostKey /run/git-host/secrets/ssh_host_ed25519_key +HostKey /run/git-host/secrets/ssh_host_rsa_key +PidFile /run/sshd/sshd.pid +AuthorizedKeysFile /run/git-host/secrets/authorized_keys +PasswordAuthentication no +KbdInteractiveAuthentication no +ChallengeResponseAuthentication no +PermitRootLogin no +PermitTunnel no +AllowTcpForwarding no +X11Forwarding no +PermitTTY no +PrintMotd no +AllowUsers git +Subsystem sftp internal-sftp -- cgit v1.2.3