summaryrefslogtreecommitdiff
path: root/f3s/git-server
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-01-09 11:06:02 +0200
committerPaul Buetow <paul@buetow.org>2026-01-09 11:06:28 +0200
commit634f98a69d398f82800d349489d3c279879aaae6 (patch)
treec27f4ea08cb7299478c71bae9d27b493cab9b745 /f3s/git-server
parent9ab8ab11ab815f9025ad6e24eac46f481f8f385f (diff)
Add self-hosted git server with SSH and cgit web UI
Deploy a self-hosted git repository solution to replace external Codeberg dependency. Components: - SSH git server: Alpine-based container with OpenSSH and git - cgit web UI: Browse repositories at cgit.f3s.buetow.org - Single pod design: git-server + cgit containers sharing storage Infrastructure: - Docker image in git-server/docker-image/ with Justfile build automation - Helm chart in git-server/helm-chart/ for Kubernetes deployment - 5Gi ReadWriteMany PVC for NFS-backed repository storage - ClusterIP service for ArgoCD internal access - NodePort 30022 for external SSH push access - Traefik ingress for cgit web UI ArgoCD Application manifest deployed to cicd namespace. Note: SSH keys must be created as Kubernetes secrets manually, not in git. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'f3s/git-server')
-rw-r--r--f3s/git-server/docker-image/Dockerfile23
-rw-r--r--f3s/git-server/docker-image/Justfile7
-rw-r--r--f3s/git-server/docker-image/sshd_config35
-rw-r--r--f3s/git-server/helm-chart/Chart.yaml5
-rw-r--r--f3s/git-server/helm-chart/templates/configmap-cgit.yaml23
-rw-r--r--f3s/git-server/helm-chart/templates/deployment.yaml97
-rw-r--r--f3s/git-server/helm-chart/templates/ingress.yaml24
-rw-r--r--f3s/git-server/helm-chart/templates/persistent-volume.yaml27
-rw-r--r--f3s/git-server/helm-chart/templates/service.yaml38
9 files changed, 279 insertions, 0 deletions
diff --git a/f3s/git-server/docker-image/Dockerfile b/f3s/git-server/docker-image/Dockerfile
new file mode 100644
index 0000000..382ad0d
--- /dev/null
+++ b/f3s/git-server/docker-image/Dockerfile
@@ -0,0 +1,23 @@
+FROM alpine:3.19
+
+# Install OpenSSH server and git
+RUN apk add --no-cache openssh git
+
+# Create git user with UID 1000 and set git-shell as login shell
+# This restricts the user to git operations only
+RUN adduser -D -u 1000 -s /usr/bin/git-shell git && \
+ mkdir -p /home/git/.ssh /repos && \
+ chown -R git:git /home/git /repos
+
+# Generate SSH host keys
+# These will be regenerated if not persisted via volume mount
+RUN ssh-keygen -A
+
+# Copy sshd configuration
+COPY sshd_config /etc/ssh/sshd_config
+
+# Expose SSH port
+EXPOSE 22
+
+# Run SSH daemon in foreground with error logging to stderr
+CMD ["/usr/sbin/sshd", "-D", "-e"]
diff --git a/f3s/git-server/docker-image/Justfile b/f3s/git-server/docker-image/Justfile
new file mode 100644
index 0000000..1b54e4a
--- /dev/null
+++ b/f3s/git-server/docker-image/Justfile
@@ -0,0 +1,7 @@
+all:
+ docker build -t git-server:1.0 .
+
+f3s:
+ docker build -t git-server:1.0 .
+ docker tag git-server:1.0 r0.lan.buetow.org:30001/git-server:1.0
+ docker push r0.lan.buetow.org:30001/git-server:1.0
diff --git a/f3s/git-server/docker-image/sshd_config b/f3s/git-server/docker-image/sshd_config
new file mode 100644
index 0000000..e49c5bb
--- /dev/null
+++ b/f3s/git-server/docker-image/sshd_config
@@ -0,0 +1,35 @@
+# SSH Server Configuration for Git Server
+# Security-hardened configuration for git-only access
+
+# Network
+Port 22
+AddressFamily any
+ListenAddress 0.0.0.0
+
+# Host Keys
+HostKey /etc/ssh/ssh_host_ed25519_key
+HostKey /etc/ssh/ssh_host_rsa_key
+
+# Security
+PermitRootLogin no
+PubkeyAuthentication yes
+PasswordAuthentication no
+PermitEmptyPasswords no
+ChallengeResponseAuthentication no
+UsePAM no
+
+# Restrict to git user only
+AllowUsers git
+
+# Disable tunneling and forwarding
+X11Forwarding no
+AllowTcpForwarding no
+AllowAgentForwarding no
+PermitTunnel no
+
+# Logging
+SyslogFacility AUTH
+LogLevel INFO
+
+# Performance
+UseDNS no
diff --git a/f3s/git-server/helm-chart/Chart.yaml b/f3s/git-server/helm-chart/Chart.yaml
new file mode 100644
index 0000000..eeceffb
--- /dev/null
+++ b/f3s/git-server/helm-chart/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v2
+name: git-server
+description: A Helm chart for deploying a self-hosted SSH git server with cgit web UI.
+version: 0.1.0
+appVersion: "1.0"
diff --git a/f3s/git-server/helm-chart/templates/configmap-cgit.yaml b/f3s/git-server/helm-chart/templates/configmap-cgit.yaml
new file mode 100644
index 0000000..840fbd4
--- /dev/null
+++ b/f3s/git-server/helm-chart/templates/configmap-cgit.yaml
@@ -0,0 +1,23 @@
+# CGit Configuration
+# Configures cgit to scan /repos for git repositories
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: cgit-config
+ namespace: cicd
+data:
+ cgitrc: |
+ # Global settings
+ root-title=f3s Git Repository Browser
+ root-desc=Browse git repositories in f3s cluster
+
+ # Enable git-config for per-repo settings
+ enable-git-config=1
+
+ # Remove .git suffix from repository URLs
+ remove-suffix=1
+
+ # Scan for repositories in /repos
+ # This must be the last setting in the file
+ scan-path=/repos
diff --git a/f3s/git-server/helm-chart/templates/deployment.yaml b/f3s/git-server/helm-chart/templates/deployment.yaml
new file mode 100644
index 0000000..7e262f8
--- /dev/null
+++ b/f3s/git-server/helm-chart/templates/deployment.yaml
@@ -0,0 +1,97 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: git-server
+ namespace: cicd
+ labels:
+ app: git-server
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: git-server
+ template:
+ metadata:
+ labels:
+ app: git-server
+ spec:
+ # Allow both git (1000) and www-data (33) to access shared files
+ securityContext:
+ fsGroup: 1000
+
+ containers:
+ # Container 1: SSH Git Server
+ - name: git-server
+ image: r0.lan.buetow.org:30001/git-server:1.0
+ ports:
+ - containerPort: 22
+ name: ssh
+ protocol: TCP
+ volumeMounts:
+ - name: repos
+ mountPath: /repos
+ - name: git-ssh-keys
+ mountPath: /home/git/.ssh/authorized_keys
+ subPath: authorized_keys
+ readOnly: true
+ securityContext:
+ runAsUser: 1000
+ runAsGroup: 1000
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop: ["ALL"]
+ resources:
+ requests:
+ cpu: 50m
+ memory: 128Mi
+ limits:
+ cpu: 250m
+ memory: 256Mi
+
+ # Container 2: CGit Web UI
+ - name: cgit
+ image: joseluisq/alpine-cgit:latest
+ ports:
+ - containerPort: 8080
+ name: http
+ protocol: TCP
+ env:
+ - name: CGIT_TITLE
+ value: "f3s Git Repository Browser"
+ - name: CGIT_DESC
+ value: "Browse git repositories"
+ volumeMounts:
+ - name: repos
+ mountPath: /repos
+ readOnly: true
+ - name: cgit-config
+ mountPath: /etc/cgitrc
+ subPath: cgitrc
+ readOnly: true
+ securityContext:
+ runAsUser: 33
+ runAsGroup: 33
+ runAsNonRoot: true
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop: ["ALL"]
+ add: ["NET_BIND_SERVICE"]
+ resources:
+ requests:
+ cpu: 50m
+ memory: 128Mi
+ limits:
+ cpu: 250m
+ memory: 256Mi
+
+ volumes:
+ - name: repos
+ persistentVolumeClaim:
+ claimName: git-server-pvc
+ - name: git-ssh-keys
+ secret:
+ secretName: git-server-authorized-keys
+ defaultMode: 0400
+ - name: cgit-config
+ configMap:
+ name: cgit-config
diff --git a/f3s/git-server/helm-chart/templates/ingress.yaml b/f3s/git-server/helm-chart/templates/ingress.yaml
new file mode 100644
index 0000000..e47ff7f
--- /dev/null
+++ b/f3s/git-server/helm-chart/templates/ingress.yaml
@@ -0,0 +1,24 @@
+# CGit Web UI Ingress
+# Exposes cgit web interface at cgit.f3s.buetow.org
+# Following f3s cluster ingress pattern (Traefik)
+
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: cgit-ingress
+ namespace: cicd
+ annotations:
+ spec.ingressClassName: traefik
+ traefik.ingress.kubernetes.io/router.entrypoints: web
+spec:
+ rules:
+ - host: cgit.f3s.buetow.org
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: git-server
+ port:
+ number: 80
diff --git a/f3s/git-server/helm-chart/templates/persistent-volume.yaml b/f3s/git-server/helm-chart/templates/persistent-volume.yaml
new file mode 100644
index 0000000..174e66e
--- /dev/null
+++ b/f3s/git-server/helm-chart/templates/persistent-volume.yaml
@@ -0,0 +1,27 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: git-server-pv
+spec:
+ capacity:
+ storage: 5Gi
+ volumeMode: Filesystem
+ accessModes:
+ - ReadWriteMany
+ persistentVolumeReclaimPolicy: Retain
+ hostPath:
+ path: /data/nfs/k3svolumes/git-server
+ type: Directory
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: git-server-pvc
+ namespace: cicd
+spec:
+ storageClassName: ""
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 5Gi
diff --git a/f3s/git-server/helm-chart/templates/service.yaml b/f3s/git-server/helm-chart/templates/service.yaml
new file mode 100644
index 0000000..9675e86
--- /dev/null
+++ b/f3s/git-server/helm-chart/templates/service.yaml
@@ -0,0 +1,38 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: git-server
+ namespace: cicd
+ labels:
+ app: git-server
+spec:
+ selector:
+ app: git-server
+ ports:
+ - name: ssh
+ protocol: TCP
+ port: 22
+ targetPort: 22
+ - name: http
+ protocol: TCP
+ port: 80
+ targetPort: 8080
+ type: ClusterIP
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: git-server-ssh
+ namespace: cicd
+ labels:
+ app: git-server
+spec:
+ selector:
+ app: git-server
+ ports:
+ - name: ssh
+ protocol: TCP
+ port: 22
+ targetPort: 22
+ nodePort: 30022
+ type: NodePort