Fresh cluster restore

This commit is contained in:
Cluster Backup Engine 2026-10-18 13:47:06 +00:00
commit bbba564dad
25 changed files with 3326 additions and 0 deletions

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# cluster-manifests

88
blocky/values.yaml Normal file
View File

@ -0,0 +1,88 @@
controller:
replicas: 2
strategy: RollingUpdate
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- blocky
topologyKey: "kubernetes.io/hostname"
config: |
upstream:
default:
- https://1.1.1.1/dns-query
- https://8.8.8.8/dns-query
customDNS:
customTTL: 1h
mapping:
needlestack.boo: 192.168.1.201
"*.needlestack.boo": 192.168.1.201
blocking:
denylists:
ads:
- https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
clientGroupsBlock:
default:
- ads
blockType: NXDOMAIN
refreshPeriod: 4h
caching:
minTime: 5m
maxTime: 30m
prefetching: true
ports:
dns: 53
http: 4000
prometheus:
enable: true
path: /metrics
service:
# The main service block MUST remain enabled on port 4000 for health checks and metrics
main:
enabled: true
ports:
http:
port: 4000
dns:
enabled: true
type: LoadBalancer
# THE FIX: Allows Node 1 to proxy queries to your replicas on Node 2 & 3
externalTrafficPolicy: Cluster
annotations: {}
ports:
dns-udp:
enabled: true
port: 53
protocol: UDP
targetPort: 53
dns-tcp:
enabled: true
port: 53
protocol: TCP
targetPort: 53
metrics:
enabled: true
serviceMonitor:
interval: 30s
scrapeTimeout: 10s
labels:
release: kube-prometheus-stack
jobLabel: ""
targetLabels: []
podTargetLabels: []
prometheusRule:
enabled: false
labels: {}
rules: []

313
bookstack-db/resources.yaml Normal file
View File

@ -0,0 +1,313 @@
apiVersion: v1
items:
- apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "3"
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"bookstack-web","namespace":"bookstack-db"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"bookstack-web"}},"template":{"metadata":{"labels":{"app":"bookstack-web"}},"spec":{"containers":[{"env":[{"name":"PUID","value":"1000"},{"name":"PGID","value":"1000"},{"name":"TZ","value":"Europe/London"},{"name":"APP_URL","value":"https://wiki.needlestack.boo"},{"name":"APP_KEY","value":"base64:Jng4M2tkbXNleXBoYWRmZ2g0NTZqYm5tY3YxMjM0NTY="},{"name":"DB_HOST","value":"10.43.161.65"},{"name":"DB_PORT","value":"3306"},{"name":"DB_USER","value":"bookstack"},{"name":"DB_PASS","value":"Bar07ney!"},{"name":"DB_DATABASE","value":"bookstack"}],"image":"docker.io/linuxserver/bookstack:latest","name":"bookstack","ports":[{"containerPort":80,"name":"http"}],"volumeMounts":[{"mountPath":"/config","name":"bookstack-config"}]}],"dnsConfig":{"nameservers":["1.1.1.1","8.8.8.8"]},"dnsPolicy":"None","volumes":[{"name":"bookstack-config","persistentVolumeClaim":{"claimName":"bookstack-config-pvc"}}]}}}}
creationTimestamp: "2026-09-12T20:44:04Z"
generation: 5
name: bookstack-web
namespace: bookstack-db
resourceVersion: "851484"
uid: 714317b1-19be-4e10-ba0d-7fbf23bae864
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: bookstack-web
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
annotations:
kubectl.kubernetes.io/restartedAt: "2026-09-12T21:36:57Z"
creationTimestamp: null
labels:
app: bookstack-web
spec:
containers:
- env:
- name: PUID
value: "1000"
- name: PGID
value: "1000"
- name: TZ
value: Europe/London
- name: APP_URL
value: https://wiki.needlestack.boo
- name: APP_KEY
value: base64:Jng4M2tkbXNleXBoYWRmZ2g0NTZqYm5tY3YxMjM0NTY=
- name: DB_HOST
value: 10.43.161.65
- name: DB_PORT
value: "3306"
- name: DB_USER
value: bookstack
- name: DB_PASS
value: Bar07ney!
- name: DB_DATABASE
value: bookstack
image: docker.io/linuxserver/bookstack:latest
imagePullPolicy: Always
name: bookstack
ports:
- containerPort: 80
name: http
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /config
name: bookstack-config
dnsConfig:
nameservers:
- 1.1.1.1
- 8.8.8.8
dnsPolicy: None
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: bookstack-config
persistentVolumeClaim:
claimName: bookstack-config-pvc
status:
availableReplicas: 1
conditions:
- lastTransitionTime: "2026-09-12T20:44:04Z"
lastUpdateTime: "2026-09-12T21:39:25Z"
message: ReplicaSet "bookstack-web-74b9c9c799" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
- lastTransitionTime: "2026-09-12T21:40:00Z"
lastUpdateTime: "2026-09-12T21:40:00Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
observedGeneration: 5
readyReplicas: 1
replicas: 1
updatedReplicas: 1
- apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"mariadb","namespace":"bookstack-db"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"mariadb"}},"template":{"metadata":{"labels":{"app":"mariadb"}},"spec":{"containers":[{"env":[{"name":"MARIADB_ROOT_PASSWORD","value":"nstBar07ney!"},{"name":"MARIADB_DATABASE","value":"bookstack"},{"name":"MARIADB_USER","value":"bookstack"},{"name":"MARIADB_PASSWORD","value":"Bar07ney!"}],"image":"docker.io/library/mariadb:10.11","name":"mariadb","ports":[{"containerPort":3306,"name":"mysql"}],"volumeMounts":[{"mountPath":"/var/lib/mysql","name":"mariadb-storage"}]}],"dnsConfig":{"nameservers":["1.1.1.1","8.8.8.8"]},"dnsPolicy":"None","volumes":[{"name":"mariadb-storage","persistentVolumeClaim":{"claimName":"mariadb-data-pvc"}}]}}}}
creationTimestamp: "2026-09-12T20:39:27Z"
generation: 1
name: mariadb
namespace: bookstack-db
resourceVersion: "834544"
uid: 9a81a32b-2079-43ee-8394-643027df3986
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: mariadb
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: mariadb
spec:
containers:
- env:
- name: MARIADB_ROOT_PASSWORD
value: nstBar07ney!
- name: MARIADB_DATABASE
value: bookstack
- name: MARIADB_USER
value: bookstack
- name: MARIADB_PASSWORD
value: Bar07ney!
image: docker.io/library/mariadb:10.11
imagePullPolicy: IfNotPresent
name: mariadb
ports:
- containerPort: 3306
name: mysql
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/lib/mysql
name: mariadb-storage
dnsConfig:
nameservers:
- 1.1.1.1
- 8.8.8.8
dnsPolicy: None
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: mariadb-storage
persistentVolumeClaim:
claimName: mariadb-data-pvc
status:
availableReplicas: 1
conditions:
- lastTransitionTime: "2026-09-12T20:40:01Z"
lastUpdateTime: "2026-09-12T20:40:01Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: "2026-09-12T20:39:27Z"
lastUpdateTime: "2026-09-12T20:40:01Z"
message: ReplicaSet "mariadb-6fcf465cc4" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
observedGeneration: 1
readyReplicas: 1
replicas: 1
updatedReplicas: 1
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"name":"bookstack-config-pvc","namespace":"bookstack-db"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"10Gi"}},"storageClassName":"longhorn"}}
pv.kubernetes.io/bind-completed: "yes"
pv.kubernetes.io/bound-by-controller: "yes"
volume.beta.kubernetes.io/storage-provisioner: driver.longhorn.io
volume.kubernetes.io/storage-provisioner: driver.longhorn.io
creationTimestamp: "2026-09-12T20:44:04Z"
finalizers:
- kubernetes.io/pvc-protection
name: bookstack-config-pvc
namespace: bookstack-db
resourceVersion: "835762"
uid: b9ed0926-9879-4ddd-885e-0948cd48ce3f
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: longhorn
volumeMode: Filesystem
volumeName: pvc-b9ed0926-9879-4ddd-885e-0948cd48ce3f
status:
accessModes:
- ReadWriteOnce
capacity:
storage: 10Gi
phase: Bound
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"name":"mariadb-data-pvc","namespace":"bookstack-db"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"10Gi"}},"storageClassName":"longhorn"}}
pv.kubernetes.io/bind-completed: "yes"
pv.kubernetes.io/bound-by-controller: "yes"
volume.beta.kubernetes.io/storage-provisioner: driver.longhorn.io
volume.kubernetes.io/storage-provisioner: driver.longhorn.io
creationTimestamp: "2026-09-12T20:39:27Z"
finalizers:
- kubernetes.io/pvc-protection
name: mariadb-data-pvc
namespace: bookstack-db
resourceVersion: "834328"
uid: b87615cd-7e29-4522-995d-4e2cd1144a0a
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: longhorn
volumeMode: Filesystem
volumeName: pvc-b87615cd-7e29-4522-995d-4e2cd1144a0a
status:
accessModes:
- ReadWriteOnce
capacity:
storage: 10Gi
phase: Bound
- apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"bookstack-web-service","namespace":"bookstack-db"},"spec":{"ports":[{"port":80,"targetPort":80}],"selector":{"app":"bookstack-web"}}}
creationTimestamp: "2026-09-12T20:44:04Z"
name: bookstack-web-service
namespace: bookstack-db
resourceVersion: "835699"
uid: 7df0e394-c2d0-482a-8212-be0a74bf20af
spec:
clusterIP: 10.43.136.41
clusterIPs:
- 10.43.136.41
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: bookstack-web
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
- apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"mariadb-service","namespace":"bookstack-db"},"spec":{"ports":[{"port":3306}],"selector":{"app":"mariadb"}}}
creationTimestamp: "2026-09-12T20:39:27Z"
name: mariadb-service
namespace: bookstack-db
resourceVersion: "834266"
uid: 3ec5d3ac-c8a8-474a-a21a-2db1ced6c503
spec:
clusterIP: 10.43.161.65
clusterIPs:
- 10.43.161.65
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- port: 3306
protocol: TCP
targetPort: 3306
selector:
app: mariadb
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
kind: List
metadata:
resourceVersion: ""

29
bookstack/ingress.yaml Normal file
View File

@ -0,0 +1,29 @@
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: bookstack-local-ingress
namespace: bookstack-db
annotations:
# AUTOMATED TLS FIX: Triggers cert-manager to provision the certificate
cert-manager.io/cluster-issuer: "letsencrypt-production"
# THE 502 FIX: Instructs NGINX how to bridge the internal pod connection protocol
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
ingressClassName: nginx
# AUTOMATED TLS FIX: Instructs NGINX where to mount the generated certificate
tls:
- secretName: bookstack-tls-secret
hosts:
- wiki.needlestack.boo
rules:
- host: wiki.needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: bookstack-web-service
port:
number: 80

40
bookstack/resources.yaml Normal file
View File

@ -0,0 +1,40 @@
apiVersion: v1
items:
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
pv.kubernetes.io/bind-completed: "yes"
pv.kubernetes.io/bound-by-controller: "yes"
volume.beta.kubernetes.io/storage-provisioner: driver.longhorn.io
volume.kubernetes.io/storage-provisioner: driver.longhorn.io
creationTimestamp: "2026-09-12T20:23:24Z"
finalizers:
- kubernetes.io/pvc-protection
labels:
app.kubernetes.io/component: primary
app.kubernetes.io/instance: bookstack
app.kubernetes.io/name: mariadb
app.kubernetes.io/part-of: mariadb
name: data-bookstack-mariadb-0
namespace: bookstack
resourceVersion: "829155"
uid: 4faa1a16-2c11-4c8b-9c09-5d271c39ebf2
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: longhorn
volumeMode: Filesystem
volumeName: pvc-4faa1a16-2c11-4c8b-9c09-5d271c39ebf2
status:
accessModes:
- ReadWriteOnce
capacity:
storage: 10Gi
phase: Bound
kind: List
metadata:
resourceVersion: ""

View File

@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "4"
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"cloudflared","namespace":"cloudflare"},"spec":{"replicas":2,"selector":{"matchLabels":{"app":"cloudflared"}},"template":{"metadata":{"labels":{"app":"cloudflared"}},"spec":{"containers":[{"args":["tunnel","--no-autoupdate","run"],"env":[{"name":"TUNNEL_TOKEN","value":"eyJhIjoiZGQzZGM4NzUyNWFlM2VhMjg4MjljY2QzN2IzM2IwNDUiLCJ0IjoiZjVkMzkwMmMtMWIzNS00MDg1LTk1MDctYTIxZGE0Njg0NzkzIiwicyI6Ik1tTmhZems0Tm1NdFkyUmhOQzAwTkdFMExUazFNV010TldRM00yWXhaalV4TlRJeiJ9"}],"image":"cloudflare/cloudflared:latest","name":"cloudflared"}],"dnsConfig":{"nameservers":["1.1.1.1","8.8.8.8"]},"dnsPolicy":"None"}}}}
creationTimestamp: "2026-09-12T15:12:46Z"
generation: 4
name: cloudflared
namespace: cloudflare
resourceVersion: "5577092"
uid: ded6d529-b685-4829-a7f6-7d16dcbf8598
spec:
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
app: cloudflared
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
annotations:
kubectl.kubernetes.io/restartedAt: "2026-09-24T20:27:50Z"
creationTimestamp: null
labels:
app: cloudflared
spec:
containers:
- args:
- tunnel
- --no-autoupdate
- run
env:
- name: TUNNEL_TOKEN
value: eyJhIjoiZGQzZGM4NzUyNWFlM2VhMjg4MjljY2QzN2IzM2IwNDUiLCJ0IjoiZjVkMzkwMmMtMWIzNS00MDg1LTk1MDctYTIxZGE0Njg0NzkzIiwicyI6Ik1tTmhZems0Tm1NdFkyUmhOQzAwTkdFMExUazFNV010TldRM00yWXhaalV4TlRJeiJ9
image: cloudflare/cloudflared:latest
imagePullPolicy: Always
name: cloudflared
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsConfig:
nameservers:
- 10.43.0.10
searches:
- svc.cluster.local
- cluster.local
dnsPolicy: None
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status:
availableReplicas: 2
conditions:
- lastTransitionTime: "2026-09-12T15:18:53Z"
lastUpdateTime: "2026-09-12T15:18:53Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: "2026-09-12T15:12:46Z"
lastUpdateTime: "2026-09-24T20:27:55Z"
message: ReplicaSet "cloudflared-6b4f8bccfc" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
observedGeneration: 4
readyReplicas: 2
replicas: 2
updatedReplicas: 2

150
cobalt/resources.yaml Normal file
View File

@ -0,0 +1,150 @@
apiVersion: v1
kind: Namespace
metadata:
name: cobalt-downloader
---
# 1. THE BACKEND API (Processing Engine)
apiVersion: apps/v1
kind: Deployment
metadata:
name: cobalt-api
namespace: cobalt-downloader
labels:
app: cobalt-api
spec:
replicas: 1
selector:
matchLabels:
app: cobalt-api
template:
metadata:
labels:
app: cobalt-api
spec:
containers:
- name: api
image: ghcr.io/imputnet/cobalt:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9000
name: http-api
env:
# Identifies its own public API endpoint location
- name: API_URL
value: "https://cobalt-api.needlestack.boo"
# Grants cross-origin clearance strictly to your web UI subdomain
- name: CORS_ALLOWED_ORIGINS
value: "https://cobalt.needlestack.boo"
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"
---
apiVersion: v1
kind: Service
metadata:
name: cobalt-api-svc
namespace: cobalt-downloader
spec:
selector:
app: cobalt-api
ports:
- protocol: TCP
port: 9000
targetPort: 9000
---
# 2. THE WEB FRONTEND UI (Browser Dashboard)
apiVersion: apps/v1
kind: Deployment
metadata:
name: cobalt-web
namespace: cobalt-downloader
labels:
app: cobalt-web
spec:
replicas: 1
selector:
matchLabels:
app: cobalt-web
template:
metadata:
labels:
app: cobalt-web
spec:
containers:
- name: web
# Swapped to a verified production container path that respects HTTPS parameters
image: ghcr.io/notnite/cobalt-web:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http-web
env:
# This image expects API_URL to pass the backend routing location to browsers
- name: API_URL
value: "https://cobalt-api.needlestack.boo"
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "50m"
memory: "128Mi"
---
apiVersion: v1
kind: Service
metadata:
name: cobalt-web-svc
namespace: cobalt-downloader
spec:
selector:
app: cobalt-web
ports:
- protocol: TCP
port: 80
targetPort: 80
---
# 3. NGINX INGRESS MAPPING (Dual Host Control)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cobalt-ingress
namespace: cobalt-downloader
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-production"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/enable-cors: "true"
spec:
ingressClassName: nginx
tls:
- secretName: cobalt-tls-secret
hosts:
- cobalt.needlestack.boo
- cobalt-api.needlestack.boo
rules:
# Routes your primary browser landing screen traffic
- host: cobalt.needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: cobalt-web-svc
port:
number: 80
# Routes underlying stream data traffic
- host: cobalt-api.needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: cobalt-api-svc
port:
number: 9000

82
convertx/values.yaml Normal file
View File

@ -0,0 +1,82 @@
controllers:
main:
type: deployment
strategy: Recreate
containers:
main:
image:
repository: ghcr.io/c4illin/convertx
tag: latest
pullPolicy: IfNotPresent
# RELAX RESOURCE LIMITS TO PREVENT THREAD STALLS
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "6000m" # Allow full core utilization during deep video transcodes
memory: 4Gi # Slightly higher ceiling for large video processing blocks
env:
PUID: "1000"
PGID: "1000"
JWT_SECRET: "d173a64678b199b21c0bc52ef17da56cec31f3eedc3685e68b394b7bc119e38b"
HTTP_ALLOWED: "true"
ALLOW_UNAUTHENTICATED: "false"
# APPLICATION LEVEL CONCURRENCY LIMIT
MAX_CONVERT_PROCESS: "1" # Restricts the app to 1 conversion at a time to prevent CPU crowding
securityContext:
privileged: true
service:
main:
controller: main
type: NodePort
ports:
http:
port: 3050
targetPort: 3000
nodePort: 32050
persistence:
data:
enabled: true
type: persistentVolumeClaim
storageClass: "longhorn"
accessMode: ReadWriteOnce
size: 10Gi
globalMounts:
- path: /app/data
igpu:
enabled: true
type: hostPath
hostPath: /dev/dri
globalMounts:
- path: /dev/dri
# values.yaml
ingress:
main:
enabled: true
className: nginx
annotations:
# AUTOMATED TLS FIX: Triggers cert-manager to provision the certificate
cert-manager.io/cluster-issuer: "letsencrypt-production"
# THE 502 FIX: Bridges to the unencrypted pod port 3050 safely
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
hosts:
- host: convertx.needlestack.boo
paths:
- path: /
pathType: Prefix
service:
identifier: main
port: 3050
# AUTOMATED TLS FIX: Instructs NGINX where to store the secret
tls:
- secretName: convertx-tls-secret
hosts:
- convertx.needlestack.boo

188
gitea/gitea-stack.yaml Normal file
View File

@ -0,0 +1,188 @@
apiVersion: v1
kind: Namespace
metadata:
name: gitea
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gitea-postgres-pvc
namespace: gitea
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: longhorn
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gitea-app-pvc
namespace: gitea
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: longhorn
---
apiVersion: v1
kind: Service
metadata:
name: gitea-postgres-service
namespace: gitea
spec:
ports:
- port: 5432
targetPort: 5432
selector:
app: gitea-postgres
type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
name: gitea-service
namespace: gitea
spec:
ports:
- name: http
port: 80
targetPort: 3000
- name: ssh
port: 2222
targetPort: 2222
selector:
app: gitea-app
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea-postgres
namespace: gitea
spec:
replicas: 1
selector:
matchLabels:
app: gitea-postgres
template:
metadata:
labels:
app: gitea-postgres
spec:
dnsConfig:
nameservers:
- 1.1.1.1
- 8.8.8.8
dnsPolicy: None
containers:
- name: postgres
image: postgres:15-alpine
env:
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
- name: POSTGRES_USER
value: gitea_admin
- name: POSTGRES_PASSWORD
value: NeedlestackCodeVault2026
- name: POSTGRES_DB
value: giteadb
ports:
- containerPort: 5432
name: dbport
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: db-data
volumes:
- name: db-data
persistentVolumeClaim:
claimName: gitea-postgres-pvc
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea-app
namespace: gitea
spec:
replicas: 1
selector:
matchLabels:
app: gitea-app
template:
metadata:
labels:
app: gitea-app
spec:
securityContext: # <-- ADD THIS SECTION
fsGroup: 1000 # <-- FORCES STORAGE VOLUMES TO BE OWNED BY USER 1000
containers:
- name: gitea
image: gitea/gitea:1.21-rootless
env:
# Core Database Settings
- name: GITEA__database__DB_TYPE
value: postgres
- name: GITEA__database__HOST
value: gitea-postgres-service:5432
- name: GITEA__database__NAME
value: giteadb
- name: GITEA__database__USER
value: gitea_admin
- name: GITEA__database__PASSWD
value: NeedlestackCodeVault2026
# Rootless Paths Fixes (Maps configuration to persistent /data)
- name: GITEA_APP_INI
value: /data/gitea/conf/app.ini
- name: GITEA_CUSTOM
value: /data/gitea
- name: GITEA_WORK_DIR
value: /data/gitea
# The Security Fixes (Bypasses installer & disables public sign-ups)
- name: GITEA__security__INSTALL_LOCK
value: "true"
- name: GITEA__service__DISABLE_REGISTRATION
value: "true"
ports:
- containerPort: 3000
name: http
- containerPort: 2222
name: ssh
volumeMounts:
- mountPath: /data
name: gitea-data
volumes:
- name: gitea-data
persistentVolumeClaim:
claimName: gitea-app-pvc
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gitea-local-ingress
namespace: gitea
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-production"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
ingressClassName: nginx
tls:
- secretName: gitea-tls-secret
hosts:
- git.needlestack.boo
rules:
- host: git.needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gitea-service
port:
number: 80

29
gitea/ingress.yaml Normal file
View File

@ -0,0 +1,29 @@
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gitea-local-ingress
namespace: gitea
annotations:
# AUTOMATED TLS FIX: Triggers cert-manager to provision the certificate
cert-manager.io/cluster-issuer: "letsencrypt-production"
# THE 502 FIX: Instructs NGINX to bridge to the unencrypted pod port 80
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
ingressClassName: nginx
# AUTOMATED TLS FIX: Instructs NGINX where to mount the generated certificate
tls:
- secretName: gitea-tls-secret
hosts:
- git.needlestack.boo
rules:
- host: git.needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gitea-service
port:
number: 80

397
gitea/resources.yaml Normal file
View File

@ -0,0 +1,397 @@
apiVersion: v1
items:
- apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "3"
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"gitea-app","namespace":"gitea"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"gitea-app"}},"template":{"metadata":{"labels":{"app":"gitea-app"}},"spec":{"containers":[{"env":[{"name":"GITEA__database__DB_TYPE","value":"postgres"},{"name":"GITEA__database__HOST","value":"gitea-postgres-service:5432"},{"name":"GITEA__database__NAME","value":"giteadb"},{"name":"GITEA__database__USER","value":"gitea_admin"},{"name":"GITEA__database__PASSWD","value":"NeedlestackCodeVault2026"}],"image":"gitea/gitea:1.21-rootless","name":"gitea","ports":[{"containerPort":3000,"name":"http"},{"containerPort":2222,"name":"ssh"}],"volumeMounts":[{"mountPath":"/data","name":"gitea-data"}]}],"volumes":[{"name":"gitea-data","persistentVolumeClaim":{"claimName":"gitea-app-pvc"}}]}}}}
creationTimestamp: "2026-09-21T21:51:38Z"
generation: 5
name: gitea-app
namespace: gitea
resourceVersion: "4415267"
uid: 46e7fffd-bd04-4e55-a82a-001fb7f459f6
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: gitea-app
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
annotations:
kubectl.kubernetes.io/restartedAt: "2026-09-21T22:09:01Z"
creationTimestamp: null
labels:
app: gitea-app
spec:
containers:
- env:
- name: GITEA__database__DB_TYPE
value: postgres
- name: GITEA__database__HOST
value: gitea-postgres-service:5432
- name: GITEA__database__NAME
value: giteadb
- name: GITEA__database__USER
value: gitea_admin
- name: GITEA__database__PASSWD
value: NeedlestackCodeVault2026
image: gitea/gitea:1.21-rootless
imagePullPolicy: IfNotPresent
name: gitea
ports:
- containerPort: 3000
name: http
protocol: TCP
- containerPort: 2222
name: ssh
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /data
name: gitea-data
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: gitea-data
persistentVolumeClaim:
claimName: gitea-app-pvc
status:
availableReplicas: 1
conditions:
- lastTransitionTime: "2026-09-21T21:51:38Z"
lastUpdateTime: "2026-09-21T22:11:07Z"
message: ReplicaSet "gitea-app-644f4c9577" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
- lastTransitionTime: "2026-09-21T22:11:36Z"
lastUpdateTime: "2026-09-21T22:11:36Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
observedGeneration: 5
readyReplicas: 1
replicas: 1
updatedReplicas: 1
- apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "2"
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"gitea-postgres","namespace":"gitea"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"gitea-postgres"}},"template":{"metadata":{"labels":{"app":"gitea-postgres"}},"spec":{"containers":[{"env":[{"name":"PGDATA","value":"/var/lib/postgresql/data/pgdata"},{"name":"POSTGRES_USER","value":"gitea_admin"},{"name":"POSTGRES_PASSWORD","value":"NeedlestackCodeVault2026"},{"name":"POSTGRES_DB","value":"giteadb"}],"image":"postgres:15-alpine","name":"postgres","ports":[{"containerPort":5432,"name":"dbport"}],"volumeMounts":[{"mountPath":"/var/lib/postgresql/data","name":"db-data"}]}],"dnsConfig":{"nameservers":["1.1.1.1","8.8.8.8"]},"dnsPolicy":"None","volumes":[{"name":"db-data","persistentVolumeClaim":{"claimName":"gitea-postgres-pvc"}}]}}}}
creationTimestamp: "2026-09-21T21:51:14Z"
generation: 2
name: gitea-postgres
namespace: gitea
resourceVersion: "4410146"
uid: df85a488-1a17-46f3-ae75-e7911f61d110
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: gitea-postgres
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: gitea-postgres
spec:
containers:
- env:
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
- name: POSTGRES_USER
value: gitea_admin
- name: POSTGRES_PASSWORD
value: NeedlestackCodeVault2026
- name: POSTGRES_DB
value: giteadb
image: postgres:15-alpine
imagePullPolicy: IfNotPresent
name: postgres
ports:
- containerPort: 5432
name: dbport
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: db-data
dnsConfig:
nameservers:
- 1.1.1.1
- 8.8.8.8
dnsPolicy: None
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: db-data
persistentVolumeClaim:
claimName: gitea-postgres-pvc
status:
availableReplicas: 1
conditions:
- lastTransitionTime: "2026-09-21T21:53:43Z"
lastUpdateTime: "2026-09-21T21:53:43Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: "2026-09-21T21:51:14Z"
lastUpdateTime: "2026-09-21T21:53:43Z"
message: ReplicaSet "gitea-postgres-5d7986b4b8" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
observedGeneration: 2
readyReplicas: 1
replicas: 1
updatedReplicas: 1
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"name":"gitea-app-pvc","namespace":"gitea"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"20Gi"}},"storageClassName":"longhorn"}}
pv.kubernetes.io/bind-completed: "yes"
pv.kubernetes.io/bound-by-controller: "yes"
volume.beta.kubernetes.io/storage-provisioner: driver.longhorn.io
volume.kubernetes.io/storage-provisioner: driver.longhorn.io
creationTimestamp: "2026-09-21T21:51:38Z"
finalizers:
- kubernetes.io/pvc-protection
name: gitea-app-pvc
namespace: gitea
resourceVersion: "4409403"
uid: 509d3566-6a32-47e9-94f9-c9dc66cd00f3
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: longhorn
volumeMode: Filesystem
volumeName: pvc-509d3566-6a32-47e9-94f9-c9dc66cd00f3
status:
accessModes:
- ReadWriteOnce
capacity:
storage: 20Gi
phase: Bound
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"name":"gitea-postgres-pvc","namespace":"gitea"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"10Gi"}},"storageClassName":"longhorn"}}
pv.kubernetes.io/bind-completed: "yes"
pv.kubernetes.io/bound-by-controller: "yes"
volume.beta.kubernetes.io/storage-provisioner: driver.longhorn.io
volume.kubernetes.io/storage-provisioner: driver.longhorn.io
creationTimestamp: "2026-09-21T21:51:14Z"
finalizers:
- kubernetes.io/pvc-protection
name: gitea-postgres-pvc
namespace: gitea
resourceVersion: "4409170"
uid: 5da54bab-fc4d-4633-80bc-959c00115f46
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: longhorn
volumeMode: Filesystem
volumeName: pvc-5da54bab-fc4d-4633-80bc-959c00115f46
status:
accessModes:
- ReadWriteOnce
capacity:
storage: 10Gi
phase: Bound
- apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"gitea-postgres-service","namespace":"gitea"},"spec":{"ports":[{"port":5432,"targetPort":5432}],"selector":{"app":"gitea-postgres"}}}
creationTimestamp: "2026-09-21T21:51:14Z"
name: gitea-postgres-service
namespace: gitea
resourceVersion: "4409101"
uid: 826733f9-3f03-4289-921b-94f283f9e360
spec:
clusterIP: 10.43.238.230
clusterIPs:
- 10.43.238.230
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- port: 5432
protocol: TCP
targetPort: 5432
selector:
app: gitea-postgres
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
- apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"gitea-service","namespace":"gitea"},"spec":{"ports":[{"name":"http","port":80,"targetPort":3000},{"name":"ssh","port":2222,"targetPort":2222}],"selector":{"app":"gitea-app"}}}
creationTimestamp: "2026-09-21T21:51:38Z"
name: gitea-service
namespace: gitea
resourceVersion: "4409344"
uid: e6ca70bd-1eeb-48e7-b800-6193a15fcb76
spec:
clusterIP: 10.43.6.10
clusterIPs:
- 10.43.6.10
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: http
port: 80
protocol: TCP
targetPort: 3000
- name: ssh
port: 2222
protocol: TCP
targetPort: 2222
selector:
app: gitea-app
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
- apiVersion: batch/v1
kind: CronJob
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"batch/v1","kind":"CronJob","metadata":{"annotations":{},"name":"cluster-yaml-backup","namespace":"gitea"},"spec":{"concurrencyPolicy":"Forbid","jobTemplate":{"spec":{"template":{"spec":{"containers":[{"command":["/bin/sh","-c","echo \"=== Starting Automated Cluster Backup ===\"\n\n# Configure local git repository tracking parameters\ngit config --global user.name \"Cluster Backup Engine\"\ngit config --global user.email \"backup@needlestack.boo\"\ngit config --global safe.directory '*'\n\n# Constructing authorized credentials paths using the 4-part internal IP\nTARGET_IP=\"10.43.6.10\"\nCLONE_URL=\"http://${GITEA_USER}:${GITEA_TOKEN}@${TARGET_IP}/${GITEA_USER}/${GITEA_REPO}.git\"\nPUSH_URL=\"http://${GITEA_USER}:${GITEA_TOKEN}@${TARGET_IP}/${GITEA_USER}/${GITEA_REPO}.git\"\n\n# Safely download the private repository shell using the injected token keys\ngit clone ${CLONE_URL} /tmp/backup\ncd /tmp/backup\n\n# Refresh backup layout data paths\nrm -rf manifests/\nmkdir -p manifests/\n\n# Extract clean YAML resource records across the namespaces\nfor ns in open-webui homepage mumble adguard; do\n echo \"Backing up namespace: ${ns}\"\n mkdir -p \"manifests/${ns}\"\n kubectl get deployment,pvc,svc,ingress,cronjob,namespace -n ${ns} -o yaml \u003e \"manifests/${ns}/resources.yaml\" 2\u003e/dev/null\ndone\n\n# Sync the layout changes back into the private vault logs\ngit add .\nif ! git diff-index --quiet HEAD --; then\n git commit -m \"Automated backup: $(date +'%Y-%m-%d %H:%M:%S')\"\n git push ${PUSH_URL} main\n echo \"=== Backup Pushed Successfully ===\"\nelse\n echo \"=== No changes detected. Skipping push ===\"\nfi\n"],"env":[{"name":"GITEA_USER","value":"needlestack"},{"name":"GITEA_REPO","value":"cluster-manifests"},{"name":"GITEA_TOKEN","value":"4a403fa7615feea2cbeb0c1f98fcacc48b84d95a"}],"image":"alpine/k8s:1.28.2","name":"backup-worker"}],"restartPolicy":"OnFailure","serviceAccountName":"default"}}}},"schedule":"0 0 * * *"}}
creationTimestamp: "2026-09-21T22:38:26Z"
generation: 10
name: cluster-yaml-backup
namespace: gitea
resourceVersion: "7914165"
uid: 8fde5768-6601-451d-885c-b919d3c9ae00
spec:
concurrencyPolicy: Forbid
failedJobsHistoryLimit: 1
jobTemplate:
metadata:
creationTimestamp: null
spec:
template:
metadata:
creationTimestamp: null
spec:
containers:
- command:
- /bin/sh
- -c
- |
echo "=== Starting Automated Cluster Backup ==="
# Configure local git repository tracking parameters
git config --global user.name "Cluster Backup Engine"
git config --global user.email "backup@needlestack.boo"
git config --global safe.directory '*'
# Constructing authorized credentials paths using the 4-part internal IP
TARGET_IP="10.43.6.10"
CLONE_URL="http://${GITEA_USER}:${GITEA_TOKEN}@${TARGET_IP}/${GITEA_USER}/${GITEA_REPO}.git"
PUSH_URL="http://${GITEA_USER}:${GITEA_TOKEN}@${TARGET_IP}/${GITEA_USER}/${GITEA_REPO}.git"
# Safely download the private repository shell using the injected token keys
git clone ${CLONE_URL} /tmp/backup
cd /tmp/backup
# Refresh backup layout data paths
rm -rf manifests/
mkdir -p manifests/
# Extract clean YAML resource records across the namespaces
for ns in open-webui homepage mumble adguard; do
echo "Backing up namespace: ${ns}"
mkdir -p "manifests/${ns}"
kubectl get deployment,pvc,svc,ingress,cronjob,namespace -n ${ns} -o yaml > "manifests/${ns}/resources.yaml" 2>/dev/null
done
# Sync the layout changes back into the private vault logs
git add .
if ! git diff-index --quiet HEAD --; then
git commit -m "Automated backup: $(date +'%Y-%m-%d %H:%M:%S')"
git push ${PUSH_URL} main
echo "=== Backup Pushed Successfully ==="
else
echo "=== No changes detected. Skipping push ==="
fi
env:
- name: GITEA_USER
value: needlestack
- name: GITEA_REPO
value: cluster-manifests
- name: GITEA_TOKEN
value: 4a403fa7615feea2cbeb0c1f98fcacc48b84d95a
image: alpine/k8s:1.28.2
imagePullPolicy: Always
name: backup-worker
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: OnFailure
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
schedule: 0 0 * * *
successfulJobsHistoryLimit: 3
suspend: false
status:
lastScheduleTime: "2026-09-30T00:00:00Z"
lastSuccessfulTime: "2026-09-30T00:00:05Z"
kind: List
metadata:
resourceVersion: ""

99
homepage/homepage.yaml Normal file
View File

@ -0,0 +1,99 @@
apiVersion: v1
kind: Namespace
metadata:
name: homepage
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: homepage-config-pvc
namespace: homepage
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: longhorn
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: homepage
namespace: homepage
spec:
replicas: 1
strategy:
type: RollingUpdate
selector:
matchLabels:
app: homepage
template:
metadata:
labels:
app: homepage
spec:
containers:
- name: homepage
image: ghcr.io/gethomepage/homepage:latest
imagePullPolicy: Always
ports:
- containerPort: 3000
name: http
protocol: TCP
env:
- name: HOMEPAGE_ALLOWED_HOSTS
value: needlestack.boo,localhost:3000
volumeMounts:
- mountPath: /app/config
name: config-volume
volumes:
- name: config-volume
persistentVolumeClaim:
claimName: homepage-config-pvc
---
apiVersion: v1
kind: Service
metadata:
name: homepage-service
namespace: homepage
spec:
type: ClusterIP
selector:
app: homepage
ports:
- port: 80
protocol: TCP
targetPort: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: homepage-local-ingress
namespace: homepage
annotations:
# AUTOMATED TLS FIX: Triggers cert-manager to provision the certificate
cert-manager.io/cluster-issuer: "letsencrypt-production"
# THE 502 FIX: Instructs NGINX to bridge to the unencrypted pod port safely
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
ingressClassName: nginx
tls:
- secretName: homepage-tls-secret
hosts:
- needlestack.boo
rules:
- host: needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: homepage-service
port:
number: 80

29
homepage/ingress.yaml Normal file
View File

@ -0,0 +1,29 @@
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: homepage-local-ingress
namespace: homepage
annotations:
# AUTOMATED TLS FIX: Triggers cert-manager to provision the certificate
cert-manager.io/cluster-issuer: "letsencrypt-production"
# THE 502 FIX: Instructs NGINX how to bridge the internal pod connection protocol
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
ingressClassName: nginx
# AUTOMATED TLS FIX: Instructs NGINX where to mount the generated certificate
tls:
- secretName: homepage-tls-secret
hosts:
- needlestack.boo
rules:
- host: needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: homepage-service
port:
number: 80

430
homepage/resources.yaml Normal file
View File

@ -0,0 +1,430 @@
apiVersion: v1
items:
- apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "3"
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"homepage","namespace":"homepage"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"homepage"}},"template":{"metadata":{"labels":{"app":"homepage"}},"spec":{"containers":[{"env":[{"name":"HOMEPAGE_ALLOWED_HOSTS","value":"needlestack.boo,localhost:3000"}],"image":"ghcr.io/gethomepage/homepage:latest","name":"homepage","ports":[{"containerPort":3000,"name":"http"}],"volumeMounts":[{"mountPath":"/app/config","name":"config-volume"}]}],"dnsConfig":{"nameservers":["1.1.1.1","8.8.8.8"]},"dnsPolicy":"None","volumes":[{"name":"config-volume","persistentVolumeClaim":{"claimName":"homepage-config-pvc"}}]}}}}
creationTimestamp: "2026-09-18T22:22:12Z"
generation: 9
name: homepage
namespace: homepage
resourceVersion: "3247538"
uid: 30d404a3-fcc7-47df-bb80-e1dbb346e606
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: homepage
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
annotations:
kubectl.kubernetes.io/restartedAt: "2026-09-18T22:31:21Z"
creationTimestamp: null
labels:
app: homepage
spec:
containers:
- env:
- name: HOMEPAGE_ALLOWED_HOSTS
value: needlestack.boo,localhost:3000
image: ghcr.io/gethomepage/homepage:latest
imagePullPolicy: Always
name: homepage
ports:
- containerPort: 3000
name: http
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /app/config
name: config-volume
dnsConfig:
nameservers:
- 1.1.1.1
- 8.8.8.8
dnsPolicy: None
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: config-volume
persistentVolumeClaim:
claimName: homepage-config-pvc
status:
availableReplicas: 1
conditions:
- lastTransitionTime: "2026-09-18T22:22:12Z"
lastUpdateTime: "2026-09-18T22:37:08Z"
message: ReplicaSet "homepage-58584558c7" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
- lastTransitionTime: "2026-09-18T23:14:50Z"
lastUpdateTime: "2026-09-18T23:14:50Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
observedGeneration: 9
readyReplicas: 1
replicas: 1
updatedReplicas: 1
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"name":"homepage-config-pvc","namespace":"homepage"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":"longhorn"}}
pv.kubernetes.io/bind-completed: "yes"
pv.kubernetes.io/bound-by-controller: "yes"
volume.beta.kubernetes.io/storage-provisioner: driver.longhorn.io
volume.kubernetes.io/storage-provisioner: driver.longhorn.io
creationTimestamp: "2026-09-18T22:22:12Z"
finalizers:
- kubernetes.io/pvc-protection
name: homepage-config-pvc
namespace: homepage
resourceVersion: "3232764"
uid: 2cd12c3c-0f79-46b5-94c6-c61d96a0b57a
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: longhorn
volumeMode: Filesystem
volumeName: pvc-2cd12c3c-0f79-46b5-94c6-c61d96a0b57a
status:
accessModes:
- ReadWriteOnce
capacity:
storage: 5Gi
phase: Bound
- apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"homepage-service","namespace":"homepage"},"spec":{"ports":[{"port":80,"targetPort":3000}],"selector":{"app":"homepage"}}}
creationTimestamp: "2026-09-18T22:22:12Z"
name: homepage-service
namespace: homepage
resourceVersion: "3232702"
uid: 6c1eeb77-f148-40eb-be19-e567aaba7743
spec:
clusterIP: 10.43.18.81
clusterIPs:
- 10.43.18.81
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- port: 80
protocol: TCP
targetPort: 3000
selector:
app: homepage
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T21:33:05Z"
labels:
kubernetes.io/metadata.name: adguard
name: adguard
name: adguard
resourceVersion: "41653"
uid: 6d812d6a-1921-4169-9805-7d1192073f46
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-12T20:23:24Z"
labels:
kubernetes.io/metadata.name: bookstack
name: bookstack
name: bookstack
resourceVersion: "829004"
uid: e5c59011-b6b6-4f53-a655-a140b7363443
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"bookstack-db"}}
creationTimestamp: "2026-09-12T20:39:27Z"
labels:
kubernetes.io/metadata.name: bookstack-db
name: bookstack-db
resourceVersion: "834254"
uid: 9600ab15-9b1a-451b-af4e-13ff3b672331
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T22:46:31Z"
labels:
kubernetes.io/metadata.name: cert-manager
name: cert-manager
name: cert-manager
resourceVersion: "61514"
uid: 05b40520-6a11-49af-96df-3d3289a9ed8f
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"cloudflare"}}
creationTimestamp: "2026-09-12T15:12:46Z"
labels:
kubernetes.io/metadata.name: cloudflare
name: cloudflare
resourceVersion: "737700"
uid: f294d89c-0348-444a-b2a8-57303311e45e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: default
name: default
resourceVersion: "266"
uid: ae7a3d3e-3d08-43fe-8e2c-8f72ef066b9e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"gitea"}}
creationTimestamp: "2026-09-21T21:51:14Z"
labels:
kubernetes.io/metadata.name: gitea
name: gitea
resourceVersion: "4409092"
uid: 6398ba34-919b-4392-afbf-ef0054176a1b
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"homepage"}}
creationTimestamp: "2026-09-18T22:22:12Z"
labels:
kubernetes.io/metadata.name: homepage
name: homepage
resourceVersion: "3232692"
uid: eaafb62a-9a9a-45f3-a7b4-7fa4d1e2ae6b
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T19:46:49Z"
labels:
kubernetes.io/metadata.name: ingress-nginx
name: ingress-nginx
name: ingress-nginx
resourceVersion: "12923"
uid: 46118181-4db6-4c3c-9fdc-f8cc20f28323
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"intel-device-plugin"}}
creationTimestamp: "2026-09-17T20:41:41Z"
labels:
kubernetes.io/metadata.name: intel-device-plugin
name: intel-device-plugin
resourceVersion: "2809324"
uid: b132d304-80cb-4bdc-88cd-2073a8239312
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: kube-node-lease
name: kube-node-lease
resourceVersion: "267"
uid: 81e945a2-a9f5-4ddc-83a8-2bc214a1559e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: kube-public
name: kube-public
resourceVersion: "268"
uid: 2142a69f-f0bd-45af-8738-563df7f99012
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: kube-system
name: kube-system
resourceVersion: "269"
uid: 1b18f0bc-7131-46b4-9e4b-bb0af3d7d63e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T19:35:47Z"
labels:
kubernetes.io/metadata.name: longhorn-system
name: longhorn-system
name: longhorn-system
resourceVersion: "9213"
uid: abd04167-9f4b-468e-a637-1649efff2bc7
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"mumble"}}
creationTimestamp: "2026-09-19T18:14:35Z"
labels:
kubernetes.io/metadata.name: mumble
name: mumble
resourceVersion: "3560003"
uid: cc88370b-9275-43f6-a1f9-2bb663600c48
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"nordvpn"}}
creationTimestamp: "2026-09-11T20:23:38Z"
labels:
kubernetes.io/metadata.name: nordvpn
name: nordvpn
resourceVersion: "417127"
uid: 15f7c8a5-1b18-475f-84dc-90e5963814fa
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"open-webui"}}
creationTimestamp: "2026-09-17T21:09:55Z"
labels:
kubernetes.io/metadata.name: open-webui
name: open-webui
resourceVersion: "2817739"
uid: 74bf3bef-51bc-405e-8f79-ebc9f52281c6
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T19:56:57Z"
labels:
kubernetes.io/metadata.name: portainer
name: portainer
name: portainer
resourceVersion: "16301"
uid: 17802103-8a9c-4b8f-aa42-03a0db58d2ae
spec:
finalizers:
- kubernetes
status:
phase: Active
kind: List
metadata:
resourceVersion: ""

33
immich/ingress.yaml Normal file
View File

@ -0,0 +1,33 @@
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: immich-local-ingress
namespace: immich
annotations:
# AUTOMATED TLS FIX: Triggers cert-manager to provision the certificate
cert-manager.io/cluster-issuer: "letsencrypt-production"
# THE 502 FIX: Instructs NGINX to bridge to the unencrypted pod port 2283
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
# THE UPLOAD FIX: Disables NGINX's default 1MB file size boundary block
nginx.ingress.kubernetes.io/proxy-body-size: "0"
# Optional but highly recommended: Stops NGINX from buffering heavy media uploads to local node drives first
nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
spec:
ingressClassName: nginx
# AUTOMATED TLS FIX: Instructs NGINX where to mount the generated certificate
tls:
- secretName: immich-tls-secret
hosts:
- photos.needlestack.boo
rules:
- host: photos.needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: immich-server
port:
number: 2283

36
immich/values.yaml Normal file
View File

@ -0,0 +1,36 @@
controllers:
main:
containers:
main:
env:
DB_HOSTNAME: "immich-db-rw.immich.svc.cluster.local"
DB_DATABASE_NAME: "app"
DB_USERNAME: "app"
DB_PASSWORD: "OJPYu0ilCbLAu7bqG2ydDbjCdl7DHHKapKoB89aiZ64UJwFnMJZ0t3ZPmtVbjVel"
DB_PORT: "5432"
REDIS_HOSTNAME: "immich-valkey"
IMMICH_MACHINE_LEARNING_URL: "http://immich-machine-learning.immich.svc.cluster.local:2283"
securityContext:
privileged: true
immich:
persistence:
library:
existingClaim: "immich-photo-library-pvc"
valkey:
enabled: true
service:
main:
type: NodePort
ports:
http:
port: 2283
persistence:
devdri:
enabled: true
type: hostPath
hostPath: /dev/dri
globalMounts:
- path: /dev/dri
ingress:
main:
enabled: false

View File

@ -0,0 +1,42 @@
# monitoring-values.yaml
prometheus:
prometheusSpec:
# Forces Prometheus to find ServiceMonitors cluster-wide (like blocky in kube-system)
serviceMonitorSelectorNilUsesHelmValues: false
ingress:
enabled: true
ingressClassName: nginx
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-production"
# THE 502 FIX: Instructs NGINX to bridge to the unencrypted pod port safely
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
hosts:
- prometheus.needlestack.boo
paths:
- /
pathType: Prefix
tls:
- secretName: prometheus-tls-secret
hosts:
- prometheus.needlestack.boo
grafana:
ingress:
enabled: true
ingressClassName: nginx
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-production"
# THE 502 FIX: Instructs NGINX to bridge to the unencrypted pod port safely
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
hosts:
- grafana.needlestack.boo
# THE SCHEMA FIX: Wrapped as an explicit array object to match the chart constraints
paths:
- /
pathType: Prefix
tls:
- secretName: grafana-tls-secret
hosts:
- grafana.needlestack.boo

432
mumble/resources.yaml Normal file
View File

@ -0,0 +1,432 @@
apiVersion: v1
items:
- apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"mumble","namespace":"mumble"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"mumble"}},"template":{"metadata":{"labels":{"app":"mumble"}},"spec":{"containers":[{"image":"mumblevoip/mumble-server:latest","name":"murmur","ports":[{"containerPort":64738,"name":"mumble-tcp","protocol":"TCP"},{"containerPort":64738,"name":"mumble-udp","protocol":"UDP"}],"volumeMounts":[{"mountPath":"/data","name":"mumble-storage"}]}],"volumes":[{"name":"mumble-storage","persistentVolumeClaim":{"claimName":"mumble-data-pvc"}}]}}}}
creationTimestamp: "2026-09-19T18:14:35Z"
generation: 1
name: mumble
namespace: mumble
resourceVersion: "3560270"
uid: 04f642f1-3525-4db7-88fe-4b09259c6264
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: mumble
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: mumble
spec:
containers:
- image: mumblevoip/mumble-server:latest
imagePullPolicy: Always
name: murmur
ports:
- containerPort: 64738
name: mumble-tcp
protocol: TCP
- containerPort: 64738
name: mumble-udp
protocol: UDP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /data
name: mumble-storage
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: mumble-storage
persistentVolumeClaim:
claimName: mumble-data-pvc
status:
availableReplicas: 1
conditions:
- lastTransitionTime: "2026-09-19T18:15:06Z"
lastUpdateTime: "2026-09-19T18:15:06Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: "2026-09-19T18:14:35Z"
lastUpdateTime: "2026-09-19T18:15:06Z"
message: ReplicaSet "mumble-757c5c899d" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
observedGeneration: 1
readyReplicas: 1
replicas: 1
updatedReplicas: 1
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"name":"mumble-data-pvc","namespace":"mumble"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"2Gi"}},"storageClassName":"longhorn"}}
pv.kubernetes.io/bind-completed: "yes"
pv.kubernetes.io/bound-by-controller: "yes"
volume.beta.kubernetes.io/storage-provisioner: driver.longhorn.io
volume.kubernetes.io/storage-provisioner: driver.longhorn.io
creationTimestamp: "2026-09-19T18:14:35Z"
finalizers:
- kubernetes.io/pvc-protection
name: mumble-data-pvc
namespace: mumble
resourceVersion: "3560074"
uid: 85fb334b-6399-4887-917c-09e703d2a0d5
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
storageClassName: longhorn
volumeMode: Filesystem
volumeName: pvc-85fb334b-6399-4887-917c-09e703d2a0d5
status:
accessModes:
- ReadWriteOnce
capacity:
storage: 2Gi
phase: Bound
- apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"mumble-service","namespace":"mumble"},"spec":{"ports":[{"name":"mumble-tcp","nodePort":31738,"port":64738,"protocol":"TCP","targetPort":64738},{"name":"mumble-udp","nodePort":31738,"port":64738,"protocol":"UDP","targetPort":64738}],"selector":{"app":"mumble"},"type":"NodePort"}}
creationTimestamp: "2026-09-19T18:14:35Z"
name: mumble-service
namespace: mumble
resourceVersion: "3560016"
uid: c20b0b3a-5d1d-45e4-aec4-37659797bb49
spec:
clusterIP: 10.43.235.20
clusterIPs:
- 10.43.235.20
externalTrafficPolicy: Cluster
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: mumble-tcp
nodePort: 31738
port: 64738
protocol: TCP
targetPort: 64738
- name: mumble-udp
nodePort: 31738
port: 64738
protocol: UDP
targetPort: 64738
selector:
app: mumble
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T21:33:05Z"
labels:
kubernetes.io/metadata.name: adguard
name: adguard
name: adguard
resourceVersion: "41653"
uid: 6d812d6a-1921-4169-9805-7d1192073f46
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-12T20:23:24Z"
labels:
kubernetes.io/metadata.name: bookstack
name: bookstack
name: bookstack
resourceVersion: "829004"
uid: e5c59011-b6b6-4f53-a655-a140b7363443
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"bookstack-db"}}
creationTimestamp: "2026-09-12T20:39:27Z"
labels:
kubernetes.io/metadata.name: bookstack-db
name: bookstack-db
resourceVersion: "834254"
uid: 9600ab15-9b1a-451b-af4e-13ff3b672331
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T22:46:31Z"
labels:
kubernetes.io/metadata.name: cert-manager
name: cert-manager
name: cert-manager
resourceVersion: "61514"
uid: 05b40520-6a11-49af-96df-3d3289a9ed8f
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"cloudflare"}}
creationTimestamp: "2026-09-12T15:12:46Z"
labels:
kubernetes.io/metadata.name: cloudflare
name: cloudflare
resourceVersion: "737700"
uid: f294d89c-0348-444a-b2a8-57303311e45e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: default
name: default
resourceVersion: "266"
uid: ae7a3d3e-3d08-43fe-8e2c-8f72ef066b9e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"gitea"}}
creationTimestamp: "2026-09-21T21:51:14Z"
labels:
kubernetes.io/metadata.name: gitea
name: gitea
resourceVersion: "4409092"
uid: 6398ba34-919b-4392-afbf-ef0054176a1b
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"homepage"}}
creationTimestamp: "2026-09-18T22:22:12Z"
labels:
kubernetes.io/metadata.name: homepage
name: homepage
resourceVersion: "3232692"
uid: eaafb62a-9a9a-45f3-a7b4-7fa4d1e2ae6b
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T19:46:49Z"
labels:
kubernetes.io/metadata.name: ingress-nginx
name: ingress-nginx
name: ingress-nginx
resourceVersion: "12923"
uid: 46118181-4db6-4c3c-9fdc-f8cc20f28323
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"intel-device-plugin"}}
creationTimestamp: "2026-09-17T20:41:41Z"
labels:
kubernetes.io/metadata.name: intel-device-plugin
name: intel-device-plugin
resourceVersion: "2809324"
uid: b132d304-80cb-4bdc-88cd-2073a8239312
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: kube-node-lease
name: kube-node-lease
resourceVersion: "267"
uid: 81e945a2-a9f5-4ddc-83a8-2bc214a1559e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: kube-public
name: kube-public
resourceVersion: "268"
uid: 2142a69f-f0bd-45af-8738-563df7f99012
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: kube-system
name: kube-system
resourceVersion: "269"
uid: 1b18f0bc-7131-46b4-9e4b-bb0af3d7d63e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T19:35:47Z"
labels:
kubernetes.io/metadata.name: longhorn-system
name: longhorn-system
name: longhorn-system
resourceVersion: "9213"
uid: abd04167-9f4b-468e-a637-1649efff2bc7
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"mumble"}}
creationTimestamp: "2026-09-19T18:14:35Z"
labels:
kubernetes.io/metadata.name: mumble
name: mumble
resourceVersion: "3560003"
uid: cc88370b-9275-43f6-a1f9-2bb663600c48
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"nordvpn"}}
creationTimestamp: "2026-09-11T20:23:38Z"
labels:
kubernetes.io/metadata.name: nordvpn
name: nordvpn
resourceVersion: "417127"
uid: 15f7c8a5-1b18-475f-84dc-90e5963814fa
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"open-webui"}}
creationTimestamp: "2026-09-17T21:09:55Z"
labels:
kubernetes.io/metadata.name: open-webui
name: open-webui
resourceVersion: "2817739"
uid: 74bf3bef-51bc-405e-8f79-ebc9f52281c6
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T19:56:57Z"
labels:
kubernetes.io/metadata.name: portainer
name: portainer
name: portainer
resourceVersion: "16301"
uid: 17802103-8a9c-4b8f-aa42-03a0db58d2ae
spec:
finalizers:
- kubernetes
status:
phase: Active
kind: List
metadata:
resourceVersion: ""

34
open-webui/ingress.yaml Normal file
View File

@ -0,0 +1,34 @@
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: openwebui-local-ingress
namespace: open-webui
annotations:
# AUTOMATED TLS FIX: Triggers cert-manager to provision the certificate
cert-manager.io/cluster-issuer: "letsencrypt-production"
# THE 502 FIX: Instructs NGINX to bridge to the unencrypted pod port 80
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
# THE STREAMING FIX: Forces NGINX to instantly forward tokens to your browser
nginx.ingress.kubernetes.io/proxy-buffering: "off"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec:
ingressClassName: nginx
# AUTOMATED TLS FIX: Instructs NGINX where to mount the generated certificate
tls:
- secretName: openwebui-tls-secret
hosts:
- ai.needlestack.boo
rules:
- host: ai.needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: open-webui-service
port:
number: 80

View File

@ -0,0 +1,68 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ollama-fallback
namespace: open-webui
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: ollama-fallback
template:
metadata:
labels:
app: ollama-fallback
spec:
# Pin the pod strictly to Node 3
nodeSelector:
kubernetes.io/hostname: nst-node-3
containers:
- name: ollama
# THE BOOT FIX: Using a frozen tag allows local caching, bypassing the 8-minute pull
image: ollama/ollama:0.5.4
imagePullPolicy: IfNotPresent
# THE FIX: Injects environment variables to pin the model in RAM permanently
env:
- name: OLLAMA_KEEP_ALIVE
value: "-1"
# THE SPEED FIX: Forces the calculations to fit perfectly onto your hardware threads
- name: OLLAMA_NUM_THREADS
value: "4"
ports:
- containerPort: 11434
name: ollama-http
resources:
# Matching limits and requests perfectly eliminates CPU scheduling wait loops
requests:
memory: "2Gi"
cpu: "4" # Guarantee 4 physical cores
limits:
memory: "4Gi"
cpu: "4" # Perfectly matches the 4 execution threads above
volumeMounts:
- name: local-model-storage
mountPath: /root/.ollama
volumes:
# THE FIX: Bypasses Longhorn replication entirely
- name: local-model-storage
hostPath:
path: /var/lib/ollama-models
type: DirectoryOrCreate
---
apiVersion: v1
kind: Service
metadata:
name: ollama-fallback-service
namespace: open-webui
spec:
selector:
app: ollama-fallback
ports:
- protocol: TCP
port: 11434
targetPort: 11434

View File

@ -0,0 +1,116 @@
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: openwebui-db
namespace: open-webui
spec:
instances: 1
imageName: ghcr.io/cloudnative-pg/postgresql:16
bootstrap:
initdb:
database: openwebui
owner: webui_admin
storage:
size: 10Gi
storageClass: longhorn
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: open-webui
namespace: open-webui
spec:
replicas: 1
revisionHistoryLimit: 5
selector:
matchLabels:
app: open-webui
strategy:
type: Recreate
template:
metadata:
labels:
app: open-webui
spec:
containers:
- name: open-webui
image: ghcr.io/open-webui/open-webui:main
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: http
protocol: TCP
env:
# THE POSTGRES ROUTE: Connects your Python app directly to the CNPG cluster
- name: DATABASE_URL
value: "postgresql://webui_admin:$(password)@openwebui-db-rw:5432/openwebui"
# CORE CAPABILITIES: Kept completely stock to support your fallback and LM Studio
- name: ENABLE_OLLAMA_API
value: "True"
- name: ENABLE_OPENAI_API
value: "True"
- name: WEBUI_SECRET_KEY
value: "5e7fb9706cbd8137baf6299a6e6af6297ae03c6bfe4a6edb"
envFrom:
- secretRef:
name: openwebui-db-app
volumeMounts:
- mountPath: /app/backend/data
name: webui-data
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "2"
# THE FIXED DNS LOGIC: Allows the container to see internal cluster service maps natively
dnsPolicy: ClusterFirst
restartPolicy: Always
volumes:
- name: webui-data
persistentVolumeClaim:
claimName: open-webui-pvc
---
apiVersion: v1
kind: Service
metadata:
name: open-webui-service
namespace: open-webui
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: open-webui
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: openwebui-local-ingress
namespace: open-webui
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-production"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
ingressClassName: nginx
tls:
- secretName: openwebui-tls-secret
hosts:
- ai.needlestack.boo
rules:
- host: ai.needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: open-webui-service
port:
number: 80

430
open-webui/resources.yaml Normal file
View File

@ -0,0 +1,430 @@
apiVersion: v1
items:
- apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"open-webui","namespace":"open-webui"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"open-webui"}},"template":{"metadata":{"labels":{"app":"open-webui"}},"spec":{"containers":[{"env":[{"name":"ENABLE_OLLAMA_API","value":"False"},{"name":"ENABLE_OPENAI_API","value":"True"}],"image":"ghcr.io/open-webui/open-webui:main","name":"open-webui","ports":[{"containerPort":8080,"name":"http"}],"volumeMounts":[{"mountPath":"/app/backend/data","name":"webui-data"}]}],"dnsConfig":{"nameservers":["1.1.1.1","8.8.8.8"]},"dnsPolicy":"None","volumes":[{"name":"webui-data","persistentVolumeClaim":{"claimName":"open-webui-pvc"}}]}}}}
creationTimestamp: "2026-09-17T21:09:55Z"
generation: 1
name: open-webui
namespace: open-webui
resourceVersion: "2817943"
uid: 507cd7bd-b252-4060-bf66-2259a42b1889
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: open-webui
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: open-webui
spec:
containers:
- env:
- name: ENABLE_OLLAMA_API
value: "False"
- name: ENABLE_OPENAI_API
value: "True"
image: ghcr.io/open-webui/open-webui:main
imagePullPolicy: IfNotPresent
name: open-webui
ports:
- containerPort: 8080
name: http
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /app/backend/data
name: webui-data
dnsConfig:
nameservers:
- 1.1.1.1
- 8.8.8.8
dnsPolicy: None
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: webui-data
persistentVolumeClaim:
claimName: open-webui-pvc
status:
availableReplicas: 1
conditions:
- lastTransitionTime: "2026-09-17T21:10:13Z"
lastUpdateTime: "2026-09-17T21:10:13Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: "2026-09-17T21:09:55Z"
lastUpdateTime: "2026-09-17T21:10:13Z"
message: ReplicaSet "open-webui-7d9f677bcf" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
observedGeneration: 1
readyReplicas: 1
replicas: 1
updatedReplicas: 1
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"name":"open-webui-pvc","namespace":"open-webui"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"15Gi"}},"storageClassName":"longhorn"}}
pv.kubernetes.io/bind-completed: "yes"
pv.kubernetes.io/bound-by-controller: "yes"
volume.beta.kubernetes.io/storage-provisioner: driver.longhorn.io
volume.kubernetes.io/storage-provisioner: driver.longhorn.io
creationTimestamp: "2026-09-17T21:09:55Z"
finalizers:
- kubernetes.io/pvc-protection
name: open-webui-pvc
namespace: open-webui
resourceVersion: "2817816"
uid: 8dea60f9-fb9c-48b2-ae21-8a197033605a
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 15Gi
storageClassName: longhorn
volumeMode: Filesystem
volumeName: pvc-8dea60f9-fb9c-48b2-ae21-8a197033605a
status:
accessModes:
- ReadWriteOnce
capacity:
storage: 15Gi
phase: Bound
- apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"open-webui-service","namespace":"open-webui"},"spec":{"ports":[{"port":80,"targetPort":8080}],"selector":{"app":"open-webui"}}}
creationTimestamp: "2026-09-17T21:09:55Z"
name: open-webui-service
namespace: open-webui
resourceVersion: "2817759"
uid: 57ffee48-e58c-4639-9c4f-0ee49236e999
spec:
clusterIP: 10.43.66.33
clusterIPs:
- 10.43.66.33
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: open-webui
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T21:33:05Z"
labels:
kubernetes.io/metadata.name: adguard
name: adguard
name: adguard
resourceVersion: "41653"
uid: 6d812d6a-1921-4169-9805-7d1192073f46
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-12T20:23:24Z"
labels:
kubernetes.io/metadata.name: bookstack
name: bookstack
name: bookstack
resourceVersion: "829004"
uid: e5c59011-b6b6-4f53-a655-a140b7363443
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"bookstack-db"}}
creationTimestamp: "2026-09-12T20:39:27Z"
labels:
kubernetes.io/metadata.name: bookstack-db
name: bookstack-db
resourceVersion: "834254"
uid: 9600ab15-9b1a-451b-af4e-13ff3b672331
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T22:46:31Z"
labels:
kubernetes.io/metadata.name: cert-manager
name: cert-manager
name: cert-manager
resourceVersion: "61514"
uid: 05b40520-6a11-49af-96df-3d3289a9ed8f
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"cloudflare"}}
creationTimestamp: "2026-09-12T15:12:46Z"
labels:
kubernetes.io/metadata.name: cloudflare
name: cloudflare
resourceVersion: "737700"
uid: f294d89c-0348-444a-b2a8-57303311e45e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: default
name: default
resourceVersion: "266"
uid: ae7a3d3e-3d08-43fe-8e2c-8f72ef066b9e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"gitea"}}
creationTimestamp: "2026-09-21T21:51:14Z"
labels:
kubernetes.io/metadata.name: gitea
name: gitea
resourceVersion: "4409092"
uid: 6398ba34-919b-4392-afbf-ef0054176a1b
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"homepage"}}
creationTimestamp: "2026-09-18T22:22:12Z"
labels:
kubernetes.io/metadata.name: homepage
name: homepage
resourceVersion: "3232692"
uid: eaafb62a-9a9a-45f3-a7b4-7fa4d1e2ae6b
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T19:46:49Z"
labels:
kubernetes.io/metadata.name: ingress-nginx
name: ingress-nginx
name: ingress-nginx
resourceVersion: "12923"
uid: 46118181-4db6-4c3c-9fdc-f8cc20f28323
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"intel-device-plugin"}}
creationTimestamp: "2026-09-17T20:41:41Z"
labels:
kubernetes.io/metadata.name: intel-device-plugin
name: intel-device-plugin
resourceVersion: "2809324"
uid: b132d304-80cb-4bdc-88cd-2073a8239312
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: kube-node-lease
name: kube-node-lease
resourceVersion: "267"
uid: 81e945a2-a9f5-4ddc-83a8-2bc214a1559e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: kube-public
name: kube-public
resourceVersion: "268"
uid: 2142a69f-f0bd-45af-8738-563df7f99012
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-07-30T20:57:34Z"
labels:
kubernetes.io/metadata.name: kube-system
name: kube-system
resourceVersion: "269"
uid: 1b18f0bc-7131-46b4-9e4b-bb0af3d7d63e
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T19:35:47Z"
labels:
kubernetes.io/metadata.name: longhorn-system
name: longhorn-system
name: longhorn-system
resourceVersion: "9213"
uid: abd04167-9f4b-468e-a637-1649efff2bc7
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"mumble"}}
creationTimestamp: "2026-09-19T18:14:35Z"
labels:
kubernetes.io/metadata.name: mumble
name: mumble
resourceVersion: "3560003"
uid: cc88370b-9275-43f6-a1f9-2bb663600c48
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"nordvpn"}}
creationTimestamp: "2026-09-11T20:23:38Z"
labels:
kubernetes.io/metadata.name: nordvpn
name: nordvpn
resourceVersion: "417127"
uid: 15f7c8a5-1b18-475f-84dc-90e5963814fa
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"open-webui"}}
creationTimestamp: "2026-09-17T21:09:55Z"
labels:
kubernetes.io/metadata.name: open-webui
name: open-webui
resourceVersion: "2817739"
uid: 74bf3bef-51bc-405e-8f79-ebc9f52281c6
spec:
finalizers:
- kubernetes
status:
phase: Active
- apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2026-09-10T19:56:57Z"
labels:
kubernetes.io/metadata.name: portainer
name: portainer
name: portainer
resourceVersion: "16301"
uid: 17802103-8a9c-4b8f-aa42-03a0db58d2ae
spec:
finalizers:
- kubernetes
status:
phase: Active
kind: List
metadata:
resourceVersion: ""

24
portainer/values.yaml Normal file
View File

@ -0,0 +1,24 @@
# values.yaml
ingress:
enabled: true
ingressClassName: nginx
annotations:
# AUTOMATED TLS FIX: Triggers cert-manager to provision the certificate
cert-manager.io/cluster-issuer: "letsencrypt-production"
# THE 502 FIX: Bridges to Portainer's unencrypted HTTP web port cleanly
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
hosts:
- host: portainer.needlestack.boo
paths:
- path: /
pathType: Prefix
# AUTOMATED TLS FIX: Instructs NGINX where to store the secret
tls:
- secretName: portainer-tls-secret
hosts:
- portainer.needlestack.boo
service:
type: ClusterIP
tls:
# Leave this false inside the values block so the pod doesn't look for custom internal certs
force: false

View File

@ -0,0 +1,74 @@
apiVersion: v1
kind: Namespace
metadata:
name: qr-generator
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: qr-generator-ui
namespace: qr-generator
labels:
app: qr-generator
spec:
replicas: 1
selector:
matchLabels:
app: qr-generator
template:
metadata:
labels:
app: qr-generator
spec:
containers:
- name: generator
image: kavehbc/qrcode-barcode:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8501
resources:
limits:
memory: "256Mi"
cpu: "500m"
requests:
memory: "128Mi"
cpu: "100m"
---
apiVersion: v1
kind: Service
metadata:
name: qr-generator-svc
namespace: qr-generator
spec:
ports:
- port: 80
targetPort: 8501
protocol: TCP
selector:
app: qr-generator
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: qr-generator-ingress
namespace: qr-generator
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-production"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
ingressClassName: nginx
tls:
- secretName: qr-generator-tls-secret
hosts:
- qr.needlestack.boo
rules:
- host: qr.needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: qr-generator-svc
port:
number: 80

84
searxng/searxng.yaml Normal file
View File

@ -0,0 +1,84 @@
apiVersion: v1
kind: Namespace
metadata:
name: searxng
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: searxng
namespace: searxng
spec:
replicas: 1
selector:
matchLabels:
app: searxng
template:
metadata:
labels:
app: searxng
spec:
containers:
- name: searxng
image: searxng/searxng:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: http
env:
# THE ANONYMITY BASE: Points SearXNG to your local LAN domain routing
- name: SEARXNG_BASE_URL
value: "https://needlestack.boo"
# SECURITY CRITICAL: Paste your unique openssl output string right here
- name: SEARXNG_SECRET_KEY
value: "0f73d2a5cb68e8ad5827d7584508c78276ebfcf391a9fb74deada8cc04fcaa71"
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "1"
---
apiVersion: v1
kind: Service
metadata:
name: searxng-service
namespace: searxng
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: searxng
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: searxng-local-ingress
namespace: searxng
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-production"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
ingressClassName: nginx
tls:
- secretName: searxng-tls-secret
hosts:
- search.needlestack.boo
rules:
- host: search.needlestack.boo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: searxng-service
port:
number: 80