Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 26d10f4e71 | |||
| 68c5eac164 | |||
| 30f0f05150 | |||
| a97560eaf3 | |||
| 2dce972be2 | |||
| c2ad1122e5 | |||
| 4c356924e7 | |||
| 51777f904f | |||
| 37550da086 | |||
| 12d59cb6f9 | |||
| 714d4896c6 | |||
| e369875117 | |||
| 31e61a9513 | |||
| 9b21f8056c | |||
| 4623fbd8bd | |||
| 18d1e21690 | |||
| 5f88ecf02b | |||
| 0093e5ac52 | |||
| 1ea669220b | |||
| f068a3e6a0 | |||
| 7a3708f70c | |||
| 01ae2dd5cf | |||
| 82595804bf | |||
| 31b3c5bc31 | |||
| 1cdbfb2d7b | |||
| 6232b77026 | |||
| 22ffd779cc | |||
| d85b3f02f5 | |||
| 17b2dfdc2e | |||
| b641e3bd94 | |||
| e19660fdf4 | |||
|
36922a177c
|
|||
|
f3d04e935c
|
|||
| e5797e60b7 | |||
|
0c5cf29f83
|
|||
|
43c38767a1
|
|||
| a68c01a68f | |||
| bdcdb1cb3d | |||
| fe2b80b51f | |||
| b8d5bc747d | |||
|
6f77b7d845
|
|||
| ea286e117d | |||
| 6a050669e8 | |||
| e9a9271d2f |
+8
-1
@@ -21,7 +21,7 @@ checkmk/checkmk/*
|
||||
downtify/Downtify_downloads
|
||||
headscale/config/*
|
||||
headscale/data/*
|
||||
searxng/core-config/settings.yml
|
||||
searxng/core-config/*
|
||||
|
||||
# Steaming services files
|
||||
streaming/jellyfin/*
|
||||
@@ -47,6 +47,7 @@ traefik/logs/*
|
||||
# SSL Certificates
|
||||
adguardhome/certs/*
|
||||
traefik/certs/*
|
||||
certs/
|
||||
|
||||
# Monitoring
|
||||
monitoring/prometheus.yml
|
||||
@@ -98,3 +99,9 @@ temp/*
|
||||
.env.forust
|
||||
.env.*
|
||||
!*example
|
||||
|
||||
# kubernetes
|
||||
*/k8s/*secret*
|
||||
!*/k8s/*secret*.example
|
||||
traefik/k8s/local-tls.yaml
|
||||
convertx/k8s/config.yaml
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: adguard-service
|
||||
namespace: adguard
|
||||
spec:
|
||||
selector:
|
||||
app: adguard
|
||||
ports:
|
||||
- port: 3000
|
||||
name: webui
|
||||
targetPort: 3000
|
||||
- port: 53
|
||||
name: dns
|
||||
targetPort: 53
|
||||
protocol: UDP
|
||||
- port: 53
|
||||
name: dns-tcp
|
||||
targetPort: 53
|
||||
protocol: TCP
|
||||
- port: 853
|
||||
name: dot
|
||||
targetPort: 853
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: adguard-deployment
|
||||
namespace: adguard
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: adguard
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: adguard
|
||||
spec:
|
||||
containers:
|
||||
- name: adguard
|
||||
image: adguard/adguardhome:latest
|
||||
resources:
|
||||
limits:
|
||||
memory: "1.5Gi"
|
||||
cpu: "300m"
|
||||
requests:
|
||||
memory: "500Mi"
|
||||
cpu: "50m"
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: webui
|
||||
- containerPort: 53
|
||||
name: dns
|
||||
- containerPort: 853
|
||||
name: dot
|
||||
volumeMounts:
|
||||
- name: adguard-data
|
||||
mountPath: /opt/adguardhome/work
|
||||
subPath: work
|
||||
- name: adguard-data
|
||||
mountPath: /opt/adguardhome/conf
|
||||
subPath: conf
|
||||
- name: adguard-certs
|
||||
mountPath: /certs
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: adguard-data
|
||||
persistentVolumeClaim:
|
||||
claimName: adguard-pvc
|
||||
- name: adguard-certs
|
||||
secret:
|
||||
secretName: adguard-certs
|
||||
items:
|
||||
- key: tls.crt
|
||||
path: fullchain.pem
|
||||
- key: tls.key
|
||||
path: privkey.pem
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: adguard-pvc
|
||||
namespace: adguard
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
@@ -0,0 +1,62 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: adguard-prod
|
||||
namespace: adguard
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^(adguard|dns)\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: adguard-service
|
||||
port: 3000
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: adguard-local
|
||||
namespace: adguard
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^(adguard|dns)\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: adguard-service
|
||||
port: 3000
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: adguard-doh
|
||||
namespace: adguard
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^(adguard|dns)\.forust\.xyz$`) && PathPrefix(`/dns-query`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: adguard-service
|
||||
port: 3000
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: adguard-dot
|
||||
namespace: adguard
|
||||
spec:
|
||||
entryPoints:
|
||||
- dot
|
||||
routes:
|
||||
- match: HostSNI(`*`)
|
||||
services:
|
||||
- name: adguard-service
|
||||
port: 853
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: adguard
|
||||
@@ -0,0 +1,10 @@
|
||||
kubectl apply -f k8s/namespace.yaml && \
|
||||
kubectl create secret tls adguard-certs -n adguard \
|
||||
--cert=certs/fullchain.pem \
|
||||
--key=certs/privkey.pem --dry-run=client -o yaml > \
|
||||
k8s/secrets.yaml
|
||||
|
||||
# OR WITH NO FILE CREATION:
|
||||
kubectl create secret tls adguard-certs -n adguard \
|
||||
--cert=certs/fullchain.pem --key=certs/privkey.pem \
|
||||
--save-config
|
||||
@@ -0,0 +1,93 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: authentik-server-service
|
||||
namespace: authentik
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: authentik-server
|
||||
ports:
|
||||
- port: 9000
|
||||
targetPort: 9000
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: authentik-worker-service
|
||||
namespace: authentik
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: authentik-worker
|
||||
ports:
|
||||
- port: 9000
|
||||
targetPort: 9000
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: authentik-server-deployment
|
||||
namespace: authentik
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: authentik-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: authentik-server
|
||||
spec:
|
||||
containers:
|
||||
- name: authentik-server
|
||||
image: ghcr.io/goauthentik/server:2025.10.2
|
||||
args: ["server"]
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: authentik-config
|
||||
- secretRef:
|
||||
name: authentik-secrets
|
||||
ports:
|
||||
- containerPort: 9000
|
||||
resources:
|
||||
requests:
|
||||
memory: "700Mi"
|
||||
cpu: "300m"
|
||||
limits:
|
||||
memory: "1.5Gi"
|
||||
cpu: "1000m"
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: authentik-worker-deployment
|
||||
namespace: authentik
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: authentik-worker
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: authentik-worker
|
||||
spec:
|
||||
containers:
|
||||
- name: authentik-worker
|
||||
image: ghcr.io/goauthentik/server:2025.10.2
|
||||
args: ["worker"]
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: authentik-config
|
||||
- secretRef:
|
||||
name: authentik-secrets
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "300m"
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "700m"
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: authentik-config
|
||||
namespace: authentik
|
||||
data:
|
||||
AUTHENTIK_IMAGE: ghcr.io/goauthentik/server
|
||||
AUTHENTIK_TAG: "2025.10.2"
|
||||
AUTHENTIK_POSTGRESQL__HOST: authentik-postgres-service
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED: "true"
|
||||
@@ -0,0 +1,32 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: authentik-prod
|
||||
namespace: authentik
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^auth\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: authentik-server-service
|
||||
port: 9000
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: authentik-local
|
||||
namespace: authentik
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^auth\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: authentik-server-service
|
||||
port: 9000
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: authentik
|
||||
@@ -0,0 +1,66 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: authentik-postgres-service
|
||||
namespace: authentik
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: authentik-postgres
|
||||
ports:
|
||||
- port: 5432
|
||||
targetPort: 5432
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: authentik-postgres-statefulset
|
||||
namespace: authentik
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: authentik-postgres
|
||||
serviceName: authentik-postgres-service
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: authentik-postgres
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: docker.io/library/postgres:15-alpine
|
||||
env:
|
||||
- name: POSTGRES_DB
|
||||
value: authentik
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: authentik-secrets
|
||||
key: AUTHENTIK_POSTGRESQL__USER
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: authentik-secrets
|
||||
key: AUTHENTIK_POSTGRESQL__PASSWORD
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: postgres
|
||||
volumeMounts:
|
||||
- name: postgres-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "200m"
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "500m"
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: postgres-data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: authentik-secrets
|
||||
namespace: authentik
|
||||
type: Opaque
|
||||
stringData:
|
||||
AUTHENTIK_SECRET_KEY: ""
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ""
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||
AUTHENTIK_BOOTSTRAP_PASSWORD: authentik
|
||||
@@ -0,0 +1 @@
|
||||
secret.yaml
|
||||
@@ -0,0 +1,32 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: cfddns
|
||||
labels:
|
||||
app: cfddns
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: cfddns
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: cfddns
|
||||
spec:
|
||||
hostNetwork: true
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
containers:
|
||||
- name: cloudflare-ddns
|
||||
image: timothyjmiller/cloudflare-ddns:latest
|
||||
imagePullPolicy: Always
|
||||
resources:
|
||||
requests:
|
||||
memory: "20Mi"
|
||||
cpu: "30m"
|
||||
limits:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: cfddns-secrets
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: cfddns-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
CLOUDFLARE_API_TOKEN: your_token
|
||||
DOMAINS: "example.com,www.example.com"
|
||||
IP4_PROVIDER: cloudflare.trace
|
||||
IP6_PROVIDER: none
|
||||
UPDATE_CRON: "@every 5m"
|
||||
UPDATE_ON_START: "true"
|
||||
DELETE_ON_STOP: "false"
|
||||
DELETE_ON_FAILURE: "true"
|
||||
TTL: "1"
|
||||
PROXIED: "true"
|
||||
EMOJI: "true"
|
||||
REJECT_CLOUDFLARE_IPS: "true"
|
||||
@@ -0,0 +1,68 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: checkmk-service
|
||||
namespace: checkmk
|
||||
spec:
|
||||
selector:
|
||||
app: checkmk
|
||||
ports:
|
||||
- port: 5000
|
||||
targetPort: 5000
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: checkmk-deployment
|
||||
namespace: checkmk
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: checkmk
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: checkmk
|
||||
spec:
|
||||
containers:
|
||||
- name: checkmk
|
||||
image: checkmk/check-mk-raw:2.4.0-latest
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: checkmk-secrets
|
||||
- configMapRef:
|
||||
name: checkmk-config
|
||||
ports:
|
||||
- containerPort: 5000
|
||||
volumeMounts:
|
||||
- name: sites
|
||||
mountPath: /omd/sites
|
||||
- name: tmp
|
||||
mountPath: /opt/omd/sites/cmk/tmp
|
||||
resources:
|
||||
requests:
|
||||
memory: "2Gi"
|
||||
cpu: "600m"
|
||||
limits:
|
||||
memory: "5Gi"
|
||||
cpu: "4"
|
||||
volumes:
|
||||
- name: sites
|
||||
persistentVolumeClaim:
|
||||
claimName: checkmk-sites-pvc
|
||||
- name: tmp
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: checkmk-sites-pvc
|
||||
namespace: checkmk
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: checkmk-config
|
||||
namespace: checkmk
|
||||
data:
|
||||
TZ: Europe/Bratislava
|
||||
CMK_SITE_ID: cmk
|
||||
@@ -0,0 +1,32 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: checkmk-prod
|
||||
namespace: checkmk
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^cmk\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: checkmk-service
|
||||
port: 5000
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: checkmk-local
|
||||
namespace: checkmk
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^cmk\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: checkmk-service
|
||||
port: 5000
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: checkmk
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: checkmk-secrets
|
||||
namespace: checkmk
|
||||
type: Opaque
|
||||
stringData:
|
||||
CMK_PASSWORD: "password"
|
||||
@@ -0,0 +1,43 @@
|
||||
services:
|
||||
convertx:
|
||||
container_name: convertx
|
||||
image: ghcr.io/c4illin/convertx:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "9992:3000"
|
||||
# https://github.com/C4illin/ConvertX#environment-variables
|
||||
environment:
|
||||
- JWT_SECRET=$(JWT_SECRET)
|
||||
- ACCOUNT_REGISTRATION=$(ACCOUNT_REGISTRATION:-false)
|
||||
- HTTP_ALLOWED=$(HTTP_ALLOWED:-false)
|
||||
- ALLOW_UNAUTHENTICATED=$(ALLOW_UNAUTHENTICATED:-false)
|
||||
- AUTO_DELETE_EVERY_N_HOURS=$(AUTO_DELETE_EVERY_N_HOURS:-24)
|
||||
- WEBROOT=$(WEBROOT)
|
||||
- HIDE_HISTORY=$(HIDE_HISTORY:-false)
|
||||
- LANGUAGE=$(LANGUAGE:-en)
|
||||
- UNAUTHENTICATED_USER_SHARING=$(UNAUTHENTICATED_USER_SHARING:-false)
|
||||
- MAX_CONVERT_PROCESS=$(MAX_CONVERT_PROCESS:-0)
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.convertx.loadbalancer.server.port=3000"
|
||||
# Prod Router
|
||||
- "traefik.http.routers.convertx.rule=Host(`convert.forust.xyz`)"
|
||||
- "traefik.http.routers.convertx.entrypoints=websecure"
|
||||
- "traefik.http.routers.convertx.tls=true"
|
||||
# Local Router
|
||||
- "traefik.http.routers.convertx-local.rule=Host(`convert.workstation.internal`)"
|
||||
- "traefik.http.routers.convertx-local.entrypoints=websecure"
|
||||
- "traefik.http.routers.convertx-local.tls=true"
|
||||
# Dev Router
|
||||
- "traefik.http.routers.convertx-dev.rule=Host(`convertx.gigaforust.internal`)"
|
||||
- "traefik.http.routers.convertx-dev.entrypoints=websecure"
|
||||
- "traefik.http.routers.convertx-dev.tls=true"
|
||||
networks:
|
||||
- proxy
|
||||
volumes:
|
||||
- data:/app/data
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
volumes:
|
||||
data:
|
||||
@@ -0,0 +1,16 @@
|
||||
# test manifest with docker and k8s config keys mismatch
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: convertx-config
|
||||
namespace: convertx
|
||||
data:
|
||||
ACCOUNT_REGISTRATION: "false"
|
||||
HTTP_ALLOWED: "false"
|
||||
ALLOW_UNAUTHENTICAED: "false"
|
||||
AUTO_DELETE_EVERY_N_HOURS: "24"
|
||||
WEBROOT: "/convert"
|
||||
HIDE_HISTORY: "false"
|
||||
LANGUAGE: "en"
|
||||
UNAUTHED_USER_SHARING: "false"
|
||||
MAX_CONVERT_PROCESS: "0"
|
||||
@@ -0,0 +1,63 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: convertx-service
|
||||
namespace: convertx
|
||||
spec:
|
||||
selector:
|
||||
app: convertx
|
||||
ports:
|
||||
- port: 3000
|
||||
targetPort: 3000
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: convertx-deployment
|
||||
namespace: convertx
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: convertx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: convertx
|
||||
spec:
|
||||
containers:
|
||||
- image: ghcr.io/c4illin/convertx:latest
|
||||
name: convertx
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: convertx-config
|
||||
- secretRef:
|
||||
name: convertx-secrets
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
volumeMounts:
|
||||
- mountPath: /data
|
||||
name: data
|
||||
resources:
|
||||
requests:
|
||||
memory: "250Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
cpu: "1500m"
|
||||
memory: "1.5Gi"
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: convertx-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: convertx-pvc
|
||||
namespace: convertx
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
@@ -0,0 +1,32 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: convertx-prod
|
||||
namespace: convertx
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^forust\.xyz$`) && PathPrefix(`/convert`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: convertx-service
|
||||
port: 3000
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: convertx-local
|
||||
namespace: convertx
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^(workstation|gigaforust)\.internal$`) && PathPrefix(`/convert`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: convertx-service
|
||||
port: 3000
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: convertx
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: convertx-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
jwt-secret: ""
|
||||
@@ -22,7 +22,7 @@ services:
|
||||
# Prod Router
|
||||
- "traefik.http.routers.dockmon.rule=Host(`dockmon.forust.xyz`)"
|
||||
- "traefik.http.routers.dockmon.entrypoints=websecure"
|
||||
- "traefik.http.routers.dockmon.middlewares=security-chain@file"
|
||||
- "traefik.http.routers.dockmon.middlewares=security-headers@file"
|
||||
- "traefik.http.routers.dockmon.tls=true"
|
||||
# Local Router
|
||||
- "traefik.http.routers.dockmon-local.rule=Host(`dockmon.workstation.internal`)"
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: dockmon-service
|
||||
namespace: dockmon
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: dockmon
|
||||
ports:
|
||||
- port: 443
|
||||
targetPort: 443
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: dockmon-statefulset
|
||||
namespace: dockmon
|
||||
spec:
|
||||
serviceName: dockmon-service
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: dockmon
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: dockmon
|
||||
spec:
|
||||
containers:
|
||||
- name: dockmon
|
||||
image: darthnorse/dockmon:latest
|
||||
ports:
|
||||
- containerPort: 443
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /app/data
|
||||
- name: docker-sock
|
||||
mountPath: /var/run/docker.sock
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 443
|
||||
scheme: HTTPS
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 3
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "200m"
|
||||
limits:
|
||||
memory: "1.5Gi"
|
||||
cpu: "700m "
|
||||
volumes:
|
||||
- name: docker-sock
|
||||
hostPath:
|
||||
path: /var/run/docker.sock
|
||||
type: Socket
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
@@ -0,0 +1,44 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: ServersTransport
|
||||
metadata:
|
||||
name: dockmon-transport
|
||||
namespace: dockmon
|
||||
spec:
|
||||
insecureSkipVerify: true
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: dockmon-prod
|
||||
namespace: dockmon
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^dockmon\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: security-headers@file
|
||||
services:
|
||||
- name: dockmon-service
|
||||
port: 443
|
||||
serversTransport: dockmon-transport
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: dockmon-local
|
||||
namespace: dockmon
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^dockmon\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: dockmon-service
|
||||
port: 443
|
||||
serversTransport: dockmon-transport
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: dockmon
|
||||
@@ -0,0 +1,58 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: downtify-service
|
||||
namespace: downtify
|
||||
spec:
|
||||
selector:
|
||||
app: downtify
|
||||
ports:
|
||||
- port: 8000
|
||||
targetPort: 8000
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: downtify-deployment
|
||||
namespace: downtify
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: downtify
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: downtify
|
||||
spec:
|
||||
containers:
|
||||
- name: downtify
|
||||
image: ghcr.io/henriquesebastiao/downtify:latest
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
volumeMounts:
|
||||
- name: downloads
|
||||
mountPath: /downloads
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "200m"
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "1"
|
||||
volumes:
|
||||
- name: downloads
|
||||
persistentVolumeClaim:
|
||||
claimName: downtify-downloads-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: downtify-downloads-pvc
|
||||
namespace: downtify
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
@@ -0,0 +1,34 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: downtify-prod
|
||||
namespace: downtify
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^downtify\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: security-chain@file
|
||||
services:
|
||||
- name: downtify-service
|
||||
port: 8000
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: downtify-local
|
||||
namespace: downtify
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^downtify\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: downtify-service
|
||||
port: 8000
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: downtify
|
||||
@@ -3,12 +3,13 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: gcr.forust.xyz/forust/dtek-notif:latest
|
||||
pull_policy: build
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- TZ=Europe/Kyiv
|
||||
|
||||
dns:
|
||||
- 1.1.1.1
|
||||
- 8.8.8.8
|
||||
networks:
|
||||
- default
|
||||
- default
|
||||
|
||||
@@ -17,6 +17,8 @@ services:
|
||||
|
||||
session-keeper:
|
||||
build: ./phpsessid-bot
|
||||
image: gcr.forust.xyz/forust/session-keeper:latest
|
||||
pull_policy: build
|
||||
env_file: .env
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
@@ -31,6 +33,8 @@ services:
|
||||
|
||||
webinar-checker:
|
||||
build: ./webinar-checker
|
||||
image: gcr.forust.xyz/forust/webinar-checker:latest
|
||||
pull_policy: build
|
||||
env_file: .env
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import os
|
||||
import re
|
||||
import logging
|
||||
import redis
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, ChatMember
|
||||
from telegram.constants import ChatType
|
||||
@@ -30,6 +33,7 @@ def _env(key, default=None):
|
||||
EDU_BASE = _env('EDU_URL_BASE', 'https://edu.edu.vn.ua')
|
||||
EDU_WEBINAR_PATH = _env('EDU_URL_WEBINAR', '/webinar/useractive')
|
||||
WEBINAR_URL = f"{EDU_BASE.rstrip('/')}/{EDU_WEBINAR_PATH.lstrip('/')}"
|
||||
DIARY_URL = f"{EDU_BASE.rstrip('/')}/user/diary"
|
||||
|
||||
WEBINAR_CHECK_INTERVAL = int(_env('WEBINAR_CHECK_INTERVAL', 60))
|
||||
REDIS_HOST = _env('REDIS_HOST', 'redis')
|
||||
@@ -252,6 +256,205 @@ def get_admin_keyboard(user_id: int):
|
||||
]
|
||||
return InlineKeyboardMarkup(keyboard)
|
||||
|
||||
# --- Diary Functions ---
|
||||
|
||||
DIARY_MONTH_NAMES = ['', 'Січня', 'Лютого', 'Березня', 'Квітня', 'Травня', 'Червня',
|
||||
'Липня', 'Серпня', 'Вересня', 'Жовтня', 'Листопада', 'Грудня']
|
||||
|
||||
DIARY_WEEKDAYS_SHORT = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Нд']
|
||||
|
||||
def get_diary_keyboard():
|
||||
today = datetime.now()
|
||||
keyboard = [
|
||||
[
|
||||
InlineKeyboardButton(f"📌 Сьогодні ({today.day}.{today.month:02d})", callback_data="diary_today"),
|
||||
InlineKeyboardButton("📌 Завтра", callback_data="diary_tomorrow"),
|
||||
],
|
||||
[
|
||||
InlineKeyboardButton("📅 Цей тиждень", callback_data="diary_week"),
|
||||
InlineKeyboardButton("📅 Весь місяць", callback_data="diary_month"),
|
||||
],
|
||||
]
|
||||
return InlineKeyboardMarkup(keyboard)
|
||||
|
||||
def _parse_calendar_html(table_html: str) -> tuple:
|
||||
"""Parse calendar HTML table into (month_text, {day_num: {weekday, events}})."""
|
||||
days = {}
|
||||
weekdays = []
|
||||
rows = re.findall(r'<tr[^>]*>(.*?)</tr>', table_html, re.DOTALL)
|
||||
|
||||
month_text = ''
|
||||
for r_idx, row in enumerate(rows):
|
||||
cells = re.findall(r'<t[dh][^>]*>(.*?)</t[dh]>', row, re.DOTALL)
|
||||
|
||||
if r_idx == 0:
|
||||
# Month navigation row: extract "Травень 2026" from nav text
|
||||
raw = re.sub(r'<[^>]+>', ' ', row).strip()
|
||||
raw = re.sub(r'\s+', ' ', raw)
|
||||
m = re.search(r'([А-Яа-яіїєґ\']+\s*:?\s*\d{4})', raw)
|
||||
if m:
|
||||
month_text = m.group(1).replace(' : ', ' ').strip()
|
||||
else:
|
||||
month_text = raw
|
||||
elif r_idx == 1:
|
||||
# Day names row
|
||||
for cell in cells:
|
||||
name = re.sub(r'<[^>]+>', '', cell).strip()
|
||||
if name:
|
||||
weekdays.append(name)
|
||||
else:
|
||||
# Data rows: each cell = a day
|
||||
for col_idx, cell in enumerate(cells):
|
||||
# Extract day number — first number in the cell text
|
||||
text = re.sub(r'<[^>]+>', ' ', cell).strip()
|
||||
text = re.sub(r'\s+', ' ', text)
|
||||
dm = re.match(r'(\d+)', text)
|
||||
if not dm:
|
||||
continue
|
||||
day_num = dm.group(1)
|
||||
|
||||
# Extract events: title attribute (full name) of ALL <a> tags inside the cell
|
||||
events = []
|
||||
for a_match in re.finditer(r'<a[^>]*>(.*?)</a>', cell, re.DOTALL):
|
||||
a_tag = a_match.group(0)
|
||||
# Prefer the title attribute (contains full name, not truncated)
|
||||
title_m = re.search(r'title\s*=\s*"([^"]*)"', a_tag)
|
||||
if title_m:
|
||||
et = title_m.group(1).strip()
|
||||
else:
|
||||
et = re.sub(r'<[^>]+>', '', a_match.group(1)).strip()
|
||||
if et:
|
||||
events.append(et)
|
||||
|
||||
weekday = weekdays[col_idx] if col_idx < len(weekdays) else ''
|
||||
days[day_num] = {'weekday': weekday, 'events': events}
|
||||
|
||||
return month_text, days
|
||||
|
||||
|
||||
async def fetch_diary_data(phpsessid: str) -> dict | None:
|
||||
logger.info("Fetching diary data via Playwright...")
|
||||
try:
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.connect(PLAYWRIGHT_WS)
|
||||
try:
|
||||
context_browser = await browser.new_context(user_agent=USER_AGENT)
|
||||
await context_browser.add_cookies([{
|
||||
'name': 'PHPSESSID',
|
||||
'value': phpsessid,
|
||||
'domain': 'edu.edu.vn.ua',
|
||||
'path': '/'
|
||||
}])
|
||||
page = await context_browser.new_page()
|
||||
|
||||
try:
|
||||
await page.goto(DIARY_URL, wait_until='domcontentloaded')
|
||||
await page.wait_for_selector('table.calendar', timeout=10000)
|
||||
await page.wait_for_timeout(1500)
|
||||
|
||||
table_html = await page.evaluate("""
|
||||
() => {
|
||||
const t = document.querySelector('table.calendar');
|
||||
return t ? t.outerHTML : null;
|
||||
}
|
||||
""")
|
||||
if not table_html:
|
||||
logger.error("table.calendar not found in DOM")
|
||||
return None
|
||||
|
||||
# Debug: save HTML for troubleshooting
|
||||
try:
|
||||
with open('/tmp/diary_debug.html', 'w', encoding='utf-8') as f:
|
||||
f.write(table_html)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
month_text, days = _parse_calendar_html(table_html)
|
||||
logger.info(f"Diary parsed: month={month_text!r}, days_with_events={sum(1 for d in days.values() if d['events'])}/{len(days)}")
|
||||
|
||||
return {'monthFullText': month_text, 'days': days}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error parsing diary: {e}")
|
||||
return None
|
||||
finally:
|
||||
await page.close()
|
||||
await context_browser.close()
|
||||
finally:
|
||||
await browser.close()
|
||||
except Exception as e:
|
||||
logger.error(f"Playwright error in diary fetch: {e}")
|
||||
return None
|
||||
|
||||
def _parse_diary_month(text: str) -> str:
|
||||
match = re.search(r'([А-Яа-яіїєґ\']+\s*:\s*\d{4})', text)
|
||||
if match:
|
||||
return match.group(1).replace(' : ', ' ').strip()
|
||||
return text.strip()
|
||||
|
||||
def format_diary_day(data: dict, day_num: int) -> str:
|
||||
days = data.get('days', {})
|
||||
month_str = _parse_diary_month(data.get('monthFullText', ''))
|
||||
day_data = days.get(str(day_num))
|
||||
lines = [f"📅 <b>{day_num} {month_str}</b>", "─" * 18]
|
||||
if not day_data or not day_data.get('events'):
|
||||
lines.append("Немає подій")
|
||||
else:
|
||||
for e in day_data['events']:
|
||||
lines.append(f"📌 {e}")
|
||||
lines.append(f"\n🔗 {DIARY_URL}")
|
||||
return "\n".join(lines)
|
||||
|
||||
def format_diary_week(data: dict, today: datetime) -> str:
|
||||
days = data.get('days', {})
|
||||
month_str = _parse_diary_month(data.get('monthFullText', ''))
|
||||
monday = today - timedelta(days=today.weekday())
|
||||
sunday = monday + timedelta(days=6)
|
||||
lines = [f"📅 <b>Тиждень {monday.day}.{monday.month} – {sunday.day}.{sunday.month}</b>\n"]
|
||||
for i in range(7):
|
||||
d = monday + timedelta(days=i)
|
||||
day_data = days.get(str(d.day))
|
||||
lines.append(f"─ <b>{DIARY_WEEKDAYS_SHORT[i]} {d.day}.{d.month}</b> ─")
|
||||
if not day_data or not day_data.get('events'):
|
||||
lines.append("Немає подій\n")
|
||||
else:
|
||||
for e in day_data['events']:
|
||||
lines.append(f"📌 {e}")
|
||||
lines.append("")
|
||||
lines.append(f"🔗 {DIARY_URL}")
|
||||
return "\n".join(lines)
|
||||
|
||||
def format_diary_month(data: dict) -> str:
|
||||
days = data.get('days', {})
|
||||
month_str = _parse_diary_month(data.get('monthFullText', ''))
|
||||
lines = [f"📅 <b>{month_str}</b>\n"]
|
||||
for day_num in sorted(days.keys(), key=int):
|
||||
day_data = days[day_num]
|
||||
events = day_data.get('events', [])
|
||||
weekday = day_data.get('weekday', '')
|
||||
lines.append(f"─ <b>{weekday} {day_num}</b> ─")
|
||||
if not events:
|
||||
lines.append("Немає подій\n")
|
||||
else:
|
||||
for e in events:
|
||||
lines.append(f"📌 {e}")
|
||||
lines.append("")
|
||||
lines.append(f"🔗 {DIARY_URL}")
|
||||
return "\n".join(lines)
|
||||
|
||||
async def _get_diary_data(context: ContextTypes.DEFAULT_TYPE) -> dict | None:
|
||||
cached = context.user_data.get('diary_cache')
|
||||
now_ts = time.time()
|
||||
if cached and (now_ts - cached.get('timestamp', 0)) < 300:
|
||||
return cached['data']
|
||||
phpsessid = redis_client.get(KEY_PHPSESSID)
|
||||
if not phpsessid:
|
||||
return None
|
||||
data = await fetch_diary_data(phpsessid)
|
||||
if data:
|
||||
context.user_data['diary_cache'] = {'data': data, 'timestamp': now_ts}
|
||||
return data
|
||||
|
||||
# --- Command Handlers ---
|
||||
|
||||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
@@ -376,6 +579,74 @@ async def clear_history(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
logger.error(f"Failed to clear history: {e}")
|
||||
await update.message.reply_text(t(admin_id, 'history_clear_failed'))
|
||||
|
||||
async def diary_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
user = update.effective_user
|
||||
chat = update.effective_chat
|
||||
if not is_whitelisted(user.id):
|
||||
await update.message.reply_text(t(user.id, 'access_denied'))
|
||||
return
|
||||
await update.message.reply_text(
|
||||
"📅 <b>Щоденник</b> — виберіть період:",
|
||||
parse_mode='HTML',
|
||||
reply_markup=get_diary_keyboard()
|
||||
)
|
||||
|
||||
async def diary_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
query = update.callback_query
|
||||
user_id = query.from_user.id
|
||||
await query.answer()
|
||||
|
||||
if user_id != ADMIN_ID:
|
||||
if not is_whitelisted(user_id):
|
||||
await query.edit_message_text("⛔ Доступ заборонено.")
|
||||
return
|
||||
|
||||
data = query.data
|
||||
if data == "diary_refresh":
|
||||
context.user_data.pop('diary_cache', None)
|
||||
await query.edit_message_text("🔄 Завантажую щоденник...")
|
||||
diary_data = await _get_diary_data(context)
|
||||
if not diary_data:
|
||||
await query.edit_message_text("❌ Не вдалося завантажити щоденник. Немає сесії або помилка.")
|
||||
return
|
||||
await query.edit_message_text(
|
||||
"📅 <b>Щоденник</b> — виберіть період:",
|
||||
parse_mode='HTML',
|
||||
reply_markup=get_diary_keyboard()
|
||||
)
|
||||
return
|
||||
|
||||
await query.edit_message_text("🔄 Завантажую щоденник...")
|
||||
diary_data = await _get_diary_data(context)
|
||||
if not diary_data:
|
||||
await query.edit_message_text("❌ Не вдалося завантажити щоденник.")
|
||||
return
|
||||
|
||||
today = datetime.now()
|
||||
if data == "diary_today":
|
||||
text = format_diary_day(diary_data, today.day)
|
||||
elif data == "diary_tomorrow":
|
||||
tomorrow = today + timedelta(days=1)
|
||||
if tomorrow.day < today.day:
|
||||
text = "❌ Дані за наступний місяць недоступні. Перейдіть на сайт."
|
||||
else:
|
||||
text = format_diary_day(diary_data, tomorrow.day)
|
||||
elif data == "diary_week":
|
||||
text = format_diary_week(diary_data, today)
|
||||
elif data == "diary_month":
|
||||
text = format_diary_month(diary_data)
|
||||
else:
|
||||
return
|
||||
|
||||
if len(text) > 4096:
|
||||
text = text[:4090] + "\n\n✂️ ...(обрізано)"
|
||||
|
||||
await query.edit_message_text(
|
||||
text,
|
||||
parse_mode='HTML',
|
||||
reply_markup=get_diary_keyboard()
|
||||
)
|
||||
|
||||
# --- Admin Callbacks ---
|
||||
|
||||
async def admin_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
@@ -649,8 +920,10 @@ def main():
|
||||
app.add_handler(CommandHandler("adduser", add_user))
|
||||
app.add_handler(CommandHandler("removeuser", remove_user))
|
||||
app.add_handler(CommandHandler("clearhistory", clear_history))
|
||||
app.add_handler(CommandHandler("diary", diary_command))
|
||||
|
||||
# Callback handlers - language selection first, then admin panel
|
||||
# Callback handlers - diary first, then language selection, then admin panel
|
||||
app.add_handler(CallbackQueryHandler(diary_callback, pattern="^diary_"))
|
||||
app.add_handler(CallbackQueryHandler(language_callback, pattern="^lang_"))
|
||||
app.add_handler(CallbackQueryHandler(admin_callback))
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
services:
|
||||
errorpage:
|
||||
build: .
|
||||
image: gcr.forust.xyz/forust/error-pages:latest
|
||||
pull_policy: build
|
||||
container_name: error-pages
|
||||
restart: unless-stopped
|
||||
# ports:
|
||||
@@ -11,7 +13,7 @@ services:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.error-pages.loadbalancer.server.port=80"
|
||||
# Error handler middleware
|
||||
- "traefik.http.middlewares.error-pages.errors.status=400-599"
|
||||
- "traefik.http.middlewares.error-pages.errors.status=400,402-599"
|
||||
- "traefik.http.middlewares.error-pages.errors.service=error-pages"
|
||||
- "traefik.http.middlewares.error-pages.errors.query=/{status}.html"
|
||||
networks:
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: error-pages-service
|
||||
namespace: error-pages
|
||||
spec:
|
||||
selector:
|
||||
app: error-pages
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: error-pages-deployment
|
||||
namespace: error-pages
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: error-pages
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: error-pages
|
||||
spec:
|
||||
containers:
|
||||
- name: error-pages
|
||||
image: gcr.forust.xyz/forust/error-pages:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: error-pages
|
||||
@@ -49,6 +49,11 @@ services:
|
||||
- "traefik.tcp.services.gitea.loadbalancer.server.port=22"
|
||||
- "traefik.tcp.routers.gitea.entrypoints=ssh"
|
||||
- "traefik.tcp.routers.gitea.rule=HostSNI(`*`)"
|
||||
# Gitea container registry Router
|
||||
- "traefik.http.routers.gitea-registry.rule=Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)"
|
||||
- "traefik.http.routers.gitea-registry.entrypoints=websecure"
|
||||
- "traefik.http.routers.gitea-registry.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.gitea-registry.tls=true"
|
||||
ports:
|
||||
- "2221:22"
|
||||
networks:
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: gitea-config
|
||||
namespace: gitea
|
||||
data:
|
||||
GITEA__server__DOMAIN: "gitea.forust.xyz"
|
||||
GITEA__server__ROOT_URL: "https://gitea.forust.xyz"
|
||||
GITEA__server__SSH_DOMAIN: "gitssh.forust.xyz"
|
||||
GITEA__server__SSH_PORT: "2221"
|
||||
|
||||
GITEA__database__DB_TYPE: "postgres"
|
||||
GITEA__database__HOST: "gitea-postgres-service:5432"
|
||||
GITEA__database__NAME: "gitea"
|
||||
GITEA__security__REVERSE_PROXY_LIMIT: "1"
|
||||
GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES: "*"
|
||||
|
||||
GITEA__mailer__ENABLED: "false"
|
||||
USER_UID: "1000"
|
||||
USER_GID: "1000"
|
||||
@@ -0,0 +1,71 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea-service
|
||||
namespace: gitea
|
||||
spec:
|
||||
selector:
|
||||
app: gitea
|
||||
ports:
|
||||
- port: 3000
|
||||
name: http
|
||||
targetPort: 3000
|
||||
- port: 2221
|
||||
name: ssh
|
||||
targetPort: 22
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: gitea-deployment
|
||||
namespace: gitea
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: gitea
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: gitea
|
||||
spec:
|
||||
containers:
|
||||
- name: gitea
|
||||
image: docker.gitea.com/gitea:1.26
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: gitea-config
|
||||
- secretRef:
|
||||
name: gitea-secrets
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: http
|
||||
- containerPort: 2221
|
||||
name: ssh
|
||||
volumeMounts:
|
||||
- name: gitea-data
|
||||
mountPath: /data
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "300m"
|
||||
limits:
|
||||
memory: "1.5Gi"
|
||||
cpu: "1300m"
|
||||
volumes:
|
||||
- name: gitea-data
|
||||
persistentVolumeClaim:
|
||||
claimName: gitea-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: gitea-pvc
|
||||
namespace: gitea
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
---
|
||||
@@ -0,0 +1,63 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: gitea-prod
|
||||
namespace: gitea
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^gitea\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: gitea-service
|
||||
port: 3000
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: gitea-local
|
||||
namespace: gitea
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^gitea\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: gitea-service
|
||||
port: 3000
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: gitea-registry
|
||||
namespace: gitea
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: gitea-service
|
||||
port: 3000
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: gitea-ssh
|
||||
namespace: gitea
|
||||
spec:
|
||||
entryPoints:
|
||||
- ssh
|
||||
routes:
|
||||
- match: HostSNI(`*`)
|
||||
services:
|
||||
- name: gitea-service
|
||||
port: 2221
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: gitea
|
||||
@@ -0,0 +1,62 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea-postgres-service
|
||||
namespace: gitea
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: gitea-postgres
|
||||
ports:
|
||||
- port: 5432
|
||||
targetPort: 5432
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: gitea-postgres-statefulset
|
||||
namespace: gitea
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: gitea-postgres
|
||||
serviceName: gitea-postgres-service
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: gitea-postgres
|
||||
spec:
|
||||
containers:
|
||||
- name: gitea-postgres
|
||||
image: postgres:14
|
||||
env:
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: GITEA__database__USER
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: GITEA__database__PASSWD
|
||||
- name: POSTGRES_DB
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: GITEA__database__USER
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: postgres
|
||||
volumeMounts:
|
||||
- name: postgres-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: postgres-data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-secrets
|
||||
namespace: gitea
|
||||
type: Opaque
|
||||
stringData:
|
||||
GITEA__database__USER: "gitea"
|
||||
GITEA__database__PASSWD: "gitea"
|
||||
@@ -0,0 +1,209 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: glance-assets
|
||||
namespace: glance
|
||||
data:
|
||||
# Инжектируем твой брутализм напрямую в ассеты
|
||||
user.css: |
|
||||
:root {
|
||||
--bg-color: #050505;
|
||||
--text-color: #e0e0e0;
|
||||
--accent: #ffffff;
|
||||
--dim: #666666;
|
||||
--font-mono: 'Courier New', Courier, monospace;
|
||||
}
|
||||
|
||||
/* Принудительно ставим моноширинный шрифт для всего дашборда */
|
||||
body, id, main, div, span, p, a, h1, h2, h3 {
|
||||
font-family: var(--font-mono) !important;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Ломаем закругления Glance и делаем жесткие рамки */
|
||||
.widget, .card, main div, [class*="widget"], [class*="card"] {
|
||||
border-radius: 0px !important;
|
||||
border: 1px solid var(--dim) !important;
|
||||
box-shadow: none !important;
|
||||
background-color: var(--bg-color) !important;
|
||||
}
|
||||
|
||||
/* Стилизация ссылок под ховер-эффект из твоего style.css */
|
||||
a {
|
||||
color: var(--text-color) !important;
|
||||
text-decoration: none !important;
|
||||
border-bottom: 1px solid var(--dim) !important;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--text-color) !important;
|
||||
color: var(--bg-color) !important;
|
||||
border-color: var(--text-color) !important;
|
||||
}
|
||||
|
||||
/* Кастомизация заголовков внутри модулей */
|
||||
h2, .widget-title, [class*="title"] {
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: glance-config
|
||||
namespace: glance
|
||||
data:
|
||||
glance.yml: |
|
||||
server:
|
||||
assets-path: /app/assets
|
||||
theme:
|
||||
# Перевели #050505 и #e0e0e0 в формат HSL для Glance
|
||||
background-color: 0 0 2 # Истинно черный фон
|
||||
primary-color: 0 0 88 # Светло-серый текст
|
||||
contrast-multiplier: 1.4
|
||||
positive-color: 140 50 50 # Зеленый для UP-сервисов (не вырвиглазный)
|
||||
negative-color: 0 70 50 # Красный для упавших сайтов
|
||||
custom-css-file: /assets/user.css
|
||||
pages:
|
||||
- $include: home.yml
|
||||
- $include: docker.yml
|
||||
- $include: monitor.yml
|
||||
|
||||
home.yml: |
|
||||
- name: Home
|
||||
columns:
|
||||
- size: small
|
||||
widgets:
|
||||
- type: clock
|
||||
hour-format: 24h
|
||||
timezones:
|
||||
- timezone: Europe/Bratislava
|
||||
label: Bratislava
|
||||
- timezone: Europe/Kyiv
|
||||
label: Kyiv
|
||||
- timezone: Europe/Moscow
|
||||
label: St. Petersburg
|
||||
- type: calendar
|
||||
first-day-of-week: monday
|
||||
- type: rss
|
||||
limit: 10
|
||||
collapse-after: 3
|
||||
cache: 12h
|
||||
feeds:
|
||||
- url: https://selfh.st/rss/
|
||||
title: selfh.st
|
||||
- size: full
|
||||
widgets:
|
||||
- type: group
|
||||
widgets:
|
||||
- type: hacker-news
|
||||
- type: lobsters
|
||||
- type: videos
|
||||
channels:
|
||||
- UCXuqSBlHAE6Xw-yeJA0Tunw
|
||||
- UCR-DXc1voovS8nhAvccRZhg
|
||||
- UCsBjURrPoezykLs9EqgamOA
|
||||
- UCBJycsmduvYEL83R_U4JriQ
|
||||
- UCHnyfMqiRRG1u-2MsSQLbXA
|
||||
- type: group
|
||||
widgets:
|
||||
- type: reddit
|
||||
subreddit: technology
|
||||
show-thumbnails: true
|
||||
- type: reddit
|
||||
subreddit: selfhosted
|
||||
show-thumbnails: true
|
||||
- size: small
|
||||
widgets:
|
||||
- type: weather
|
||||
location: London, United Kingdom
|
||||
units: metric
|
||||
hour-format: 12h
|
||||
hide-location: true
|
||||
- type: markets
|
||||
markets:
|
||||
- symbol: SPY
|
||||
name: S&P 500
|
||||
- symbol: BTC-USD
|
||||
name: Bitcoin
|
||||
- symbol: NVDA
|
||||
name: NVIDIA
|
||||
- symbol: AAPL
|
||||
name: Apple
|
||||
- symbol: MSFT
|
||||
name: Microsoft
|
||||
- type: releases
|
||||
cache: 1d
|
||||
repositories:
|
||||
- glanceapp/glance
|
||||
- go-gitea/gitea
|
||||
- nextcloud/all-in-one
|
||||
|
||||
docker.yml: |
|
||||
- name: Docker
|
||||
columns:
|
||||
- size: full
|
||||
widgets:
|
||||
- type: docker-containers
|
||||
hide-by-default: false
|
||||
|
||||
monitor.yml: |
|
||||
- name: Monitoring
|
||||
columns:
|
||||
- size: small
|
||||
widgets:
|
||||
- type: dns-stats
|
||||
service: adguard
|
||||
url: http://adguard-service.adguard.svc.cluster.local:3000
|
||||
username: forust
|
||||
password: ${ADGUARD_PASSWORD}
|
||||
- size: full
|
||||
widgets:
|
||||
- type: monitor
|
||||
title: Services Status
|
||||
cache: 1m
|
||||
sites:
|
||||
- title: forust.xyz
|
||||
url: https://forust.xyz
|
||||
- title: dns.forust.xyz
|
||||
url: https://dns.forust.xyz
|
||||
- title: www.lk-tour.com.ua
|
||||
url: https://www.lk-tour.com.ua
|
||||
- title: lk-tour.com.ua
|
||||
url: https://lk-tour.com.ua
|
||||
# - title: gitssh.forust.xyz
|
||||
# url: https://gitssh.forust.xyz
|
||||
# - title: gcr.forust.xyz
|
||||
# url: https://gcr.forust.xyz/v2/
|
||||
- title: gitea.forust.xyz
|
||||
url: https://gitea.forust.xyz
|
||||
- title: nextcloud.forust.xyz
|
||||
url: https://nextcloud.forust.xyz
|
||||
- title: mc.forust.xyz
|
||||
url: https://mc.forust.xyz/map
|
||||
- title: auth.forust.xyz
|
||||
url: https://auth.forust.xyz
|
||||
- title: metube.forust.xyz
|
||||
url: https://metube.forust.xyz
|
||||
- title: dockmon.forust.xyz
|
||||
url: https://dockmon.forust.xyz
|
||||
- title: portainer.forust.xyz
|
||||
url: https://portainer.forust.xyz
|
||||
- title: termix.forust.xyz
|
||||
url: https://termix.forust.xyz
|
||||
- title: uptime.forust.xyz
|
||||
url: https://uptime.forust.xyz
|
||||
- title: cmk.forust.xyz
|
||||
url: https://cmk.forust.xyz
|
||||
- title: search.forust.xyz
|
||||
url: https://search.forust.xyz
|
||||
- title: status.forust.xyz
|
||||
url: https://status.forust.xyz
|
||||
- title: traefik.forust.xyz
|
||||
url: https://traefik.forust.xyz
|
||||
- title: media.forust.xyz
|
||||
url: https://media.forust.xyz
|
||||
- title: wfs.forust.xyz
|
||||
url: https://wfs.forust.xyz
|
||||
- title: forust.xyz/convert
|
||||
url: https://forust.xyz/convert
|
||||
@@ -0,0 +1,78 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: glance-service
|
||||
namespace: glance
|
||||
spec:
|
||||
selector:
|
||||
app: glance
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: glance-deployment
|
||||
namespace: glance
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: glance
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: glance
|
||||
spec:
|
||||
containers:
|
||||
- name: glance
|
||||
image: glanceapp/glance
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: glance-secrets
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
volumeMounts:
|
||||
- name: glance-config
|
||||
mountPath: /app/config/glance.yml
|
||||
subPath: glance.yml
|
||||
- name: glance-config
|
||||
mountPath: /app/config/home.yml
|
||||
subPath: home.yml
|
||||
- name: glance-config
|
||||
mountPath: /app/config/docker.yml
|
||||
subPath: docker.yml
|
||||
- name: glance-config
|
||||
mountPath: /app/config/monitor.yml
|
||||
subPath: monitor.yml
|
||||
- name: glance-assets
|
||||
mountPath: /app/assets/user.css
|
||||
subPath: user.css
|
||||
- name: docker-socket
|
||||
mountPath: /var/run/docker.sock
|
||||
- name: localtime
|
||||
mountPath: /etc/localtime
|
||||
readOnly: true
|
||||
resources:
|
||||
requests:
|
||||
memory: "10Mi"
|
||||
cpu: "20m"
|
||||
limits:
|
||||
memory: "100Mi"
|
||||
cpu: "50m"
|
||||
volumes:
|
||||
- name: glance-config
|
||||
configMap:
|
||||
name: glance-config
|
||||
- name: glance-assets
|
||||
configMap:
|
||||
name: glance-config
|
||||
- name: docker-socket
|
||||
hostPath:
|
||||
path: /var/run/docker.sock
|
||||
type: Socket
|
||||
- name: localtime
|
||||
hostPath:
|
||||
path: /etc/localtime
|
||||
type: File
|
||||
@@ -0,0 +1,35 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: glance-prod
|
||||
namespace: glance
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^forust\.xyz$`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: glance-strupprefix
|
||||
services:
|
||||
- name: glance-service
|
||||
port: 8080
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: glance-local
|
||||
namespace: glance
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^glance\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: glance-service
|
||||
port: 8080
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: glance
|
||||
@@ -4,6 +4,9 @@ services:
|
||||
restart: unless-stopped
|
||||
container_name: headscale-server
|
||||
command: serve
|
||||
ports:
|
||||
- 18080:8080
|
||||
- 19090:9090
|
||||
networks:
|
||||
- proxy
|
||||
volumes:
|
||||
@@ -54,7 +57,7 @@ services:
|
||||
container_name: headplane
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '3000:3000'
|
||||
- '13000:3000'
|
||||
volumes:
|
||||
- ./config/headplane.yaml:/etc/headplane/config.yaml
|
||||
- ./config/headscale.yaml:/etc/headscale/config.yaml
|
||||
@@ -65,6 +68,8 @@ services:
|
||||
web:
|
||||
image: goodieshq/headscale-admin:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 10080:80
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.headscale-ui.loadbalancer.server.port=80"
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: headscale-server-external
|
||||
namespace: headscale
|
||||
spec:
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 18080
|
||||
name: http
|
||||
- port: 9090
|
||||
targetPort: 19090
|
||||
name: metrics
|
||||
---
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
kind: EndpointSlice
|
||||
metadata:
|
||||
name: headscale-server-external
|
||||
namespace: headscale
|
||||
labels:
|
||||
kubernetes.io/service-name: headscale-server-external
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 18080
|
||||
protocol: TCP
|
||||
name: http
|
||||
- port: 19090
|
||||
protocol: TCP
|
||||
name: metrics
|
||||
endpoints:
|
||||
- addresses:
|
||||
- "192.168.88.100"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: headscale-ui-external
|
||||
namespace: headscale
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 10080
|
||||
name: http
|
||||
---
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
kind: EndpointSlice
|
||||
metadata:
|
||||
name: headscale-ui-external
|
||||
namespace: headscale
|
||||
labels:
|
||||
kubernetes.io/service-name: headscale-ui-external
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 10080
|
||||
protocol: TCP
|
||||
name: http
|
||||
endpoints:
|
||||
- addresses:
|
||||
- "192.168.88.100"
|
||||
@@ -0,0 +1,101 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: headscale-server-prod
|
||||
namespace: headscale
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^hs\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: headscale-server-external
|
||||
port: 8080
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: headscale-server-local
|
||||
namespace: headscale
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: headscale-server-external
|
||||
port: 8080
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: headscale-ui-prod
|
||||
namespace: headscale
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^hs\.forust\.xyz$`) && PathPrefix(`/admin`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: security-chain@file
|
||||
services:
|
||||
- name: headscale-ui-external
|
||||
port: 80
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: headscale-ui-local
|
||||
namespace: headscale
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`) && PathPrefix(`/admin`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: headscale-ui-external
|
||||
port: 80
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: headscale-metrics-prod
|
||||
namespace: headscale
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^hs\.forust\.xyz$`) && PathPrefix(`/metrics`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: headscale-server-external
|
||||
port: 9090
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: headscale-metrics-local
|
||||
namespace: headscale
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`) && PathPrefix(`/metrics`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: headscale-server-external
|
||||
port: 9090
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: headscale
|
||||
@@ -3,6 +3,8 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.forust
|
||||
image: gcr.forust.xyz/forust/forust-homepage:latest
|
||||
pull_policy: build
|
||||
# ports:
|
||||
# - "8085:80"
|
||||
restart: unless-stopped
|
||||
@@ -15,7 +17,7 @@ services:
|
||||
- "traefik.http.services.forust-homepage.loadbalancer.server.port=80"
|
||||
|
||||
# Prod Router
|
||||
- "traefik.http.routers.forust-homepage.rule=Host(`forust.xyz`)"
|
||||
- "traefik.http.routers.forust-homepage.rule=Host(`forust.xyz`) || Host(`www.forust.xyz`)"
|
||||
- "traefik.http.routers.forust-homepage.entrypoints=websecure"
|
||||
- "traefik.http.routers.forust-homepage.tls=true"
|
||||
# Local Router
|
||||
@@ -30,6 +32,8 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.xdfnx
|
||||
image: gcr.forust.xyz/forust/xdfnx-homepage:latest
|
||||
pull_policy: build
|
||||
restart: unless-stopped
|
||||
# ports:
|
||||
# - "8086:80"
|
||||
@@ -40,9 +44,9 @@ services:
|
||||
- "traefik.http.services.xdfnx-homepage.loadbalancer.server.port=80"
|
||||
|
||||
# Prod Router
|
||||
- "traefik.http.routers.xdfnx.rule=Host(`xdfnx.cfd`)"
|
||||
- "traefik.http.routers.xdfnx.rule=Host(`xdfnx.cfd`) || Host(`www.xdfnx.cfd`)"
|
||||
- "traefik.http.routers.xdfnx.entrypoints=websecure"
|
||||
- "traefik.http.routers.xdfnx.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.xdfnx.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.xdfnx.tls=true"
|
||||
# Local Router
|
||||
- "traefik.http.routers.xdfnx-local.rule=Host(`xdfnx.workstation.internal`)"
|
||||
|
||||
@@ -43,6 +43,14 @@
|
||||
<i class="fas fa-envelope"></i>
|
||||
<a href="mailto:contact@forust.xyz">mail/contact@forust.xyz</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-pie-chart"></i>
|
||||
<a href="https://forust.xyz/glance">forust/dashboard</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-refresh"></i>
|
||||
<a href="https://forust.xyz/convert">forust/converter</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa-solid fa-key"></i>
|
||||
<a href=".well-known/pgp-key.asc">security/PGP Key</a>
|
||||
@@ -61,6 +69,12 @@
|
||||
<span>ArchLinux # btw</span>
|
||||
<span class="level">[#######...]</span>
|
||||
</div>
|
||||
<div class="skill-item">
|
||||
<span>Kubernetes</span> <span class="level">[###.......]</span>
|
||||
</div>
|
||||
<div class="skill-item">
|
||||
<span>Docker</span> <span class="level">[####......]</span>
|
||||
</div>
|
||||
<div class="skill-item">
|
||||
<span>Docker Compose</span> <span class="level">[#####.....]</span>
|
||||
</div>
|
||||
@@ -70,9 +84,6 @@
|
||||
<div class="skill-item">
|
||||
<span>Burpsuite</span> <span class="level">[#####.....]</span>
|
||||
</div>
|
||||
<div class="skill-item">
|
||||
<span>Docker</span> <span class="level">[####......]</span>
|
||||
</div>
|
||||
<div class="skill-item">
|
||||
<span>Steganography</span> <span class="level">[####......]</span>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: forust-homepage-service
|
||||
namespace: homepages
|
||||
spec:
|
||||
selector:
|
||||
app: forust-homepage
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: forust-homepage-deployment
|
||||
namespace: homepages
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: forust-homepage
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: forust-homepage
|
||||
spec:
|
||||
containers:
|
||||
- name: forust-homepage
|
||||
image: gcr.forust.xyz/forust/forust-homepage:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
resources:
|
||||
requests:
|
||||
memory: "10Mi"
|
||||
cpu: "20m"
|
||||
limits:
|
||||
memory: "100Mi"
|
||||
cpu: "50m"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: xdfnx-homepage-service
|
||||
namespace: homepages
|
||||
spec:
|
||||
selector:
|
||||
app: xdfnx-homepage
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: xdfnx-homepage-deployment
|
||||
namespace: homepages
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: xdfnx-homepage
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: xdfnx-homepage
|
||||
spec:
|
||||
containers:
|
||||
- name: xdfnx-homepage
|
||||
image: gcr.forust.xyz/forust/xdfnx-homepage:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
resources:
|
||||
requests:
|
||||
memory: "10Mi"
|
||||
cpu: "20m"
|
||||
limits:
|
||||
memory: "100Mi"
|
||||
cpu: "50m"
|
||||
@@ -0,0 +1,64 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: forust-homepage-prod
|
||||
namespace: homepages
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^(forust\.xyz|www\.forust\.xyz)$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: forust-homepage-service
|
||||
port: 80
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: forust-homepage-local
|
||||
namespace: homepages
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^landing\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: forust-homepage-service
|
||||
port: 80
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: xdfnx-homepage-prod
|
||||
namespace: homepages
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^(xdfnx\.cfd|www\.xdfnx\.cfd)$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: xdfnx-homepage-service
|
||||
port: 80
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: xdfnx-homepage-local
|
||||
namespace: homepages
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^xdfnx\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: xdfnx-homepage-service
|
||||
port: 80
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: homepages
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: kener-config
|
||||
namespace: kener
|
||||
data:
|
||||
ORIGIN: "https://status.forust.xyz"
|
||||
REDIS_URL: "redis://kener-redis-service:6379"
|
||||
TZ: "Etc/UTC"
|
||||
@@ -0,0 +1,32 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: kener-prod
|
||||
namespace: kener
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^status\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: kener-service
|
||||
port: 3000
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: kener-local
|
||||
namespace: kener
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^status\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: kener-service
|
||||
port: 3000
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kener-service
|
||||
namespace: kener
|
||||
spec:
|
||||
selector:
|
||||
app: kener
|
||||
ports:
|
||||
- port: 3000
|
||||
targetPort: 3000
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kener-deployment
|
||||
namespace: kener
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kener
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kener
|
||||
spec:
|
||||
containers:
|
||||
- name: kener
|
||||
image: rajnandan1/kener:4.0.23
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: kener-config
|
||||
- secretRef:
|
||||
name: kener-secrets
|
||||
resources:
|
||||
requests:
|
||||
memory: "300Mi"
|
||||
cpu: "350m"
|
||||
limits:
|
||||
memory: "2Gi"
|
||||
cpu: "1"
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
volumeMounts:
|
||||
- name: kener-db
|
||||
mountPath: /app/database
|
||||
- name: kener-uploads
|
||||
mountPath: /app/uploads
|
||||
volumes:
|
||||
- name: kener-db
|
||||
persistentVolumeClaim:
|
||||
claimName: kener-db-pvc
|
||||
- name: kener-uploads
|
||||
persistentVolumeClaim:
|
||||
claimName: kener-uploads-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: kener-db-pvc
|
||||
namespace: kener
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: kener-uploads-pvc
|
||||
namespace: kener
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: kener
|
||||
@@ -0,0 +1,46 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kener-redis-service
|
||||
namespace: kener
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: kener-redis
|
||||
ports:
|
||||
- name: redis
|
||||
port: 6379
|
||||
targetPort: 6379
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: kener-redis
|
||||
namespace: kener
|
||||
spec:
|
||||
serviceName: kener-redis-service
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kener-redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kener-redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
volumeMounts:
|
||||
- name: redis-data
|
||||
mountPath: /data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: redis-data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: kener-secrets
|
||||
namespace: kener
|
||||
type: Opaque
|
||||
stringData:
|
||||
KENER_SECRET_KEY: ""
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: metube-config
|
||||
namespace: metube
|
||||
data:
|
||||
DOWNLOAD_MODE: "limited"
|
||||
MAX_CONCURRENT_DOWNLOADS: "3"
|
||||
DELETE_FILE_ON_TRASHCAN: "true"
|
||||
DEFAULT_OPTION_PLAYLIST_STRICT_MODE: "true"
|
||||
CLEAR_COMPLETED_AFTER: "600" # 10 min
|
||||
@@ -0,0 +1,34 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: metube-prod
|
||||
namespace: metube
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^metube\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: security-headers@file
|
||||
services:
|
||||
- name: metube-service
|
||||
port: 8081
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: metube-local
|
||||
namespace: metube
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^metube\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: metube-service
|
||||
port: 8081
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: metube-service
|
||||
namespace: metube
|
||||
spec:
|
||||
selector:
|
||||
app: metube
|
||||
ports:
|
||||
- port: 8081
|
||||
targetPort: 8081
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: metube-deployment
|
||||
namespace: metube
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: metube
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: metube
|
||||
spec:
|
||||
containers:
|
||||
- name: metube
|
||||
image: ghcr.io/alexta69/metube
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: metube-config
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
volumeMounts:
|
||||
- name: downloads
|
||||
mountPath: /downloads
|
||||
resources:
|
||||
requests:
|
||||
memory: "600Mi"
|
||||
cpu: "400m"
|
||||
limits:
|
||||
memory: "2Gi"
|
||||
cpu: "1700m"
|
||||
volumes:
|
||||
- name: downloads
|
||||
emptyDir:
|
||||
sizeLimit: 20Gi
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: metube
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: n8n-config
|
||||
namespace: n8n
|
||||
data:
|
||||
N8N_PORT: "5678"
|
||||
N8N_RUNNERS_ENABLED: "true"
|
||||
NODE_ENV: production
|
||||
GENERIC_TIMEZONE: Europe/Bratislava
|
||||
TZ: Europe/Bratislava
|
||||
N8N_SECURE_COOKIE: "false"
|
||||
N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE: "true"
|
||||
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: "true"
|
||||
@@ -0,0 +1,32 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: n8n-prod
|
||||
namespace: n8n
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^n8n\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: n8n-service
|
||||
port: 5678
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: n8n-local
|
||||
namespace: n8n
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^n8n\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: n8n-service
|
||||
port: 5678
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: n8n-service
|
||||
namespace: n8n
|
||||
spec:
|
||||
selector:
|
||||
app: n8n
|
||||
ports:
|
||||
- port: 5678
|
||||
targetPort: 5678
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: n8n-deployment
|
||||
namespace: n8n
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: n8n
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: n8n
|
||||
spec:
|
||||
containers:
|
||||
- name: n8n
|
||||
image: docker.n8n.io/n8nio/n8n
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: n8n-config
|
||||
ports:
|
||||
- containerPort: 5678
|
||||
volumeMounts:
|
||||
- name: n8n-node-data
|
||||
mountPath: /home/node/.n8n
|
||||
- name: n8n-files
|
||||
mountPath: /files
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "150m"
|
||||
limits:
|
||||
memory: "5Gi"
|
||||
cpu: "1500m"
|
||||
volumes:
|
||||
- name: n8n-node-data
|
||||
persistentVolumeClaim:
|
||||
claimName: n8n-node-pvc
|
||||
- name: n8n-files
|
||||
persistentVolumeClaim:
|
||||
claimName: n8n-files-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: n8n-node-pvc
|
||||
namespace: n8n
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: n8n-files-pvc
|
||||
namespace: n8n
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: n8n
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: netronome-config
|
||||
namespace: netronome
|
||||
data:
|
||||
NETRONOME__DB_TYPE: "postgres"
|
||||
NETRONOME__DB_HOST: "netronome-postgres-service"
|
||||
NETRONOME__DB_PORT: "5432"
|
||||
NETRONOME__DB_NAME: "netronome"
|
||||
NETRONOME__DB_SSLMODE: "disable"
|
||||
NETRONOME__HOST: "0.0.0.0"
|
||||
NETRONOME__PORT: "7575"
|
||||
NETRONOME__BASE_URL: "/"
|
||||
@@ -0,0 +1,32 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: netronome-prod
|
||||
namespace: netronome
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^nm\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: netronome-service
|
||||
port: 7575
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: netronome-local
|
||||
namespace: netronome
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^nm\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: netronome-service
|
||||
port: 7575
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: netronome
|
||||
@@ -0,0 +1,58 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: netronome-service
|
||||
namespace: netronome
|
||||
spec:
|
||||
selector:
|
||||
app: netronome
|
||||
ports:
|
||||
- port: 7575
|
||||
protocol: TCP
|
||||
targetPort: 7575
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: netronome-deployment
|
||||
namespace: netronome
|
||||
labels:
|
||||
app: netronome
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: netronome
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: netronome
|
||||
spec:
|
||||
containers:
|
||||
- name: netronome
|
||||
image: ghcr.io/autobrr/netronome:latest
|
||||
ports:
|
||||
- name: netronome-port
|
||||
protocol: TCP
|
||||
containerPort: 7575
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: netronome-config
|
||||
env:
|
||||
- name: NETRONOME__DB_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: netronome-secrets
|
||||
key: NETRONOME__DB_USER
|
||||
- name: NETRONOME__DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: netronome-secrets
|
||||
key: NETRONOME__DB_PASSWORD
|
||||
resources:
|
||||
requests:
|
||||
memory: "100Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
@@ -0,0 +1,71 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: netronome-postgres-service
|
||||
namespace: netronome
|
||||
spec:
|
||||
selector:
|
||||
app: netronome-postgres
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
targetPort: 5432
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: netronome-postgres
|
||||
namespace: netronome
|
||||
spec:
|
||||
serviceName: "netronome-postgres-service"
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: netronome-postgres
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: netronome-postgres
|
||||
spec:
|
||||
containers:
|
||||
- name: netronome-postgres
|
||||
image: postgres:17-alpine
|
||||
ports:
|
||||
- name: postgres-port
|
||||
protocol: TCP
|
||||
containerPort: 5432
|
||||
env:
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: netronome-secrets
|
||||
key: NETRONOME__DB_USER
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: netronome-secrets
|
||||
key: NETRONOME__DB_PASSWORD
|
||||
- name: POSTGRES_DB
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: netronome-config
|
||||
key: NETRONOME__DB_NAME
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "1000m"
|
||||
volumeMounts:
|
||||
- name: netronome-pg-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: netronome-pg-data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
@@ -6,15 +6,13 @@ services:
|
||||
container_name: nextcloud-aio-mastercontainer # Do not change
|
||||
volumes:
|
||||
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config # Do not change (backup)
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /dev/dri:/dev/dri
|
||||
ports:
|
||||
- 8888:8080
|
||||
networks:
|
||||
- nextcloud-aio
|
||||
- proxy # Optional: Connects the mastercontainer to the proxy network in order to make the built-in reverse proxy detection work. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
|
||||
# ports:
|
||||
# - 8081:80 # may be removed if under reverse-proxy
|
||||
# - 8443:8443
|
||||
# - 8888:8080 # AIO
|
||||
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nextcloud-apache
|
||||
namespace: nextcloud
|
||||
spec:
|
||||
ports:
|
||||
- port: 11000
|
||||
targetPort: 11000
|
||||
---
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
kind: EndpointSlice
|
||||
metadata:
|
||||
name: nextcloud-apache
|
||||
namespace: nextcloud
|
||||
labels:
|
||||
kubernetes.io/service-name: nextcloud-apache
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 11000
|
||||
protocol: TCP
|
||||
endpoints:
|
||||
- addresses:
|
||||
- "192.168.88.100"
|
||||
conditions:
|
||||
ready: true
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nextcloud-aio
|
||||
namespace: nextcloud
|
||||
spec:
|
||||
ports:
|
||||
- port: 8888
|
||||
targetPort: 8888
|
||||
---
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
kind: EndpointSlice
|
||||
metadata:
|
||||
name: nextcloud-aio
|
||||
namespace: nextcloud
|
||||
labels:
|
||||
kubernetes.io/service-name: nextcloud-aio
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8888
|
||||
protocol: TCP
|
||||
endpoints:
|
||||
- addresses:
|
||||
- "192.168.88.100"
|
||||
conditions:
|
||||
ready: true
|
||||
@@ -0,0 +1,75 @@
|
||||
# Nextcloud
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: nextcloud-prod
|
||||
namespace: nextcloud
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^nextcloud\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: nextcloud-chain@file
|
||||
services:
|
||||
- name: nextcloud-apache
|
||||
port: 11000
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: nextcloud-local
|
||||
namespace: nextcloud
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^nextcloud\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: nextcloud-chain@file
|
||||
services:
|
||||
- name: nextcloud-apache
|
||||
port: 11000
|
||||
|
||||
---
|
||||
# Nextcloud AIO
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: naio-prod
|
||||
namespace: nextcloud
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^naio\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: nextcloud-aio
|
||||
port: 8888
|
||||
scheme: https
|
||||
serversTransport: insecure-transport # <-- Ссылка на ваш CRD ресурс вместо @file
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: naio-local
|
||||
namespace: nextcloud
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^naio\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: nextcloud-aio
|
||||
port: 8888
|
||||
scheme: https
|
||||
serversTransport: insecure-transport
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: nextcloud
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: ServersTransport
|
||||
metadata:
|
||||
name: insecure-transport
|
||||
namespace: nextcloud
|
||||
spec:
|
||||
insecureSkipVerify: true
|
||||
@@ -0,0 +1,32 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: portainer-prod
|
||||
namespace: portainer
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^portainer\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: portainer-service
|
||||
port: 9000
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: portainer-local
|
||||
namespace: portainer
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^portainer\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: portainer-service
|
||||
port: 9000
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: portainer
|
||||
@@ -0,0 +1,64 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: portainer-service
|
||||
namespace: portainer
|
||||
spec:
|
||||
selector:
|
||||
app: portainer
|
||||
ports:
|
||||
- port: 9000
|
||||
targetPort: 9000
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: portainer-deployment
|
||||
namespace: portainer
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: portainer
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: portainer
|
||||
spec:
|
||||
containers:
|
||||
- name: portainer
|
||||
image: portainer/portainer-ce:2.41.0
|
||||
ports:
|
||||
- containerPort: 9000
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
- name: docker-sock
|
||||
mountPath: /var/run/docker.sock
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "200m"
|
||||
limits:
|
||||
memory: "2Gi"
|
||||
cpu: "1"
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: portainer-data-pvc
|
||||
- name: docker-sock
|
||||
hostPath:
|
||||
path: /var/run/docker.sock
|
||||
type: Socket
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: portainer-data-pvc
|
||||
namespace: portainer
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: searxng-config
|
||||
namespace: searxng
|
||||
data:
|
||||
SEARXNG_BASE_URL: "https://s.forust.xyz"
|
||||
SEARXNG_PORT: "8080"
|
||||
SEARXNG_BIND_ADDRESS: "0.0.0.0"
|
||||
SEARXNG_LIMITER: "true"
|
||||
SEARXNG_VALKEY_URL: "valkey://searxng-valkey-service:6379/0"
|
||||
@@ -0,0 +1,32 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: searxng-prod
|
||||
namespace: searxng
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^(s|searxng)\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: searxng-service
|
||||
port: 8080
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: searxng-local
|
||||
namespace: searxng
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^(s|searxng)\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: searxng-service
|
||||
port: 8080
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: searxng
|
||||
@@ -0,0 +1,50 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: searxng-service
|
||||
namespace: searxng
|
||||
spec:
|
||||
selector:
|
||||
app: searxng
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: searxng-deployment
|
||||
namespace: searxng
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: searxng
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: searxng
|
||||
spec:
|
||||
containers:
|
||||
- name: searxng
|
||||
image: docker.io/searxng/searxng:latest
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: searxng-config
|
||||
- secretRef:
|
||||
name: searxng-secrets
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
volumeMounts:
|
||||
- name: cache
|
||||
mountPath: /var/cache/searxng
|
||||
resources:
|
||||
requests:
|
||||
memory: "300Mi"
|
||||
cpu: "30m"
|
||||
limits:
|
||||
memory: "700Mi"
|
||||
cpu: "500m"
|
||||
volumes:
|
||||
- name: cache
|
||||
emptyDir: {}
|
||||
@@ -0,0 +1,51 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: searxng-valkey-service
|
||||
namespace: searxng
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: searxng-valkey
|
||||
ports:
|
||||
- port: 6379
|
||||
targetPort: 6379
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: searxng-valkey-statefulset
|
||||
namespace: searxng
|
||||
spec:
|
||||
serviceName: searxng-valkey-service
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: searxng-valkey
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: searxng-valkey
|
||||
spec:
|
||||
containers:
|
||||
- name: valkey
|
||||
image: docker.io/valkey/valkey:9-alpine
|
||||
command:
|
||||
- valkey-server
|
||||
- --save
|
||||
- "30 1"
|
||||
- --loglevel
|
||||
- warning
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
volumeMounts:
|
||||
- name: valkey-data
|
||||
mountPath: /data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: valkey-data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: termix-config
|
||||
namespace: termix
|
||||
data:
|
||||
PORT: "8080"
|
||||
@@ -0,0 +1,32 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: termix-prod
|
||||
namespace: termix
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^termix\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: termix-service
|
||||
port: 8080
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: termix-local
|
||||
namespace: termix
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^termix\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: termix-service
|
||||
port: 8080
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: termix
|
||||
@@ -0,0 +1,69 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: termix-service
|
||||
namespace: termix
|
||||
spec:
|
||||
selector:
|
||||
app: termix
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: termix-deployment
|
||||
namespace: termix
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: termix
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: termix
|
||||
spec:
|
||||
containers:
|
||||
- name: termix
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: termix-config
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
volumeMounts:
|
||||
- name: termix-data
|
||||
mountPath: /app/data
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "300m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
volumes:
|
||||
- name: termix-data
|
||||
persistentVolumeClaim:
|
||||
claimName: termix-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: termix-pvc
|
||||
namespace: termix
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3.7
|
||||
image: traefik:v3.7.4
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
command:
|
||||
|
||||
@@ -4,12 +4,12 @@ tls:
|
||||
# Cloudflare Origin CA *.forust.xyz
|
||||
# - certFile: /certs/cloudflare.pem
|
||||
# keyFile: /certs/cloudflare.key
|
||||
stores:
|
||||
default:
|
||||
defaultCertificate:
|
||||
# Fallback local certificate
|
||||
certFile: /certs/local.pem
|
||||
keyFile: /certs/local-key.pem
|
||||
# stores:
|
||||
# default:
|
||||
# defaultCertificate:
|
||||
# # Fallback local certificate
|
||||
# certFile: /certs/local.pem
|
||||
# keyFile: /certs/local-key.pem
|
||||
|
||||
options:
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: dashboard-prod
|
||||
namespace: traefik
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^traefik\.forust\.xyz$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: api@internal
|
||||
kind: TraefikService
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: dashboard-local
|
||||
namespace: traefik
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: HostRegexp(`^traefik\.(workstation|gigaforust)\.internal$`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: api@internal
|
||||
kind: TraefikService
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVWRENDQXJ5Z0F3SUJBZ0lSQUpkbVJpaHoxNWNpeXczUU5wTVgxVGd3RFFZSktvWklodmNOQVFFTEJRQXcKZFRFZU1Cd0dBMVVFQ2hNVmJXdGpaWEowSUdSbGRtVnNiM0J0Wlc1MElFTkJNU1V3SXdZRFZRUUxEQnhtYjNKMQpjM1JBWjJsbllXWnZjblZ6ZENBb1RYSkdiM0oxYzNRcE1Td3dLZ1lEVlFRRERDTnRhMk5sY25RZ1ptOXlkWE4wClFHZHBaMkZtYjNKMWMzUWdLRTF5Um05eWRYTjBLVEFlRncweU5URXlNRFV4TWpVME16UmFGdzB5T0RBek1EVXgKTWpVME16UmFNRkF4SnpBbEJnTlZCQW9USG0xclkyVnlkQ0JrWlhabGJHOXdiV1Z1ZENCalpYSjBhV1pwWTJGMApaVEVsTUNNR0ExVUVDd3djWm05eWRYTjBRR2RwWjJGbWIzSjFjM1FnS0UxeVJtOXlkWE4wS1RDQ0FTSXdEUVlKCktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQUx1c2dJNUJuQVJnZzVTS1hpR29PT3dXSkFocXBXSUQKOWg4cGtUMjFTZzhxM3haeU80anZjUEVWbmpOVzRnRFQ0WUhFdjNIZDdZY25IRFdOWG5qSW9LdUd2N2lMOUQyagpLMllNUGtXOGM4RmhJRzFycTJmNTR5YXYxbm1QVmtoYVk2WkJRdzRVT0ZCKzRYRHprbDJTZXcxQnBCV3JIQmZmCitYT2gzUUllcFRiZGdGalhsS0VQdEZuR0YrZFhyZmZmZm5Ucm80ejJ4QVpYeUdSb2pqZTZSbi9tMjJYeHZVRXYKcnhnUE5sM2Y4N0grZXpmZXgrQndMZWNSbVVhQkU0MEFmOHpobSs3T0JvZ1psQU4vZGU2TnZrT1JWdjRydGdIWgpaczFacGYzYmxqTGpwUmh2NGNwYVhPam44bW9UaEEzNUsrRVVUY3hBaUVZSE5pVHZFY2tMZXFjQ0F3RUFBYU9CCmd6Q0JnREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUhBd0V3SHdZRFZSMGoKQkJnd0ZvQVVYU25JWGM5cU55TktibDhEZjZ4T3V3UHZFQW93T0FZRFZSMFJCREV3TDRJVktpNW5hV2RoWm05eQpkWE4wTG1sdWRHVnlibUZzZ2hZcUxuZHZjbXR6ZEdGMGFXOXVMbWx1ZEdWeWJtRnNNQTBHQ1NxR1NJYjNEUUVCCkN3VUFBNElCZ1FETVdmMXUzQm5IRnV4TlpRN29CYnZBQk5Xb0xlOTlSb2N6TFk2c2dzZkdCZFFIWXdvUzMxT2EKZXgwT0ZYVXZQb2N2NWRIdWdtSlpvUlN0NDU1QndZRzVuTUM0VTJhY0NzNm53TjJGK2paa3BNL2xCUEdtek1WWgpvM0lNc1M0VU5IYzZXRGllRWp3Y1J1Q005bldWQnRrTmE4RTdsdWJxZk5SclhZTjB4L0YzWGpud2RWUS8wT0l0CnZvc2ZyRTRzMVJUdEhmY3VQWnhBZW9NSVdFN0pSQjRMOHhabHU5T0RZeituRGwva3BOTDkwVThHdXQwWFFucHgKY1RScVhnNC9nT1RKOUFlUnMwMHIrQU9wV1V3ZExFTmZnQVZ4Z0MrZ3FWVmFMV0NlVkFTWi9UNFJNWmt6K0YxeQpZRU5PR2o2L09hdm5wd25Wd21GcVRya1lHWURqU3RNWW9GZHBrWHB1VjY1dkg3Qnk4cHkyNmpMWFZ3VUpsUjQyClFUMGZnV0RDVFcxZTEwQ0o4N2NZMVNFQ3N2T2kwWVM0ZmtUTHJCM0FsMEhoQVZiWkFicmRSSHErMWQySzhtSTIKcUVpOXVPVnZZckZneHFtcWxIRUR1cFJMM095bWJ6bnRQeFZabXpzMmRiRXNVd0lxUXo0VFRiTzU4ZWs0eVI2dApQdG5hNyttNzJIMD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2QUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktZd2dnU2lBZ0VBQW9JQkFRQzdySUNPUVp3RVlJT1UKaWw0aHFEanNGaVFJYXFWaUEvWWZLWkU5dFVvUEt0OFdjanVJNzNEeEZaNHpWdUlBMCtHQnhMOXgzZTJISnh3MQpqVjU0eUtDcmhyKzRpL1E5b3l0bURENUZ2SFBCWVNCdGE2dG4rZU1tcjlaNWoxWklXbU9tUVVNT0ZEaFFmdUZ3Cjg1SmRrbnNOUWFRVnF4d1gzL2x6b2QwQ0hxVTIzWUJZMTVTaEQ3Ulp4aGZuVjYzMzMzNTA2Nk9NOXNRR1Y4aGsKYUk0M3VrWi81dHRsOGIxQkw2OFlEelpkMy9PeC9uczMzc2ZnY0MzbkVabEdnUk9OQUgvTTRadnV6Z2FJR1pRRApmM1h1amI1RGtWYitLN1lCMldiTldhWDkyNVl5NDZVWWIrSEtXbHpvNS9KcUU0UU4rU3ZoRkUzTVFJaEdCellrCjd4SEpDM3FuQWdNQkFBRUNnZ0VBR1dmNDMwa3lmY1V6Q3VEUWJXNEFoclZZbTJzVWlIaFEwVmNuT2x0WWMwVXkKZmk5b3I5ajZTU2pNQ2RjeE1UdDl3N3VHenp0ajlHL3UrYkR4b1JoSDUvQ044OFcrZ3JtY0hteDU0YWJwWkx4cApUMmJNQlg5bXFNNFZFcys4dG43R0RyTzNDQ2prbHNFV2M5d0ZiSFZ3QXhObnl5Y20zblNMcUlPNUQ1aG1kVTY3CmlRR1c3bEd3WGJicWlTbUZ1NjIyaERNWWE0Z3RYUnB5cXkrZlpjcGNES29iSXpJRjBCcmhQRDN5RytCellhaFYKVVpIZVBlRm9mTjQvOXI4MTVmOWE3MndPSFBJa0Z6NWdNSlBIREdkUDh1aHdrdzlUOEV2NHAvT0lLZlJTYmc2cgp3VVdlMVowNFUzL0VvenkyczRwYURua1VYVXBoRytINzhnTnVta2VIQVFLQmdRREpOM0VSMURjMHplWEo0Um5oCmI3TldzY1RDV09sS2FkVGN2YlFFY3ViRnVjZzE3Vkc4UzNrVjhSYStmam9zVGNpN0hmR1dZSUc2MS90dXNXYTgKTDVJVUNRNnJlSFhpempLM1BsK0oyOW9TM1RhbjZDdDlxOEtaalYwMXZKTXEzYk1FQVg5VUVwL2JTbHdPUWVqeApOZkZrZ2JFMkRmSEJRVTY3SVlsQ2lVMy9FUUtCZ1FEdXhTWGd3UTRYT1h6T1hrMzlVZE56TVB3S2tDUFhMZkgxCjRGbElTUXZHU05QY1FmK0t0WVVvL1hGNXF2RkkxTUNEa1JBT01FMWZCcFQ4OW9wbEVLUXQ3M3RLc1BoUHhzSHgKem5sL2t0MVRZdUZrcDZtdk9wOHpLdHZqRGVoRGoxUmJZTVN3OFZJNkNlSTRqcDZoSmdZQVhhNURwbFkxM3dFegpHMnhCV1dyT053S0JnRDQ3UEdna056TEluMUlSb1h4OG5IMnFtMHowVEtxc0VwNTJ1VzlLemg3Rzk2bmVEUkpzClVUVzlDNmk4eDJjZVkzK2pvaTA5Q2NKc3ZDR2ZFa1FQZm1GZDc4Q09qLzhtZ0w3MXRueWZsMUdRUXpBbytSSjAKQmNxUjB3c2ttR3VBaDdZc2RHSGZKTHVnd3RuUi9xWmpaWllOR202NlgxUEN6QVBLT25adW1zWFJBb0dBY2pURQphRnVQRk5hL2Rxb3UzWkxzOC9VaktSNUd0bDdZbEFYS1RzUDVxTThlM3dTR2FWOW5vUEtRKzJRall2VzRXM1hnCld4a0plUUZaOUNFc2t5akJqdU0wY3NaeER4OS9sdHh1eXZHQmdhZ1RMU1R4Q2NxZGFVai93ZnZkODZxejY3MCsKZDNBR0o1S2dyUEt5dDF2TGxSTTZEa3VhZ3N2MjgrNFMrckw5WGtNQ2dZQjQ0d0IzdUs4N0lsK3F0dGFNdG5SQwp5NkcwNlBsUkZlbGF6THoxc2F0aC9Gam1JUm5rd2tqcUEzRFRwV04wM1RWRStqdDRQY2h5VkQ2cWw0S3JJQzZMCjdKWDc4Qm1Yc1NGTkxZZ3h4NUNCejJUU0wvODA1amdVRnVmZGg5TjlWZm9YWnJKSldSakpqTTg4UU5xTmxNSWMKbVVobkMzU01kajdkdDVMSU9pNE5NUT09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: local-tls
|
||||
type: kubernetes.io/tls
|
||||
@@ -0,0 +1,124 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: traefik
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: traefik-dynamic
|
||||
namespace: traefik
|
||||
data:
|
||||
dynamic.yml: |
|
||||
http:
|
||||
serversTransports:
|
||||
insecureTransport:
|
||||
insecureSkipVerify: true
|
||||
middlewares.yml: |
|
||||
http:
|
||||
middlewares:
|
||||
# HTTPS Redirect
|
||||
redirect-https:
|
||||
redirectScheme:
|
||||
scheme: https
|
||||
permanent: true
|
||||
# Cloudflare IP Whitelist
|
||||
cloudflare-ipwhitelist:
|
||||
ipWhiteList:
|
||||
sourceRange:
|
||||
- "173.245.48.0/20"
|
||||
- "103.21.244.0/22"
|
||||
- "103.22.200.0/22"
|
||||
- "103.31.4.0/22"
|
||||
- "141.101.64.0/18"
|
||||
- "108.162.192.0/18"
|
||||
- "190.93.240.0/20"
|
||||
- "188.114.96.0/20"
|
||||
- "197.234.240.0/22"
|
||||
- "198.41.128.0/17"
|
||||
- "162.158.0.0/15"
|
||||
- "104.16.0.0/13"
|
||||
- "104.24.0.0/14"
|
||||
- "172.64.0.0/13"
|
||||
- "131.0.72.0/22"
|
||||
|
||||
# Authentik + secure headers
|
||||
security-chain:
|
||||
chain:
|
||||
middlewares:
|
||||
- authentik@file
|
||||
- security-headers@file
|
||||
authentik:
|
||||
forwardAuth:
|
||||
address: "http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
|
||||
trustForwardHeader: true
|
||||
maxResponseBodySize: 1048576
|
||||
authResponseHeaders:
|
||||
- X-authentik-username
|
||||
- X-authentik-groups
|
||||
- X-authentik-email
|
||||
- X-authentik-name
|
||||
- X-authentik-uid
|
||||
- X-authentik-jwt
|
||||
- X-authentik-meta-jwks
|
||||
- X-authentik-meta-outpost
|
||||
- X-authentik-meta-provider
|
||||
- X-authentik-meta-app
|
||||
- X-authentik-meta-version
|
||||
|
||||
# Security Headers
|
||||
security-headers:
|
||||
headers:
|
||||
browserXssFilter: true
|
||||
contentTypeNosniff: true
|
||||
forceSTSHeader: true
|
||||
stsIncludeSubdomains: true
|
||||
stsPreload: true
|
||||
stsSeconds: 31536000
|
||||
customFrameOptionsValue: "SAMEORIGIN"
|
||||
customResponseHeaders:
|
||||
X-Content-Type-Options: "nosniff"
|
||||
Referrer-Policy: "strict-origin-when-cross-origin"
|
||||
|
||||
# Nextcloud specific headers
|
||||
nextcloud-secure-headers:
|
||||
headers:
|
||||
hostsProxyHeaders:
|
||||
- "X-Forwarded-Host"
|
||||
- "X-Forwarded-Proto"
|
||||
referrerPolicy: "same-origin"
|
||||
customFrameOptionsValue: "SAMEORIGIN"
|
||||
|
||||
# Rate limiting
|
||||
rate-limit:
|
||||
rateLimit:
|
||||
average: 100
|
||||
burst: 50
|
||||
period: 1m
|
||||
|
||||
# Nextcloud chain
|
||||
nextcloud-chain:
|
||||
chain:
|
||||
middlewares:
|
||||
- nextcloud-secure-headers@file
|
||||
- security-headers@file
|
||||
|
||||
# Error pages
|
||||
error-pages:
|
||||
errors:
|
||||
status:
|
||||
- "400"
|
||||
- "402-599"
|
||||
service: error-pages-service.error-pages@kubernetescrd
|
||||
query: /{status}.html
|
||||
tls.yml: |
|
||||
# TLS Configuration
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
minVersion: VersionTLS12
|
||||
sniStrict: false
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
|
||||
@@ -0,0 +1,124 @@
|
||||
# Auto-generated by forust | See https://github.com/traefik/traefik-helm-chart/blob/master/values.yaml
|
||||
hostNetwork: false
|
||||
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- NET_BIND_SERVICE
|
||||
|
||||
podSecurityContext: ~
|
||||
|
||||
service:
|
||||
enabled: true
|
||||
type: LoadBalancer
|
||||
annotations:
|
||||
metallb.io/loadBalancerIPs: "192.168.80.2"
|
||||
api:
|
||||
dashboard: true
|
||||
insecure: true
|
||||
|
||||
updateStrategy:
|
||||
type: Recreate
|
||||
|
||||
deployment:
|
||||
initContainers:
|
||||
- name: volume-permissions
|
||||
image: busybox:latest
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- "mkdir -p /data/letsencrypt && touch /data/letsencrypt/acme.json && chmod 600 /data/letsencrypt/acme.json"
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
|
||||
providers:
|
||||
kubernetesIngress:
|
||||
enabled: false
|
||||
kubernetesCRD:
|
||||
enabled: true
|
||||
kubernetesGateway:
|
||||
enabled: false
|
||||
file:
|
||||
enabled: false
|
||||
|
||||
# Entrypoints
|
||||
ports:
|
||||
web:
|
||||
port: 80
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: websecure
|
||||
scheme: https
|
||||
permanent: true
|
||||
websecure:
|
||||
port: 443
|
||||
http:
|
||||
tls:
|
||||
enabled: true
|
||||
ssh:
|
||||
port: 2221
|
||||
exposedPort: 2221
|
||||
protocol: TCP
|
||||
expose:
|
||||
default: true
|
||||
minecraft-tcp:
|
||||
port: 25565
|
||||
exposedPort: 25565
|
||||
protocol: TCP
|
||||
expose:
|
||||
default: true
|
||||
minecraft-udp:
|
||||
port: 19132
|
||||
exposedPort: 19132
|
||||
protocol: UDP
|
||||
expose:
|
||||
default: true
|
||||
dot:
|
||||
port: 853
|
||||
exposedPort: 853
|
||||
protocol: TCP
|
||||
expose:
|
||||
default: true
|
||||
|
||||
ingressRoute:
|
||||
dashboard:
|
||||
enabled: false
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 100Mi
|
||||
path: /data
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt-staging:
|
||||
acme:
|
||||
email: bobrovod@national.shitposting.agency
|
||||
storage: /data/letsencrypt/acme.json
|
||||
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
httpChallenge:
|
||||
entryPoint: web
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: bobrovod@national.shitposting.agency
|
||||
storage: /data/letsencrypt/acme.json
|
||||
caServer: https://acme-v02.api.letsencrypt.org/directory
|
||||
httpChallenge:
|
||||
entryPoint: web
|
||||
|
||||
volumes:
|
||||
- name: traefik-dynamic
|
||||
mountPath: /etc/traefik/dynamic
|
||||
type: configMap
|
||||
|
||||
additionalArguments:
|
||||
- "--providers.file.directory=/etc/traefik/dynamic"
|
||||
- "--providers.file.watch=true"
|
||||
|
||||
logs:
|
||||
general:
|
||||
level: INFO
|
||||
format: json
|
||||
access:
|
||||
enabled: true
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user