commit 2f3f377efaa4ebd1c37be9a52333ea7adc34f57a
parent 263db88c61de2ed322c8e211046eac864977acbe
Author: awy <awy@awy.one>
Date: Sun, 26 Apr 2026 18:08:39 +0300
docker
Diffstat:
10 files changed, 366 insertions(+), 0 deletions(-)
diff --git a/Dockerfile b/Dockerfile
@@ -0,0 +1,85 @@
+FROM alpine:latest AS build
+
+RUN apk add --no-cache \
+ build-base \
+ git \
+ go \
+ libgit2-dev \
+ md4c-dev
+
+RUN git clone https://github.com/alecthomas/chroma /tmp/chroma && \
+ cd /tmp/chroma && \
+ git checkout v2.14.0 && \
+ cd cmd/chroma && \
+ CGO_ENABLED=0 go build -o /tmp/install/usr/local/bin/chroma-v2 .
+
+RUN git clone https://codeberg.org/awy/stagit /tmp/stagit && \
+ cd /tmp/stagit && \
+ make CFLAGS="-O2" && \
+ make install DESTDIR=/tmp/install
+
+FROM alpine:latest
+
+RUN apk add --no-cache \
+ git \
+ git-daemon \
+ openssh-server \
+ libgit2 \
+ md4c \
+ fcgiwrap \
+ nginx \
+ spawn-fcgi \
+ su-exec \
+ ca-certificates
+
+RUN addgroup -S git && \
+ adduser -S -G git -h /home/git -s /usr/bin/git-shell git && \
+ sed -i 's/^git:!:/git:*:/' /etc/shadow
+
+RUN mkdir -p /home/git/.ssh && \
+ mkdir -p /home/git/git-shell-commands && \
+ chmod 700 /home/git/.ssh
+
+RUN mkdir -p /home/git/hooks
+COPY docker/git-scripts/create /home/git/git-shell-commands
+COPY docker/git-scripts/rebuild /home/git/git-shell-commands
+RUN chown -R git:git /home/git
+
+COPY --from=build /tmp/install/usr/local/bin/stagit /usr/local/bin/stagit
+COPY --from=build /tmp/install/usr/local/bin/stagit-index /usr/local/bin/stagit-index
+COPY --from=build /tmp/install/usr/local/bin/stagit-gen-index /usr/local/bin/stagit-gen-index
+COPY --from=build /tmp/install/usr/local/bin/stagit-newrepo /usr/local/bin/stagit-newrepo
+COPY --from=build /tmp/install/usr/local/bin/stagit-rebuild-all /usr/local/bin/stagit-rebuild-all
+COPY --from=build /tmp/install/usr/local/bin/chroma-v2 /usr/local/bin/chroma-v2
+COPY docker/sshd_config /etc/ssh/sshd_config
+
+RUN mkdir -p \
+ /srv/git/repos \
+ /srv/git/repos/template \
+ /var/www/git \
+ /run/nginx \
+ /run/fcgiwrap && \
+ chown -R git:git /srv/git /var/www/git /run/fcgiwrap && \
+ chmod +x \
+ /usr/local/bin/stagit \
+ /usr/local/bin/stagit-index \
+ /usr/local/bin/stagit-gen-index \
+ /usr/local/bin/stagit-newrepo \
+ /usr/local/bin/stagit-rebuild-all \
+ /usr/local/bin/chroma-v2
+
+COPY docker/config.rc /home/git/config.rc
+COPY docker/post-receive /home/git/hooks/post-receive
+COPY docker/nginx.conf /etc/nginx/http.d/default.conf
+COPY docker/entrypoint.sh /entrypoint.sh
+COPY docker/style.css /var/www/git/style.css
+
+RUN chown git:git \
+ /home/git/config.rc \
+ /var/www/git/style.css && \
+ chmod +x \
+ /entrypoint.sh
+
+EXPOSE 80
+
+CMD ["/entrypoint.sh"]
diff --git a/docker-compose.yml b/docker-compose.yml
@@ -0,0 +1,12 @@
+services:
+ stagit:
+ image: stagit:latest
+ container_name: stagit
+ restart: unless-stopped
+ ports:
+ - "2222:22"
+ volumes:
+ - ./repos:/srv/git
+ - ./www:/var/www/git
+ - ./ssh/authorized_keys:/home/git/.ssh/authorized_keys
+ - ./ssh/hostkeys:/etc/ssh/hostkeys
diff --git a/docker/config.rc b/docker/config.rc
@@ -0,0 +1,6 @@
+GIT_HOME="/srv/git"
+WWW_HOME="/var/www/git"
+CLONE_URI="https://git.example.com"
+DEFAULT_OWNER="cat"
+DEFAULT_DESCRIPTION="description"
+GIT_USER="git"
diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+set -eu
+
+mkdir -p /run/nginx /run/fcgiwrap /run/sshd /etc/ssh/hostkeys
+chown -R git:git /run/fcgiwrap
+chown -R git:git /srv/git
+chown -R git:git /var/www/git
+chown -R git:git /home/git/.ssh
+
+# Generate persistent SSH host keys only once
+if [ ! -f /etc/ssh/hostkeys/ssh_host_ed25519_key ]; then
+ ssh-keygen -t ed25519 -f /etc/ssh/hostkeys/ssh_host_ed25519_key -N ''
+fi
+
+if [ ! -f /etc/ssh/hostkeys/ssh_host_rsa_key ]; then
+ ssh-keygen -t rsa -b 4096 -f /etc/ssh/hostkeys/ssh_host_rsa_key -N ''
+fi
+
+chmod 700 /home/git/.ssh
+chmod 600 /home/git/.ssh/authorized_keys
+chmod 600 /etc/ssh/hostkeys/ssh_host_*_key
+chmod 644 /etc/ssh/hostkeys/ssh_host_*_key.pub
+
+spawn-fcgi \
+ -s /run/fcgiwrap/fcgiwrap.sock \
+ -U nginx \
+ -G nginx \
+ -u git \
+ -g git \
+ -- /usr/bin/fcgiwrap
+
+su-exec git:git stagit-rebuild-all
+
+/usr/sbin/sshd
+
+nginx -g 'daemon off;'
diff --git a/docker/git-scripts/create b/docker/git-scripts/create
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+stagit-newrepo "$1" "$2" "$3"
diff --git a/docker/git-scripts/rebuild b/docker/git-scripts/rebuild
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+stagit-rebuild-all
diff --git a/docker/nginx.conf b/docker/nginx.conf
@@ -0,0 +1,24 @@
+server {
+ listen 80 default_server;
+ listen [::]:80 default_server;
+
+ server_name _;
+
+ root /var/www/git;
+ index index.html;
+
+ location / {
+ try_files $uri $uri/ =404;
+ }
+
+ # clone by http
+ location ~ /.+/(info/refs|git-upload-pack) {
+ include fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend;
+ fastcgi_param PATH_INFO $uri;
+ fastcgi_param GIT_HTTP_EXPORT_ALL "";
+ fastcgi_param GIT_PROJECT_ROOT /srv/git;
+ fastcgi_param HOME /srv/git;
+ fastcgi_pass unix:/run/fcgiwrap/fcgiwrap.sock;
+ }
+}
diff --git a/docker/post-receive b/docker/post-receive
@@ -0,0 +1,20 @@
+#!/bin/sh
+# Author: Cale "poptart" Black
+# License: MIT
+
+set -euf
+. /home/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
+echo "[stagit] updating index"
+/usr/local/bin/stagit-gen-index
diff --git a/docker/sshd_config b/docker/sshd_config
@@ -0,0 +1,14 @@
+Port 22
+HostKey /etc/ssh/hostkeys/ssh_host_ed25519_key
+HostKey /etc/ssh/hostkeys/ssh_host_rsa_key
+PermitRootLogin no
+PubkeyAuthentication yes
+PasswordAuthentication no
+KbdInteractiveAuthentication no
+X11Forwarding no
+PrintMotd no
+AcceptEnv LANG LC_* COLORTERM NO_COLOR
+Subsystem sftp /usr/lib/openssh/sftp-server
+ClientAliveInterval 120
+AllowUsers git
+AuthorizedKeysFile .ssh/authorized_keys
diff --git a/docker/style.css b/docker/style.css
@@ -0,0 +1,163 @@
+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;
+}
+
+a:target {
+ background-color: #ccc;
+}
+
+img {
+ border: 0;
+}
+
+a.d,
+a.h,
+a.i,
+a.line {
+ text-decoration: none;
+}
+
+/*
+a {
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}*/
+
+#blob a {
+ color: #777;
+}
+
+#blob a:hover {
+ color: blue;
+ text-decoration: none;
+}
+
+table thead td {
+ font-weight: bold;
+}
+
+table td {
+ padding: 0 0.4em;
+}
+
+#content table td {
+ vertical-align: top;
+ 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: #777;
+}
+
+hr {
+ border: 0;
+ border-top: 1px solid #777;
+ 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 (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;
+ }
+}