feat: deploy Forgejo self-hosted git server

- Add ZFS NFS datasets: media-pool/git (50G) and media-pool/git-db (10G)
- Add nfs-git and nfs-git-db NFS subdir provisioner Helm values
- Deploy Forgejo 10 (StatefulSet) + PostgreSQL 16 (StatefulSet) in infrastructure namespace
- StorageClasses: nfs-git (repos/LFS, 50Gi) and nfs-git-db (postgres, 10Gi)
- Ingress: git.vandachevici.ro with TLS via cert-manager
- SSH NodePort 30022 for git clone ssh://git@host:30022/user/repo.git
- Authentik OIDC provider configured (client ID: ZdnrHgyfUncSIPPrOe1o7UAA42N7BMhUHXjQVw4Y)
- Add 'git' subdomain to dns-updater configmap

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Dan V 2026-04-08 23:10:41 +02:00
parent 29440b68a9
commit 88540b6ded
4 changed files with 420 additions and 0 deletions

View file

@ -0,0 +1,14 @@
nfs:
mountOptions:
- soft
- timeo=30
path: /media-pool/git-db
server: 192.168.2.193
storageClass:
allowVolumeExpansion: true
archiveOnDelete: true
defaultClass: false
mountOptions:
- soft
- timeo=30
name: nfs-git-db

View file

@ -0,0 +1,14 @@
nfs:
mountOptions:
- soft
- timeo=30
path: /media-pool/git
server: 192.168.2.193
storageClass:
allowVolumeExpansion: true
archiveOnDelete: true
defaultClass: false
mountOptions:
- soft
- timeo=30
name: nfs-git

View file

@ -0,0 +1,72 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
annotations: {}
name: dns-updater-config
namespace: infrastructure
data:
DOMAIN: vandachevici.ro
NAME: photos;backup;media;chat;openttd;excalidraw;prv;drive;grafana;paperclip;proxmox;parts;dns;games;git
REMOVE_DUPLICATES: 'true'
SLEEP_INTERVAL: '60'
---
# NOTE: Secret 'dns-updater-secret' must be created manually:
# kubectl create secret generic dns-updater-secret \
# --from-literal=digitalocean-token=<YOUR_TOKEN> \
# -n infrastructure
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
annotations: {}
labels:
app: dns-updater
name: dns-updater
namespace: infrastructure
spec:
selector:
matchLabels:
app: dns-updater
template:
metadata:
labels:
app: dns-updater
spec:
containers:
- env:
- name: DIGITALOCEAN_TOKEN
valueFrom:
secretKeyRef:
key: digitalocean-token
name: dns-updater-secret
- name: DOMAIN
valueFrom:
configMapKeyRef:
key: DOMAIN
name: dns-updater-config
- name: NAME
valueFrom:
configMapKeyRef:
key: NAME
name: dns-updater-config
- name: SLEEP_INTERVAL
valueFrom:
configMapKeyRef:
key: SLEEP_INTERVAL
name: dns-updater-config
- name: REMOVE_DUPLICATES
valueFrom:
configMapKeyRef:
key: REMOVE_DUPLICATES
name: dns-updater-config
image: tunix/digitalocean-dyndns:latest
name: dns-updater
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
restartPolicy: Always

View file

@ -0,0 +1,320 @@
---
# Forgejo git server + PostgreSQL database
# Domain: git.vandachevici.ro
# Auth: Authentik OIDC (configured post-deploy via admin UI)
# Storage: NFS on HP ProLiant (media-pool/git, media-pool/git-db)
# SSH: NodePort 30022 (clone with: git clone ssh://git@<host>:30022/<user>/<repo>.git)
#
# Initial deploy steps after applying:
# 1. Create Authentik OIDC provider (see plan.md todo: authentik-oidc)
# 2. In Forgejo admin: Site Administration → Authentication Sources → Add OAuth2 Source
# - Provider: OpenID Connect
# - Name: authentik
# - Client ID/Secret: from Authentik
# - OpenID Discovery URL: https://auth.vandachevici.ro/application/o/forgejo/.well-known/openid-configuration
---
apiVersion: v1
kind: Secret
metadata:
name: forgejo-db-secret
namespace: infrastructure
type: Opaque
stringData:
POSTGRES_DB: forgejo
POSTGRES_USER: forgejo
POSTGRES_PASSWORD: Hg9mKnRpQwXvTz2Ld8cJsY4bAeUfN6
---
apiVersion: v1
kind: Secret
metadata:
name: forgejo-secret
namespace: infrastructure
type: Opaque
stringData:
# Random secret key for Forgejo session/cookie signing
# Generate with: openssl rand -hex 32
secret-key: 5f323a291b24ba0d83c5df56569eeeb44e5eda0bcfc9f3d9601d5ab46f5f3754
---
# PostgreSQL for Forgejo
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: forgejo-db-pvc
namespace: infrastructure
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: nfs-git-db
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: forgejo-db
namespace: infrastructure
spec:
replicas: 1
selector:
matchLabels:
app: forgejo-db
serviceName: forgejo-db
template:
metadata:
labels:
app: forgejo-db
spec:
containers:
- name: postgres
image: postgres:16-alpine
ports:
- containerPort: 5432
name: postgres
env:
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: forgejo-db-secret
key: POSTGRES_DB
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: forgejo-db-secret
key: POSTGRES_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: forgejo-db-secret
key: POSTGRES_PASSWORD
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: db-data
mountPath: /var/lib/postgresql/data
livenessProbe:
exec:
command:
- pg_isready
- -U
- forgejo
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 5
readinessProbe:
exec:
command:
- pg_isready
- -U
- forgejo
initialDelaySeconds: 10
periodSeconds: 5
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
volumes:
- name: db-data
persistentVolumeClaim:
claimName: forgejo-db-pvc
---
apiVersion: v1
kind: Service
metadata:
name: forgejo-db
namespace: infrastructure
spec:
selector:
app: forgejo-db
ports:
- name: postgres
port: 5432
targetPort: 5432
---
# Forgejo git server
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: forgejo-data-pvc
namespace: infrastructure
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: nfs-git
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: forgejo
namespace: infrastructure
spec:
replicas: 1
selector:
matchLabels:
app: forgejo
serviceName: forgejo
template:
metadata:
labels:
app: forgejo
spec:
initContainers:
- name: wait-for-db
image: busybox:1.36
command:
- sh
- -c
- |
until nc -z forgejo-db 5432; do
echo "Waiting for PostgreSQL..."
sleep 2
done
echo "PostgreSQL is ready"
containers:
- name: forgejo
image: codeberg.org/forgejo/forgejo:10
ports:
- containerPort: 3000
name: http
- containerPort: 22
name: ssh
env:
- name: FORGEJO__database__DB_TYPE
value: postgres
- name: FORGEJO__database__HOST
value: forgejo-db:5432
- name: FORGEJO__database__NAME
valueFrom:
secretKeyRef:
name: forgejo-db-secret
key: POSTGRES_DB
- name: FORGEJO__database__USER
valueFrom:
secretKeyRef:
name: forgejo-db-secret
key: POSTGRES_USER
- name: FORGEJO__database__PASSWD
valueFrom:
secretKeyRef:
name: forgejo-db-secret
key: POSTGRES_PASSWORD
- name: FORGEJO__server__DOMAIN
value: git.vandachevici.ro
- name: FORGEJO__server__ROOT_URL
value: https://git.vandachevici.ro
- name: FORGEJO__server__SSH_DOMAIN
value: git.vandachevici.ro
- name: FORGEJO__server__SSH_PORT
value: "30022"
- name: FORGEJO__server__SSH_LISTEN_PORT
value: "22"
- name: FORGEJO__security__SECRET_KEY
valueFrom:
secretKeyRef:
name: forgejo-secret
key: secret-key
- name: FORGEJO__service__DISABLE_REGISTRATION
value: "false"
- name: FORGEJO__service__REQUIRE_SIGNIN_VIEW
value: "false"
volumeMounts:
- name: forgejo-data
mountPath: /data
livenessProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: 60
periodSeconds: 15
failureThreshold: 5
readinessProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 1000m
memory: 512Mi
volumes:
- name: forgejo-data
persistentVolumeClaim:
claimName: forgejo-data-pvc
---
# ClusterIP for HTTP (used by ingress)
apiVersion: v1
kind: Service
metadata:
name: forgejo
namespace: infrastructure
spec:
selector:
app: forgejo
ports:
- name: http
port: 3000
targetPort: 3000
---
# NodePort for SSH git access (git clone ssh://git@git.vandachevici.ro:30022/user/repo.git)
apiVersion: v1
kind: Service
metadata:
name: forgejo-ssh
namespace: infrastructure
spec:
type: NodePort
selector:
app: forgejo
ports:
- name: ssh
port: 22
targetPort: 22
nodePort: 30022
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: forgejo
namespace: infrastructure
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec:
ingressClassName: nginx
rules:
- host: git.vandachevici.ro
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: forgejo
port:
number: 3000
tls:
- hosts:
- git.vandachevici.ro
secretName: forgejo-tls