diff options
| author | Your Name <you@example.com> | 2025-12-29 18:28:13 +0800 |
|---|---|---|
| committer | Your Name <you@example.com> | 2025-12-29 18:28:13 +0800 |
| commit | 214f4bab8b852e9b66d909bc22e5f9119da7dfb5 (patch) | |
| tree | ee970b0f1738e5e08afe24247305be2defb27735 | |
initial commit
| -rw-r--r-- | Caddyfile | 22 | ||||
| -rw-r--r-- | Dockerfile | 20 | ||||
| -rw-r--r-- | README | 44 | ||||
| -rw-r--r-- | cgitrc.template | 27 | ||||
| -rw-r--r-- | config.env | 16 | ||||
| -rw-r--r-- | entrypoint.sh | 19 | ||||
| -rwxr-xr-x | start_container.sh | 37 |
7 files changed, 185 insertions, 0 deletions
diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..b783e7b --- /dev/null +++ b/Caddyfile | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | {$DOMAIN} { | ||
| 2 | handle {$CGIT_CSS} { | ||
| 3 | root * /usr/share/webapps/cgit | ||
| 4 | file_server | ||
| 5 | } | ||
| 6 | |||
| 7 | handle {$CGIT_LOGO} { | ||
| 8 | root * /usr/share/webapps/cgit | ||
| 9 | file_server | ||
| 10 | } | ||
| 11 | |||
| 12 | handle { | ||
| 13 | reverse_proxy unix/{$FCGI_SOCK} { | ||
| 14 | transport fastcgi { | ||
| 15 | env SCRIPT_FILENAME /usr/share/webapps/cgit/cgit.cgi | ||
| 16 | env QUERY_STRING {query} | ||
| 17 | env HTTP_HOST {host} | ||
| 18 | env PATH_INFO {path} | ||
| 19 | } | ||
| 20 | } | ||
| 21 | } | ||
| 22 | } | ||
diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..35208e9 --- /dev/null +++ b/Dockerfile | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | FROM alpine:latest | ||
| 2 | |||
| 3 | RUN apk add --no-cache \ | ||
| 4 | caddy \ | ||
| 5 | cgit \ | ||
| 6 | git \ | ||
| 7 | fcgiwrap \ | ||
| 8 | spawn-fcgi \ | ||
| 9 | gettext \ | ||
| 10 | openssl | ||
| 11 | |||
| 12 | COPY cgitrc.template /etc/cgitrc.template | ||
| 13 | COPY Caddyfile /etc/caddy/Caddyfile | ||
| 14 | COPY entrypoint.sh /entrypoint.sh | ||
| 15 | RUN chmod +x /entrypoint.sh | ||
| 16 | |||
| 17 | # 80 required for Let's Encrypt HTTP-01 challenge, 443 for HTTPS | ||
| 18 | EXPOSE 80 443 | ||
| 19 | |||
| 20 | ENTRYPOINT ["/entrypoint.sh"] | ||
| @@ -0,0 +1,44 @@ | |||
| 1 | CGIT-CADDY CONTAINER | ||
| 2 | |||
| 3 | Build: | ||
| 4 | podman build -t cgit-caddy . | ||
| 5 | |||
| 6 | Run (first time or after changes): | ||
| 7 | ./start_container.sh | ||
| 8 | |||
| 9 | Run (manual): | ||
| 10 | podman run -d \ | ||
| 11 | --name cgit \ | ||
| 12 | --network public-routed \ | ||
| 13 | --ip 10.89.0.2 \ | ||
| 14 | --cap-add=NET_ADMIN \ | ||
| 15 | --env-file config.env \ | ||
| 16 | -v cgit_data:/data \ | ||
| 17 | -v /git:/git \ | ||
| 18 | localhost/cgit-caddy | ||
| 19 | |||
| 20 | sleep 2 | ||
| 21 | podman exec cgit ip addr add 37.27.166.242/32 dev eth0 | ||
| 22 | ip route add 37.27.166.242/32 via 10.89.0.2 | ||
| 23 | |||
| 24 | Restart: | ||
| 25 | podman restart cgit | ||
| 26 | |||
| 27 | Stop: | ||
| 28 | podman stop cgit && podman rm cgit && ip route del 37.27.166.242/32 | ||
| 29 | |||
| 30 | Cleanup (remove everything): | ||
| 31 | podman stop cgit | ||
| 32 | podman rm cgit | ||
| 33 | podman volume rm cgit_data | ||
| 34 | ip route del 37.27.166.242/32 | ||
| 35 | podman network rm public-routed # only if no other containers use it | ||
| 36 | |||
| 37 | Logs: | ||
| 38 | podman logs -f cgit | ||
| 39 | |||
| 40 | Shell: | ||
| 41 | podman exec -it cgit sh | ||
| 42 | |||
| 43 | Create repo: | ||
| 44 | git init --bare /git/myrepo | ||
diff --git a/cgitrc.template b/cgitrc.template new file mode 100644 index 0000000..950bf64 --- /dev/null +++ b/cgitrc.template | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | css=${CGIT_CSS} | ||
| 2 | logo=${CGIT_LOGO} | ||
| 3 | root-title=Git Repositories | ||
| 4 | root-desc= | ||
| 5 | scan-path=${GIT_PATH} | ||
| 6 | |||
| 7 | # Features | ||
| 8 | enable-index-links=1 | ||
| 9 | enable-commit-graph=1 | ||
| 10 | enable-log-filecount=1 | ||
| 11 | enable-log-linecount=1 | ||
| 12 | enable-http-clone=1 | ||
| 13 | enable-blame=1 | ||
| 14 | |||
| 15 | # Downloads | ||
| 16 | snapshots=tar.gz zip tar.xz | ||
| 17 | |||
| 18 | # Clone URL | ||
| 19 | clone-url=https://$HTTP_HOST/$CGIT_REPO_URL | ||
| 20 | |||
| 21 | # Caching (0 = disabled) | ||
| 22 | cache-size=0 | ||
| 23 | |||
| 24 | # Appearance | ||
| 25 | max-repo-count=50 | ||
| 26 | max-stats=year | ||
| 27 | side-by-side-diffs=1 | ||
diff --git a/config.env b/config.env new file mode 100644 index 0000000..417ce14 --- /dev/null +++ b/config.env | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | # Container config | ||
| 2 | CONTAINER_NAME=cgit | ||
| 3 | DOMAIN=git2.noml.ch | ||
| 4 | |||
| 5 | # Network | ||
| 6 | PRIVATE_SUBNET=10.89.0.0/24 | ||
| 7 | PRIVATE_IP=10.89.0.2 | ||
| 8 | PUBLIC_IP=37.27.166.242 | ||
| 9 | NETWORK=public-routed | ||
| 10 | |||
| 11 | # Paths (inside container) | ||
| 12 | GIT_PATH=/git | ||
| 13 | XDG_DATA_HOME=/data # mounted as caddy_data volume, stores SSL certs | ||
| 14 | CGIT_CSS=/cgit.css | ||
| 15 | CGIT_LOGO=/cgit.png | ||
| 16 | FCGI_SOCK=/run/fcgiwrap.sock | ||
diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..bf3753f --- /dev/null +++ b/entrypoint.sh | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | set -e | ||
| 3 | |||
| 4 | # Check cert matches domain, else clear and renew | ||
| 5 | if [ -d "/data/caddy/certificates" ]; then | ||
| 6 | CERT_CN=$(echo | openssl s_client -connect ${DOMAIN}:443 2>/dev/null | openssl x509 -noout -subject 2>/dev/null | grep -o "CN=.*" | cut -d= -f2 || true) | ||
| 7 | if [ -n "$CERT_CN" ] && [ "$CERT_CN" != "$DOMAIN" ]; then | ||
| 8 | echo "Cert mismatch: $CERT_CN != $DOMAIN, clearing certs" | ||
| 9 | rm -rf /data/caddy/certificates/ | ||
| 10 | fi | ||
| 11 | fi | ||
| 12 | |||
| 13 | # Generate cgitrc from template | ||
| 14 | envsubst < /etc/cgitrc.template > /etc/cgitrc | ||
| 15 | |||
| 16 | spawn-fcgi -s ${FCGI_SOCK} /usr/bin/fcgiwrap | ||
| 17 | chmod 666 ${FCGI_SOCK} | ||
| 18 | |||
| 19 | exec caddy run --config /etc/caddy/Caddyfile --adapter caddyfile | ||
diff --git a/start_container.sh b/start_container.sh new file mode 100755 index 0000000..bf1c167 --- /dev/null +++ b/start_container.sh | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | set -e | ||
| 3 | |||
| 4 | # Load config | ||
| 5 | source "$(dirname "$0")/config.env" | ||
| 6 | |||
| 7 | # Create network if not exists | ||
| 8 | if ! podman network exists ${NETWORK}; then | ||
| 9 | echo "Creating network: ${NETWORK} (subnet: ${PRIVATE_SUBNET})" | ||
| 10 | podman network create --subnet=${PRIVATE_SUBNET} ${NETWORK} | ||
| 11 | else | ||
| 12 | echo "Network exists: ${NETWORK}" | ||
| 13 | fi | ||
| 14 | |||
| 15 | # Stop existing container if running | ||
| 16 | podman stop ${CONTAINER_NAME} 2>/dev/null || true | ||
| 17 | podman rm ${CONTAINER_NAME} 2>/dev/null || true | ||
| 18 | ip route del ${PUBLIC_IP}/32 2>/dev/null || true | ||
| 19 | |||
| 20 | # Run container | ||
| 21 | podman run -d \ | ||
| 22 | --name ${CONTAINER_NAME} \ | ||
| 23 | --network ${NETWORK} \ | ||
| 24 | --ip ${PRIVATE_IP} \ | ||
| 25 | --cap-add=NET_ADMIN \ | ||
| 26 | --env-file "$(dirname "$0")/config.env" \ | ||
| 27 | -v ${CONTAINER_NAME}_data:/data \ | ||
| 28 | -v /git:/git \ | ||
| 29 | localhost/cgit-caddy | ||
| 30 | |||
| 31 | # Setup public IP | ||
| 32 | sleep 2 | ||
| 33 | IFACE=$(podman exec ${CONTAINER_NAME} sh -c "ip -o link | grep -v lo | head -1 | cut -d: -f2 | tr -d ' ' | cut -d@ -f1") | ||
| 34 | podman exec ${CONTAINER_NAME} ip addr add ${PUBLIC_IP}/32 dev ${IFACE} | ||
| 35 | ip route add ${PUBLIC_IP}/32 via ${PRIVATE_IP} | ||
| 36 | |||
| 37 | echo "Running at https://${DOMAIN}/" | ||
