Compare commits

...

10 Commits

29 changed files with 456 additions and 18 deletions

View File

@@ -31,12 +31,10 @@ The repository is split into three top-level areas. Within each, there is one di
│ ├── infisical/ # Secrets management │ ├── infisical/ # Secrets management
│ ├── it-tools/ # IT utilities │ ├── it-tools/ # IT utilities
│ ├── jellyfin/ # Media server │ ├── jellyfin/ # Media server
│ ├── jenkins/ # CI/CD automation
│ ├── minecraft/ # Game servers │ ├── minecraft/ # Game servers
│ ├── minio-aistor/ # S3-compatible object storage │ ├── minio-aistor/ # S3-compatible object storage
│ ├── n8n/ # Workflow automation │ ├── n8n/ # Workflow automation
│ ├── netbootxyz/ # Network boot service │ ├── netbootxyz/ # Network boot service
│ ├── ntfy/ # Push notifications
│ ├── ollama/ # Local LLM runner │ ├── ollama/ # Local LLM runner
│ ├── openwebui/ # Web UI for AI models │ ├── openwebui/ # Web UI for AI models
│ ├── outline/ # Knowledge base / wiki │ ├── outline/ # Knowledge base / wiki
@@ -81,13 +79,11 @@ The repository is split into three top-level areas. Within each, there is one di
- **Stable Diffusion**: Image generation service - **Stable Diffusion**: Image generation service
### Self-Hosted Tools ### Self-Hosted Tools
- **AFFiNE**: Collaborative workspace and note-taking platform
- **Harbor**: Container image registry - **Harbor**: Container image registry
- **Pelican**: Game server management panel - **Pelican**: Game server management panel
### Development & CI/CD ### Development & CI/CD
- **Gitea**: Self-hosted Git service with container registry - **Gitea**: Self-hosted Git service with container registry
- **Jenkins**: Automation server for CI/CD pipelines
- **n8n**: Workflow automation platform - **n8n**: Workflow automation platform
- **MinIO AIStor**: S3-compatible object storage - **MinIO AIStor**: S3-compatible object storage
@@ -95,9 +91,9 @@ The repository is split into three top-level areas. Within each, there is one di
- **React-Resume**: Resume builder with MinIO and PostgreSQL - **React-Resume**: Resume builder with MinIO and PostgreSQL
- **Passbolt**: Team password manager - **Passbolt**: Team password manager
- **Wiki.js**: Modern documentation platform - **Wiki.js**: Modern documentation platform
- **Outline**: Team knowledge base and wiki (PostgreSQL, Redis/Valkey, MinIO S3, Authentik SSO)
- **Zipline**: File sharing and screenshot service - **Zipline**: File sharing and screenshot service
- **Gotify**: Push notification server with REST API and WebSocket support - **Gotify**: Push notification server with REST API and WebSocket support
- **Ntfy**: Push notification service
- **BentoPDF**: PDF conversion service - **BentoPDF**: PDF conversion service
- **Excalidraw**: Online whiteboard and diagramming tool - **Excalidraw**: Online whiteboard and diagramming tool
- **SearXNG**: Privacy-respecting metasearch engine - **SearXNG**: Privacy-respecting metasearch engine
@@ -120,6 +116,9 @@ The repository is split into three top-level areas. Within each, there is one di
- **Nginx Ingress Controller**: Replaced by Envoy Gateway; dropped after upstream support ended in March 2025 - **Nginx Ingress Controller**: Replaced by Envoy Gateway; dropped after upstream support ended in March 2025
- **Psono**: Self-hosted password manager; replaced by Passbolt - **Psono**: Self-hosted password manager; replaced by Passbolt
- **Vaultwarden**: Self-hosted Bitwarden server; no longer in use - **Vaultwarden**: Self-hosted Bitwarden server; no longer in use
- **AFFiNE**: Collaborative workspace and note-taking platform; no longer in use
- **Jenkins**: CI/CD automation server; no longer in use
- **Ntfy**: Push notification service; no longer in use
## Infrastructure ## Infrastructure

View File

@@ -7,15 +7,17 @@ spec:
hostAPI: https://infisical.jsme.be hostAPI: https://infisical.jsme.be
resyncInterval: 30 resyncInterval: 30
authentication: authentication:
universalAuth: kubernetesAuth:
identityId: "9f65814e-bf4c-42fc-b382-26be15b11416"
serviceAccountRef:
name: infisical-auth
namespace: infisical
autoCreateServiceAccountToken: true
secretsScope: secretsScope:
projectSlug: "kubernetes" projectSlug: "kubernetes"
envSlug: "prod" envSlug: "prod"
secretsPath: "/netbootxyz" secretsPath: "/netbootxyz"
recursive: true recursive: true
credentialsRef:
secretName: infisical-universal-auth
secretNamespace: infisical
managedSecretReference: managedSecretReference:
secretName: netbootxyz-secrets secretName: netbootxyz-secrets
secretNamespace: netbootxyz secretNamespace: netbootxyz

View File

@@ -0,0 +1,22 @@
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
name: outline-secrets
namespace: infisical
spec:
hostAPI: https://infisical.jsme.be
resyncInterval: 30
authentication:
universalAuth:
secretsScope:
projectSlug: "kubernetes"
envSlug: "prod"
secretsPath: "/outline"
recursive: true
credentialsRef:
secretName: infisical-universal-auth
secretNamespace: infisical
managedSecretReference:
secretName: outline-secrets
secretNamespace: outline
secretType: Opaque

View File

@@ -5,6 +5,7 @@ metadata:
namespace: infisical namespace: infisical
spec: spec:
parentRefs: parentRefs:
# Internal gateway only — Infisical is not exposed publicly.
- group: gateway.networking.k8s.io - group: gateway.networking.k8s.io
kind: Gateway kind: Gateway
name: gateway-internal name: gateway-internal
@@ -39,7 +40,7 @@ spec:
- name: Permissions-Policy - name: Permissions-Policy
value: "camera=(), microphone=(), geolocation=(), payment=()" value: "camera=(), microphone=(), geolocation=(), payment=()"
backendRefs: backendRefs:
- name: infisical - name: infisical-backend
port: 8080 port: 8080
kind: Service kind: Service
group: "" group: ""

View File

@@ -10,4 +10,4 @@ spec:
volumeName: jellyfin-pvc volumeName: jellyfin-pvc
resources: resources:
requests: requests:
storage: 40Gi storage: 80Gi

View File

@@ -0,0 +1,118 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: outline
name: outline
spec:
replicas: 1
selector:
matchLabels:
app: outline
template:
metadata:
labels:
app: outline
spec:
restartPolicy: Always
terminationGracePeriodSeconds: 60
containers:
- name: outline
image: docker.getoutline.com/outlinewiki/outline:1.8.1
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "2Gi"
cpu: "2000m"
ports:
- containerPort: 3000
env:
- name: TZ
value: "Europe/Brussels"
- name: NODE_ENV
value: "production"
- name: URL
value: "https://outline.jsme.be"
- name: PORT
value: "3000"
# TLS is terminated at the gateway and X-Forwarded-Proto is set to
# https on the HTTPRoute, so Outline must not force an https redirect.
- name: FORCE_HTTPS
value: "false"
# --- Database (PostgreSQL) ---
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: outline-secrets
key: database_url
# In-cluster Postgres has no TLS; disable SSL on the connection.
- name: PGSSLMODE
value: "disable"
# --- Cache / queue (Redis-compatible Valkey) ---
- name: REDIS_URL
value: "redis://outline-redis.outline.svc.cluster.local:6379"
# --- Secrets ---
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: outline-secrets
key: secret_key
- name: UTILS_SECRET
valueFrom:
secretKeyRef:
name: outline-secrets
key: utils_secret
# --- File storage (MinIO / S3) ---
- name: FILE_STORAGE
value: "s3"
- name: AWS_REGION
value: "us-east-1"
- name: AWS_S3_UPLOAD_BUCKET_URL
value: "https://s3.jsme.be"
- name: AWS_S3_UPLOAD_BUCKET_NAME
value: "outline"
- name: AWS_S3_FORCE_PATH_STYLE
value: "true"
- name: AWS_S3_ACL
value: "private"
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: outline-secrets
key: s3_access_key
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: outline-secrets
key: s3_secret_key
# --- Authentication (Authentik OIDC) ---
- name: OIDC_DISPLAY_NAME
value: "Authentik"
- name: OIDC_AUTH_URI
value: "https://auth.jsme.be/application/o/authorize/"
- name: OIDC_TOKEN_URI
value: "https://auth.jsme.be/application/o/token/"
- name: OIDC_USERINFO_URI
value: "https://auth.jsme.be/application/o/userinfo/"
- name: OIDC_LOGOUT_URI
value: "https://auth.jsme.be/application/o/outline/end-session/"
- name: OIDC_USERNAME_CLAIM
value: "preferred_username"
- name: OIDC_SCOPES
value: "openid profile email"
- name: OIDC_CLIENT_ID
valueFrom:
secretKeyRef:
name: outline-secrets
key: oidc_client_id
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: outline-secrets
key: oidc_client_secret

View File

@@ -0,0 +1,51 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: outline-route
namespace: outline
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: gateway-internal
namespace: envoy-gateway
sectionName: outline
- group: gateway.networking.k8s.io
kind: Gateway
name: gateway-public
namespace: envoy-gateway
sectionName: outline
hostnames:
- "outline.jsme.be"
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
set:
- name: X-Forwarded-Host
value: "outline.jsme.be"
- name: X-Forwarded-Proto
value: https
- type: ResponseHeaderModifier
responseHeaderModifier:
set:
- name: Strict-Transport-Security
value: "max-age=31536000; includeSubDomains"
- name: X-Content-Type-Options
value: nosniff
- name: X-Frame-Options
value: SAMEORIGIN
- name: Referrer-Policy
value: strict-origin-when-cross-origin
- name: Permissions-Policy
value: "camera=(), microphone=(), geolocation=(), payment=()"
backendRefs:
- name: outline
port: 3000
kind: Service
group: ""
weight: 1

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
namespace: outline
name: outline
spec:
selector:
app: outline
ports:
- protocol: TCP
port: 3000
targetPort: 3000
type: ClusterIP

View File

@@ -0,0 +1,12 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
namespace: outline
name: outline-postgres-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn-static
resources:
requests:
storage: 5Gi

View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: outline-postgres
namespace: outline
spec:
selector:
app: outline-postgres
type: ClusterIP
ports:
- name: outline-postgres-port
protocol: TCP
port: 5432
targetPort: 5432

View File

@@ -0,0 +1,55 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
namespace: outline
name: outline-postgres
spec:
replicas: 1
serviceName: outline-postgres
selector:
matchLabels:
app: outline-postgres
template:
metadata:
labels:
app: outline-postgres
spec:
restartPolicy: Always
terminationGracePeriodSeconds: 60
containers:
- name: outline-postgres
image: postgres:18
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "1Gi"
cpu: "500m"
ports:
- containerPort: 5432
volumeMounts:
- name: outline-postgres-data
mountPath: /var/lib/postgresql/data
env:
- name: PGDATA
value: "/var/lib/postgresql/data/pgdata"
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: outline-secrets
key: db_user
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: outline-secrets
key: db_password
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: outline-secrets
key: db_name
volumes:
- name: outline-postgres-data
persistentVolumeClaim:
claimName: outline-postgres-pvc

View File

@@ -0,0 +1,28 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: outline
name: outline-redis
spec:
replicas: 1
selector:
matchLabels:
app: outline-redis
template:
metadata:
labels:
app: outline-redis
spec:
restartPolicy: Always
containers:
- name: outline-redis
image: valkey/valkey:9
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "256Mi"
cpu: "200m"
ports:
- containerPort: 6379

View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: outline-redis
namespace: outline
spec:
selector:
app: outline-redis
type: ClusterIP
ports:
- name: outline-redis-port
protocol: TCP
port: 6379
targetPort: 6379

View File

@@ -0,0 +1,27 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: envoy-gateway-config
namespace: argocd
spec:
project: default
source:
repoURL: https://gitea.jsme.be/Jeffrey/Kubernetes-Manifests.git
path: infra/envoy-gateway
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: envoy-gateway
ignoreDifferences:
- group: gateway.networking.k8s.io
kind: Gateway
jqPathExpressions:
- '.spec.listeners[].tls.certificateRefs[].group'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- PruneLast=true
- ServerSideApply=true

View File

@@ -0,0 +1,24 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: outline
namespace: argocd
spec:
project: default
source:
repoURL: https://gitea.jsme.be/Jeffrey/Kubernetes-Manifests.git
path: applications/outline
targetRevision: HEAD
directory:
recurse: true
destination:
server: https://kubernetes.default.svc
namespace: outline
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
- PrunePropagationPolicy=foreground

View File

@@ -19,7 +19,6 @@ resources:
- infisical/infisical-certificate.yaml - infisical/infisical-certificate.yaml
- it-tools/it-tools-certificate.yaml - it-tools/it-tools-certificate.yaml
- jellyfin/jellyfin-certificate.yaml - jellyfin/jellyfin-certificate.yaml
- jenkins/jenkins-certificate.yaml
- longhorn/longhorn-certificate.yaml - longhorn/longhorn-certificate.yaml
- monitoring/monitoring-certificate.yaml - monitoring/monitoring-certificate.yaml
- n8n/n8n-certificate.yaml - n8n/n8n-certificate.yaml
@@ -48,6 +47,7 @@ resources:
- affine/affine-certificate.yaml - affine/affine-certificate.yaml
- pelican/pelican-certificate.yaml - pelican/pelican-certificate.yaml
- pelican/pelican-wings-certificate.yaml - pelican/pelican-wings-certificate.yaml
- outline/outline-certificate.yaml
patches: patches:
# Internal gateway patches # Internal gateway patches
@@ -81,12 +81,6 @@ patches:
kind: Gateway kind: Gateway
name: gateway-internal name: gateway-internal
path: infisical/infisical-gateway-patch.yaml path: infisical/infisical-gateway-patch.yaml
- target:
group: gateway.networking.k8s.io
version: v1
kind: Gateway
name: gateway-internal
path: jenkins/jenkins-gateway-patch.yaml
- target: - target:
group: gateway.networking.k8s.io group: gateway.networking.k8s.io
version: v1 version: v1
@@ -273,6 +267,12 @@ patches:
kind: Gateway kind: Gateway
name: gateway-internal name: gateway-internal
path: pelican/pelican-wings-gateway-patch.yaml path: pelican/pelican-wings-gateway-patch.yaml
- target:
group: gateway.networking.k8s.io
version: v1
kind: Gateway
name: gateway-internal
path: outline/outline-gateway-patch.yaml
# Public gateway patches # Public gateway patches
- target: - target:
@@ -347,6 +347,12 @@ patches:
kind: Gateway kind: Gateway
name: gateway-public name: gateway-public
path: gotify/gotify-gateway-public-patch.yaml path: gotify/gotify-gateway-public-patch.yaml
- target:
group: gateway.networking.k8s.io
version: v1
kind: Gateway
name: gateway-public
path: outline/outline-gateway-public-patch.yaml
# Uncomment to expose Grafana publicly — ensure Grafana auth is properly configured first # Uncomment to expose Grafana publicly — ensure Grafana auth is properly configured first
# - target: # - target:
# group: gateway.networking.k8s.io # group: gateway.networking.k8s.io

View File

@@ -0,0 +1,14 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: outline-tls
namespace: envoy-gateway
spec:
secretName: outline-tls
privateKey:
rotationPolicy: Always
issuerRef:
name: azure-dns
kind: ClusterIssuer
dnsNames:
- outline.jsme.be

View File

@@ -0,0 +1,19 @@
- op: add
path: /spec/listeners/-
value:
name: outline
protocol: HTTPS
port: 443
hostname: "outline.jsme.be"
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
kubernetes.io/metadata.name: outline
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: outline-tls
namespace: envoy-gateway

View File

@@ -0,0 +1,19 @@
- op: add
path: /spec/listeners/-
value:
name: outline
protocol: HTTPS
port: 443
hostname: "outline.jsme.be"
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
kubernetes.io/metadata.name: outline
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: outline-tls
namespace: envoy-gateway