Compare commits

..
1 Commits
Author SHA1 Message Date
forust 5b3ef39102 template for lampa service 2026-01-21 11:36:36 +01:00
285 changed files with 5314 additions and 10379 deletions

No files matched your search

-24
View File
@@ -1,24 +0,0 @@
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.{yml,yaml}]
indent_size = 2
[*.{json,jsonc}]
indent_size = 2
[*.md]
trim_trailing_whitespace = false
[*.py]
indent_size = 4
[{Makefile,makefile}]
indent_style = tab
-39
View File
@@ -1,39 +0,0 @@
name: Deploy to Server
run-name: Deploying to ${{ runner.os}} server on ${{ gitea.ref }}
on:
push:
branches:
- main
- ci/gitea-actions
jobs:
deploy:
runs-on: prod
steps:
- name: Fetch and Diff Analysis
id: diff
run: |
cd ${{ secrets.PROD_DIR }}
git fetch origin main
CHANGES=$(git diff --name-only HEAD origin/main | cut -d/ -f1 | sort -u | tr '\n' ' ')
echo "dirs=$CHANGES" >> $GITHUB_OUTPUT
echo "Changed dirs: $CHANGES"
- name: Sync Server Files
run: |
cd ${{ secrets.PROD_DIR }}
git reset --hard origin/main
echo "Server files synced with origin/main"
- name: Deploy Services
run: |
cd ${{ secrets.PROD_DIR }}
for dir in ${{ steps.diff.outputs.dirs }}; do
if [ -d "$dir" ] && ([ -f "$dir/compose.yaml" ] || [ -f "$dir/docker-compose.yaml" ]); then
echo ">>> Deploying $dir"
cd "$dir"
DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=plain docker compose up -d --build --no-color
cd ..
else
echo ">>> Skipping $dir: no compose file found"
fi
done
-41
View File
@@ -1,41 +0,0 @@
## BINARY MODE, USE WITH THE GITHUB RUNNER BINARY INSTALLED ON THE SERVER
name: Deploy to Server
run-name: Deploying onto server on ${{ github.ref }}
on:
push:
branches:
- main
- ci/actions
jobs:
deploy:
runs-on: [prod, self-hosted]
steps:
- name: Fetch and Diff Analysis
id: diff
run: |
cd ${{ secrets.PROD_DIR }}
git fetch origin main
CHANGES=$(git diff --name-only HEAD origin/main | cut -d/ -f1 | sort -u | tr '\n' ' ')
echo "dirs=$CHANGES" >> $GITHUB_OUTPUT
echo "Changed dirs: $CHANGES"
- name: Sync Server Files
run: |
cd ${{ secrets.PROD_DIR }}
git reset --hard origin/main
echo "Server files synced with origin/main"
- name: Deploy Services
run: |
cd ${{ secrets.PROD_DIR }}
for dir in ${{ steps.diff.outputs.dirs }}; do
if [ -d "$dir" ] && ([ -f "$dir/compose.yaml" ] || [ -f "$dir/docker-compose.yaml" ]); then
echo ">>> Deploying $dir"
cd "$dir"
DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=plain docker compose up -d --build --no-color
cd ..
else
echo ">>> Skipping $dir: no compose file found"
fi
done
+3 -18
View File
@@ -5,12 +5,12 @@ sync.ffs_lock
# Copyparty # Copyparty
*.hist/ *.hist/
# Volumes, configs and data directories # Volumes and data directories
gitea/gitea-db/ gitea/gitea-db/
gitea/gitea-data/* gitea/gitea-data/*
n8n/n8n-data/* n8n/n8n-data/*
n8n/n8n-node-data/* n8n/n8n-node-data/*
adguardhome/conf/* adguardhome/data/*
dockmon/data/* dockmon/data/*
portainer/portainer_data/* portainer/portainer_data/*
metube/MeTube_downloads metube/MeTube_downloads
@@ -21,7 +21,6 @@ checkmk/checkmk/*
downtify/Downtify_downloads downtify/Downtify_downloads
headscale/config/* headscale/config/*
headscale/data/* headscale/data/*
searxng/core-config/*
# Steaming services files # Steaming services files
streaming/jellyfin/* streaming/jellyfin/*
@@ -33,21 +32,17 @@ streaming/qbittorrent/*
streaming/prowlarr/* streaming/prowlarr/*
# Homepage # Homepage
homepages/forust_files/assets/images/team/*
homepages/forust_files/.well-known/* homepages/forust_files/.well-known/*
# Traefik files # Traefik files
traefik/letsencrypt/acme.json traefik/letsencrypt/acme.json
traefik/dynamic/fileservers.yml traefik/dynamic/fileservers.yml
traefik/dynamic/*.local.y*ml.*
traefik/dynamic/*.external.y*ml
traefik/logs/* traefik/logs/*
# SSL Certificates # SSL Certificates
adguardhome/certs/* adguardhome/certs/*
traefik/certs/* traefik/certs/*
certs/
# Monitoring # Monitoring
monitoring/prometheus.yml monitoring/prometheus.yml
@@ -82,8 +77,6 @@ replacements.txt
# Git # Git
.gitattributes .gitattributes
# Gitea/github Runners
.runner
# Misc # Misc
.DS_Store .DS_Store
@@ -99,11 +92,3 @@ temp/*
.env.forust .env.forust
.env.* .env.*
!*example !*example
# kubernetes
*/k8s/*secret*
!*/k8s/*secret*.example
traefik/k8s/local-tls.yaml
converters/k8s/config.yaml
convertx/k8s/config.yaml
traefik/k8s/crowdsec-middleware.yaml
-10
View File
@@ -1,10 +0,0 @@
ignored:
- DL3008
- DL3042
- DL3018
- DL3059
trustedRegistries:
- docker.io
- ghcr.io
- quay.io
- gcr.forust.xyz
-8
View File
@@ -1,8 +0,0 @@
{
"default": true,
"MD013": false,
"MD024": false,
"MD033": false,
"MD041": false,
"MD046": false
}
-7
View File
@@ -1,7 +0,0 @@
bracketSameLine: true
htmlWhitespaceSensitivity: css
printWidth: 120
tabWidth: 2
trailingComma: all
proseWrap: preserve
endOfLine: lf
-22
View File
@@ -1,22 +0,0 @@
extends: default
rules:
comments:
min-spaces-from-content: 1
comments-indentation: false
document-start: disable
line-length: disable
braces:
min-spaces-inside: 0
max-spaces-inside: 1
brackets:
min-spaces-inside: 0
max-spaces-inside: 1
indentation:
spaces: 2
indent-sequences: consistent
truthy:
allowed-values:
- "true"
- "false"
- "on"
-39
View File
@@ -1,39 +0,0 @@
{
"tab_size": 2,
"soft_wrap": "prefer_line",
"preferred_line_length": 120,
"format_on_save": "on",
"languages": {
"YAML": {
"tab_size": 2,
"hard_tabs": false,
"format_on_save": "on",
"formatter": {
"language_server": { "name": "yaml-language-server" }
}
},
"Python": {
"tab_size": 4,
"format_on_save": "on",
"formatter": {
"language_server": { "name": "ruff" }
}
}
},
"lsp": {
"yaml-language-server": {
"settings": {
"yaml": {
"schemas": {
"kubernetes": ["**/k8s/*.yaml", "**/k8s/*.yml"]
},
"validate": true,
"completion": true,
"format": {
"enable": true
}
}
}
}
}
}
+11 -9
View File
@@ -11,29 +11,33 @@ services:
# - "68:68/tcp" # DHCP # - "68:68/tcp" # DHCP
# - "3000:3000/tcp" # - "3000:3000/tcp"
volumes: volumes:
- data:/opt/adguardhome/work - ./data/work:/opt/adguardhome/work
- ./conf:/opt/adguardhome/conf - ./data/conf:/opt/adguardhome/conf
- ./certs:/certs:ro - ./certs:/certs:ro
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.adguard.loadbalancer.server.port=3000" - "traefik.http.services.adguard.loadbalancer.server.port=3000"
# Prod Router # Prod Router
- "traefik.http.routers.adguard.rule=Host(`dns.forust.xyz`) || Host(`adguard.forust.xyz`)" - "traefik.http.routers.adguard.rule=Host(`dns.forust.xyz`) || Host(`adguard.forust.xyz`)"
- "traefik.http.routers.adguard.entrypoints=websecure" - "traefik.http.routers.adguard.entrypoints=websecure"
- "traefik.http.routers.adguard.tls.certresolver=letsencrypt" - "traefik.http.routers.adguard.middlewares=security-headers@file"
- "traefik.http.routers.adguard.tls=true"
# Local Router # Local Router
- "traefik.http.routers.adguard-local.rule=Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`)" - "traefik.http.routers.adguard-local.rule=Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`)"
- "traefik.http.routers.adguard-local.entrypoints=websecure" - "traefik.http.routers.adguard-local.entrypoints=websecure"
- "traefik.http.routers.adguard-local.middlewares=security-headers@file"
- "traefik.http.routers.adguard-local.tls=true" - "traefik.http.routers.adguard-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.adguard-dev.rule=Host(`adguard.gigaforust.internal`) || Host(`dns.gigaforust.internal`)" - "traefik.http.routers.adguard-dev.rule=Host(`adguard.gigaforust.internal`) Host(`dns.gigaforust.internal`)"
- "traefik.http.routers.adguard-dev.entrypoints=websecure" - "traefik.http.routers.adguard-dev.entrypoints=websecure"
- "traefik.http.routers.adguard-dev.middlewares=security-headers@file"
- "traefik.http.routers.adguard-dev.tls=true" - "traefik.http.routers.adguard-dev.tls=true"
# DoH Router # DoH Router
- "traefik.http.routers.dns-over-https.rule=(Host(`dns.forust.xyz` || Host(`adguard.forust.xyz`)) && PathPrefix(`/dns-query`))" - "traefik.http.routers.dns.rule=(Host(`dns.forust.xyz`) && PathPrefix(`/dns-query`))"
- "traefik.http.routers.dns-over-https.entrypoints=websecure" - "traefik.http.routers.dns.entrypoints=websecure"
- "traefik.http.routers.dns-over-https.tls.certresolver=letsencrypt" - "traefik.http.routers.dns.tls.certresolver=letsencrypt"
# Glance Metadata # Glance Metadata
- glance.name=adguard - glance.name=adguard
@@ -41,8 +45,6 @@ services:
- glance.description=AdGuard Home is a network-wide software for blocking ads. - glance.description=AdGuard Home is a network-wide software for blocking ads.
networks: networks:
- proxy - proxy
volumes:
data:
networks: networks:
proxy: proxy:
external: true external: true
-116
View File
@@ -1,116 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: adguard-lb-service
namespace: adguard
annotations:
metallb.io/loadBalancerIPs: "192.168.80.3"
spec:
type: LoadBalancer
externalTrafficPolicy: Local
selector:
app: adguard
ports:
- name: dns-udp
port: 53
targetPort: 53
protocol: UDP
- name: dns-tcp
port: 53
targetPort: 53
protocol: TCP
- name: dot
port: 853
targetPort: 853
protocol: TCP
---
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
-52
View File
@@ -1,52 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: adguard-prod
namespace: adguard
spec:
entryPoints:
- websecure
routes:
- match: Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
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: Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`) || Host(`adguard.gigaforust.internal`) || Host(`dns.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: (Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)) && PathPrefix(`/dns-query`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
services:
- name: adguard-service
port: 3000
tls:
certResolver: letsencrypt
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: adguard
-10
View File
@@ -1,10 +0,0 @@
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
+8 -2
View File
@@ -42,20 +42,26 @@ services:
- ./custom-templates:/templates - ./custom-templates:/templates
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.authentik-server.loadbalancer.server.port=9000" - "traefik.http.services.authentik-server.loadbalancer.server.port=9000"
# Prod Router # Prod Router
- "traefik.http.routers.authentik-server.rule=Host(`auth.forust.xyz`)" - "traefik.http.routers.authentik-server.rule=Host(`auth.forust.xyz`)"
- "traefik.http.routers.authentik-server.entrypoints=websecure" - "traefik.http.routers.authentik-server.entrypoints=websecure"
- "traefik.http.routers.authentik-server.tls.certresolver=letsencrypt" - "traefik.http.routers.authentik-server.middlewares=security-headers@file"
- "traefik.http.routers.authentik-server.service=authentik-server"
- "traefik.http.routers.authentik-server.tls=true"
# Local Router # Local Router
- "traefik.http.routers.authentik-server-local.rule=Host(`auth.workstation.internal`)" - "traefik.http.routers.authentik-server-local.rule=Host(`auth.workstation.internal`) || Host(`auth-dashboard.internal`)"
- "traefik.http.routers.authentik-server-local.entrypoints=websecure" - "traefik.http.routers.authentik-server-local.entrypoints=websecure"
- "traefik.http.routers.authentik-server-local.middlewares=security-headers@file"
- "traefik.http.routers.authentik-server-local.service=authentik-server"
- "traefik.http.routers.authentik-server-local.tls=true" - "traefik.http.routers.authentik-server-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.authentik-server-dev.rule=Host(`auth.gigaforust.internal`)" - "traefik.http.routers.authentik-server-dev.rule=Host(`auth.gigaforust.internal`)"
- "traefik.http.routers.authentik-server-dev.entrypoints=websecure" - "traefik.http.routers.authentik-server-dev.entrypoints=websecure"
- "traefik.http.routers.authentik-server-dev.middlewares=security-headers@file" - "traefik.http.routers.authentik-server-dev.middlewares=security-headers@file"
- "traefik.http.routers.authentik-server-dev.service=authentik-server"
- "traefik.http.routers.authentik-server-dev.tls=true" - "traefik.http.routers.authentik-server-dev.tls=true"
networks: networks:
- proxy - proxy
-93
View File
@@ -1,93 +0,0 @@
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"
-11
View File
@@ -1,11 +0,0 @@
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"
-33
View File
@@ -1,33 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: authentik-prod
namespace: authentik
spec:
entryPoints:
- websecure
routes:
- match: Host(`auth.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
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: Host(`auth.workstation.internal`) || Host(`auth.gigaforust.internal`)
kind: Rule
services:
- name: authentik-server-service
port: 9000
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: authentik
-66
View File
@@ -1,66 +0,0 @@
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
-11
View File
@@ -1,11 +0,0 @@
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
-15
View File
@@ -1,15 +0,0 @@
CLOUDFLARE_API_TOKEN=YOUR_CLOUDFLARE_API_TOKEN
DOMAINS=example.com,dns.example.com,mc.example.com,auth.example.com,ssh.example.com
IP4_DOMAINS=
IP6_DOMAINS=
IP4_PROVIDER=cloudflare.trace
IP6_PROVIDER=none # change if you want to update AAAA
UPDATE_CRON=@every 5m
UPDATE_ON_START=true
DELETE_ON_STOP=false
DELETE_ON_FAILURE=true
TTL=1
PROXIED=!is(dns.example.com) && !is(mc.example.com) && !is(ssh.example.com)
EMOJI=true
UPTIMEKUMA=https://uptime-kuma.example.com/api/push/AsaSDFGFkfklaFALSKffkfFKfkfkfkFK?status=up&msg=OK&ping=
REJECT_CLOUDFLARE_IPS=true
+5 -22
View File
@@ -5,26 +5,9 @@ services:
restart: unless-stopped restart: unless-stopped
security_opt: security_opt:
- no-new-privileges:true - no-new-privileges:true
network_mode: "host" network_mode: 'host'
# https://github.com/timothymiller/cloudflare-ddns#-quick-start
environment: environment:
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN:?Cloudflare API token is required} - PUID=1000
- DOMAINS=${DOMAINS:-} - PGID=1000
- IP4_DOMAINS=${IP4_DOMAINS:-} volumes:
- IP6_DOMAINS=${IP6_DOMAINS:-} - ./config.json:/config.json
- IP4_PROVIDER=${IP4_PROVIDER:-cloudflare.trace}
- IP6_PROVIDER=${IP6_PROVIDER:-none}
- UPDATE_CRON=${UPDATE_CRON:-@every 5m}
- UPDATE_ON_START=${UPDATE_ON_START:-true}
- DELETE_ON_STOP=${DELETE_ON_STOP:-false}
- DELETE_ON_FAILURE=${DELETE_ON_FAILURE:-true}
- TTL=${TTL:-1} # 1=auto
# to proxy only "dns.example.com" and "wfs.example.com" use "!is(dns.domain.com) && !is (wfs.domain.com)"
- PROXIED=${PROXIED:-true}
- EMOJI=${EMOJI:-true}
- UPTIMEKUMA=${UPTIMEKUMA:-}
- HEALTHCHECKS=${HEALTHCHECKS:-}
- REJECT_CLOUDFLARE_IPS=${REJECT_CLOUDFLARE_IPS:-true}
# volumes:
# Prefer using environment variables for configuration, config.json legacy support
# - ./config.json:/config.json
-1
View File
@@ -1 +0,0 @@
secret.yaml
-32
View File
@@ -1,32 +0,0 @@
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
-18
View File
@@ -1,18 +0,0 @@
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"
+5 -2
View File
@@ -13,21 +13,24 @@ services:
environment: environment:
- CMK_PASSWORD=${CMK_PASSWORD:-password} - CMK_PASSWORD=${CMK_PASSWORD:-password}
- CMK_SITE_ID=cmk - CMK_SITE_ID=cmk
- TZ=${TZ:-Etc/UTC}
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.checkmk.loadbalancer.server.port=5000" - "traefik.http.services.checkmk.loadbalancer.server.port=5000"
# Prod Router # Prod Router
- "traefik.http.routers.checkmk.rule=Host(`cmk.forust.xyz`)" - "traefik.http.routers.checkmk.rule=Host(`cmk.forust.xyz`)"
- "traefik.http.routers.checkmk.entrypoints=websecure" - "traefik.http.routers.checkmk.entrypoints=websecure"
- "traefik.http.routers.checkmk.tls.certresolver=letsencrypt" - "traefik.http.routers.checkmk.middlewares=security-headers@file"
- "traefik.http.routers.checkmk.tls=true"
# Local Router # Local Router
- "traefik.http.routers.checkmk-local.rule=Host(`cmk.workstation.internal`)" - "traefik.http.routers.checkmk-local.rule=Host(`cmk.workstation.internal`)"
- "traefik.http.routers.checkmk-local.entrypoints=websecure" - "traefik.http.routers.checkmk-local.entrypoints=websecure"
- "traefik.http.routers.checkmk-local.middlewares=security-headers@file"
- "traefik.http.routers.checkmk-local.tls=true" - "traefik.http.routers.checkmk-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.checkmk-dev.rule=Host(`cmk.gigaforust.internal`)" - "traefik.http.routers.checkmk-dev.rule=Host(`cmk.gigaforust.internal`)"
- "traefik.http.routers.checkmk-dev.middlewares=security-headers@file"
- "traefik.http.routers.checkmk-dev.entrypoints=websecure" - "traefik.http.routers.checkmk-dev.entrypoints=websecure"
- "traefik.http.routers.checkmk-dev.tls=true" - "traefik.http.routers.checkmk-dev.tls=true"
networks: networks:
-68
View File
@@ -1,68 +0,0 @@
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
-8
View File
@@ -1,8 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: checkmk-config
namespace: checkmk
data:
TZ: Europe/Bratislava
CMK_SITE_ID: cmk
-33
View File
@@ -1,33 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: checkmk-prod
namespace: checkmk
spec:
entryPoints:
- websecure
routes:
- match: Host(`cmk.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
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: Host(`cmk.workstation.internal`) || Host(`cmk.gigaforust.internal`)
kind: Rule
services:
- name: checkmk-service
port: 5000
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: checkmk
-8
View File
@@ -1,8 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: checkmk-secrets
namespace: checkmk
type: Opaque
stringData:
CMK_PASSWORD: "password"
-9
View File
@@ -1,9 +0,0 @@
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
-70
View File
@@ -1,70 +0,0 @@
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(`forust.xyz`) || Host(`www.forust.xyz`)) && PathPrefix(`/convert`)"
- "traefik.http.routers.convertx.entrypoints=websecure"
- "traefik.http.routers.convertx.priority=50"
- "traefik.http.routers.convertx.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.convertx-local.rule=Host(`workstation.internal`) && PathPrefix(`/convert`)"
- "traefik.http.routers.convertx-local.entrypoints=websecure"
- "traefik.http.routers.convertx-local.priority=50"
- "traefik.http.routers.convertx-local.tls=true"
# Dev Router
- "traefik.http.routers.convertx-dev.rule=Host(`gigaforust.internal`) && PathPrefix(`/convert`)"
- "traefik.http.routers.convertx-dev.entrypoints=websecure"
- "traefik.http.routers.convertx-dev.priority=50"
- "traefik.http.routers.convertx-dev.tls=true"
networks:
- proxy
volumes:
- data:/app/data
bentopdf:
container_name: bentopdf
image: bentopdf/bentopdf:latest
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.services.bentopdf.loadbalancer.server.port=8080"
# Prod router
- "traefik.http.routers.bentopdf.rule=Host(`pdf.forust.xyz`)"
- "traefik.http.routers.bentopdf.entrypoints=websecure"
- "traefik.http.routers.bentopdf.tls.certresolver=letsencrypt"
- "traefik.http.routers.bentopdf.tls=true"
# Local router
- "traefik.http.routers.bentopdf-local.rule=Host(`pdf.wokstation.internal`)"
- "traefik.http.routers.bentopdf-local.entrypoints=websecure"
- "traefik.http.routers.bentopdf-local.tls=true"
# Dev router
- "traefik.http.routers.bentopdf-dev.rule=Host(`pdf.gigaforust.internal`)"
- "traefik.http.routers.bentopdf-dev.entrypoints=websecure"
- "traefik.http.routers.bentopdf-dev.tls=true"
networks:
- proxy
networks:
proxy:
external: true
volumes:
data:
-42
View File
@@ -1,42 +0,0 @@
kind: Service
apiVersion: v1
metadata:
name: bentopdf-service
namespace: converters
spec:
selector:
app: bentopdf
ports:
- port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: bentopdf-deployment
namespace: converters
spec:
replicas: 2
selector:
matchLabels:
app: bentopdf
template:
metadata:
labels:
app: bentopdf
spec:
containers:
- image: bentopdf/bentopdf:latest
imagePullPolicy: Always
name: bentopdf
ports:
- containerPort: 8080
resources:
requests:
memory: "50Mi"
cpu: "50m"
ephemeral-storage: "100Mi"
limits:
memory: "700Mi"
cpu: "700m"
ephemeral-storage: "5Gi"
-16
View File
@@ -1,16 +0,0 @@
# test manifest with docker and k8s config keys mismatch
apiVersion: v1
kind: ConfigMap
metadata:
name: convertx-config
namespace: converters
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"
-63
View File
@@ -1,63 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: convertx-service
namespace: converters
spec:
selector:
app: convertx
ports:
- port: 3000
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: convertx-deployment
namespace: converters
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: converters
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
-65
View File
@@ -1,65 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: convertx-prod
namespace: converters
spec:
entryPoints:
- websecure
routes:
- match: (Host(`forust.xyz`) || Host(`www.forust.xyz`)) && PathPrefix(`/convert`)
kind: Rule
priority: 50
services:
- name: convertx-service
port: 3000
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: convertx-local
namespace: converters
spec:
entryPoints:
- websecure
routes:
- match: (Host(`workstation.internal`) || Host(`gigaforust.internal`)) && PathPrefix(`/convert`)
kind: Rule
priority: 50
services:
- name: convertx-service
port: 3000
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: bentopdf-prod
namespace: converters
spec:
entryPoints:
- websecure
routes:
- match: Host(`pdf.forust.xyz`)
kind: Rule
services:
- name: bentopdf-service
port: 8080
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: bentopdf-local
namespace: converters
spec:
entryPoints:
- websecure
routes:
- match: Host(`pdf.workstation.internal`) || Host(`pdf.gigaforust.internal`)
kind: Rule
services:
- name: bentopdf-service
port: 8080
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: converters
-8
View File
@@ -1,8 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: convertx-secrets
namespace: converters
type: Opaque
stringData:
jwt-secret: ""
-14
View File
@@ -1,14 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: crowdsec-bouncer
namespace: crowdsec
spec:
plugin:
crowdsec-bouncer:
enabled: true
LogLevel: INFO
CrowdsecMode: live
CrowdsecLapiScheme: http
CrowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080
CrowdsecLapiKeyFile: "/etc/traefik/secrets/traefik-api-key"
-57
View File
@@ -1,57 +0,0 @@
container_runtime: containerd
agent:
env:
- name: COLLECTIONS
value: "crowdsecurity/traefik crowdsecurity/base-http-scenarios crowdsecurity/sshd"
extraVolumes:
- name: journal-dir
hostPath:
path: /var/log/journal
type: DirectoryOrCreate
- name: run-journal-dir
hostPath:
path: /run/log/journal
type: DirectoryOrCreate
extraVolumeMounts:
- name: journal-dir
mountPath: /var/log/journal
readOnly: true
- name: run-journal-dir
mountPath: /run/log/journal
readOnly: true
acquisition:
- namespace: traefik
podName: "*traefik*"
program: traefik
poll_without_inotify: true
acquisitionCustom: |
- source: journalctl
journalctl_filter:
- _SYSTEMD_UNIT=sshd.service
labels:
type: syslog
resources:
requests:
cpu: 50m
memory: 100Mi
limits:
cpu: 200m
memory: 500Mi
lapi:
env:
- name: COLLECTIONS
value: "crowdsecurity/traefik crowdsecurity/base-http-scenarios crowdsecurity/sshd"
service:
type: NodePort
nodePort: 30011
resources:
requests:
cpu: 50m
memory: 150Mi
limits:
cpu: 200m
memory: 500Mi
+6 -2
View File
@@ -15,6 +15,7 @@ services:
retries: 3 retries: 3
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.dockmon.loadbalancer.server.port=443" - "traefik.http.services.dockmon.loadbalancer.server.port=443"
- "traefik.http.services.dockmon.loadbalancer.server.scheme=https" - "traefik.http.services.dockmon.loadbalancer.server.scheme=https"
- "traefik.http.services.dockmon.loadbalancer.serverstransport=insecureTransport@file" - "traefik.http.services.dockmon.loadbalancer.serverstransport=insecureTransport@file"
@@ -22,15 +23,18 @@ services:
# Prod Router # Prod Router
- "traefik.http.routers.dockmon.rule=Host(`dockmon.forust.xyz`)" - "traefik.http.routers.dockmon.rule=Host(`dockmon.forust.xyz`)"
- "traefik.http.routers.dockmon.entrypoints=websecure" - "traefik.http.routers.dockmon.entrypoints=websecure"
- "traefik.http.routers.dockmon.middlewares=security-headers@file" - "traefik.http.routers.dockmon.middlewares=security-chain@file"
- "traefik.http.routers.dockmon.tls.certresolver=letsencrypt" - "traefik.http.routers.dockmon.service=dockmon"
- "traefik.http.routers.dockmon.tls=true"
# Local Router # Local Router
- "traefik.http.routers.dockmon-local.rule=Host(`dockmon.workstation.internal`)" - "traefik.http.routers.dockmon-local.rule=Host(`dockmon.workstation.internal`)"
- "traefik.http.routers.dockmon-local.entrypoints=websecure" - "traefik.http.routers.dockmon-local.entrypoints=websecure"
- "traefik.http.routers.dockmon-local.middlewares=security-headers@file"
- "traefik.http.routers.dockmon-local.tls=true" - "traefik.http.routers.dockmon-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.dockmon-dev.rule=Host(`dockmon.gigaforust.internal`)" - "traefik.http.routers.dockmon-dev.rule=Host(`dockmon.gigaforust.internal`)"
- "traefik.http.routers.dockmon-dev.entrypoints=websecure" - "traefik.http.routers.dockmon-dev.entrypoints=websecure"
- "traefik.http.routers.dockmon-dev.middlewares=security-chain@file"
- "traefik.http.routers.dockmon-dev.tls=true" - "traefik.http.routers.dockmon-dev.tls=true"
# Glance Metadata # Glance Metadata
-68
View File
@@ -1,68 +0,0 @@
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
-44
View File
@@ -1,44 +0,0 @@
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: Host(`dockmon.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
- 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: Host(`dockmon.workstation.internal`) || Host(`dockmon.gigaforust.internal`)
kind: Rule
services:
- name: dockmon-service
port: 443
serversTransport: dockmon-transport
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: dockmon
+15 -13
View File
@@ -2,28 +2,30 @@ services:
downtify: downtify:
container_name: downtify container_name: downtify
image: ghcr.io/henriquesebastiao/downtify:latest image: ghcr.io/henriquesebastiao/downtify:latest
restart: unless-stopped
# ports: # ports:
# - '7077:8000' # - '7077:8000'
volumes: volumes:
- ./Downtify_downloads:/downloads - ./Downtify_downloads:/downloads
labels: labels:
- "traefik.enable=true" - traefik.enable=true
- "traefik.http.services.downtify.loadbalancer.server.port=8000" - traefik.docker.network=proxy
- traefik.http.services.downtify.loadbalancer.server.port=8000
# Prod Router # Prod Router
- "traefik.http.routers.downtify.rule=Host(`downtify.forust.xyz`)" - traefik.http.routers.downtify.rule=Host(`downtify.forust.xyz`)
- "traefik.http.routers.downtify.entrypoints=websecure" - traefik.http.routers.downtify.entrypoints=websecure
- "traefik.http.routers.downtify.middlewares=security-chain@file" - traefik.http.routers.downtify.middlewares=security-chain@file
- "traefik.http.routers.downtify.tls.certresolver=letsencrypt" - traefik.http.routers.downtify.tls=true
# Local Router # Local Router
- "traefik.http.routers.downtify-local.rule=Host(`downtify.workstation.internal`)" - traefik.http.routers.downtify-local.rule=Host(`downtify.workstation.internal`) || Host(`downtify.internal`)
- "traefik.http.routers.downtify-local.entrypoints=websecure" - traefik.http.routers.downtify-local.entrypoints=websecure
- "traefik.http.routers.downtify-local.tls=true" - traefik.http.routers.downtify-local.middlewares=security-headers@file
- traefik.http.routers.downtify-local.tls=true
# Dev Router # Dev Router
- "traefik.http.routers.downtify-dev.rule=Host(`downtify.gigaforust.internal`)" - traefik.http.routers.downtify-dev.rule=Host(`downtify.gigaforust.internal`)
- "traefik.http.routers.downtify-dev.entrypoints=websecure" - traefik.http.routers.downtify-dev.entrypoints=websecure
- "traefik.http.routers.downtify-dev.tls=true" - traefik.http.routers.downtify-dev.middlewares=security-chain@file
- traefik.http.routers.downtify-dev.tls=true
networks: networks:
- proxy - proxy
networks: networks:
-58
View File
@@ -1,58 +0,0 @@
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
-34
View File
@@ -1,34 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: downtify-prod
namespace: downtify
spec:
entryPoints:
- websecure
routes:
- match: Host(`downtify.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
- 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: Host(`downtify.workstation.internal`) || Host(`downtify.gigaforust.internal`)
kind: Rule
services:
- name: downtify-service
port: 8000
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: downtify
+1 -2
View File
@@ -3,11 +3,10 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
image: gcr.forust.xyz/forust/dtek-notif:latest
pull_policy: build
restart: unless-stopped restart: unless-stopped
environment: environment:
- TZ=Europe/Kyiv - TZ=Europe/Kyiv
dns: dns:
- 1.1.1.1 - 1.1.1.1
- 8.8.8.8 - 8.8.8.8
-4
View File
@@ -17,8 +17,6 @@ services:
session-keeper: session-keeper:
build: ./phpsessid-bot build: ./phpsessid-bot
image: gcr.forust.xyz/forust/session-keeper:latest
pull_policy: build
env_file: .env env_file: .env
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
@@ -33,8 +31,6 @@ services:
webinar-checker: webinar-checker:
build: ./webinar-checker build: ./webinar-checker
image: gcr.forust.xyz/forust/webinar-checker:latest
pull_policy: build
env_file: .env env_file: .env
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
+1 -274
View File
@@ -1,10 +1,7 @@
import os import os
import re
import logging import logging
import redis import redis
import json import json
import time
from datetime import datetime, timedelta
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, ChatMember from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, ChatMember
from telegram.constants import ChatType from telegram.constants import ChatType
@@ -33,7 +30,6 @@ def _env(key, default=None):
EDU_BASE = _env('EDU_URL_BASE', 'https://edu.edu.vn.ua') EDU_BASE = _env('EDU_URL_BASE', 'https://edu.edu.vn.ua')
EDU_WEBINAR_PATH = _env('EDU_URL_WEBINAR', '/webinar/useractive') EDU_WEBINAR_PATH = _env('EDU_URL_WEBINAR', '/webinar/useractive')
WEBINAR_URL = f"{EDU_BASE.rstrip('/')}/{EDU_WEBINAR_PATH.lstrip('/')}" 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)) WEBINAR_CHECK_INTERVAL = int(_env('WEBINAR_CHECK_INTERVAL', 60))
REDIS_HOST = _env('REDIS_HOST', 'redis') REDIS_HOST = _env('REDIS_HOST', 'redis')
@@ -256,205 +252,6 @@ def get_admin_keyboard(user_id: int):
] ]
return InlineKeyboardMarkup(keyboard) 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 --- # --- Command Handlers ---
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
@@ -579,74 +376,6 @@ async def clear_history(update: Update, context: ContextTypes.DEFAULT_TYPE):
logger.error(f"Failed to clear history: {e}") logger.error(f"Failed to clear history: {e}")
await update.message.reply_text(t(admin_id, 'history_clear_failed')) 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 --- # --- Admin Callbacks ---
async def admin_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): async def admin_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
@@ -920,10 +649,8 @@ def main():
app.add_handler(CommandHandler("adduser", add_user)) app.add_handler(CommandHandler("adduser", add_user))
app.add_handler(CommandHandler("removeuser", remove_user)) app.add_handler(CommandHandler("removeuser", remove_user))
app.add_handler(CommandHandler("clearhistory", clear_history)) app.add_handler(CommandHandler("clearhistory", clear_history))
app.add_handler(CommandHandler("diary", diary_command))
# Callback handlers - diary first, then language selection, then admin panel # Callback handlers - language selection first, then admin panel
app.add_handler(CallbackQueryHandler(diary_callback, pattern="^diary_"))
app.add_handler(CallbackQueryHandler(language_callback, pattern="^lang_")) app.add_handler(CallbackQueryHandler(language_callback, pattern="^lang_"))
app.add_handler(CallbackQueryHandler(admin_callback)) app.add_handler(CallbackQueryHandler(admin_callback))
-5
View File
@@ -1,5 +0,0 @@
FROM nginx:alpine
RUN rm -rf /usr/share/nginx/html/*
COPY html /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
-21
View File
@@ -1,21 +0,0 @@
services:
errorpage:
build: .
image: gcr.forust.xyz/forust/error-pages:latest
pull_policy: build
container_name: error-pages
restart: unless-stopped
# ports:
# - 1234:80
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.services.error-pages.loadbalancer.server.port=80"
# Error handler middleware
- "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:
proxy:
external: true
-208
View File
@@ -1,208 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>403 // Forbidden</title>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1 class="glitch" data-text="403">403</h1>
<p class="subtitle">> Forbidden / Access Denied.</p>
</header>
<hr>
<section id="message">
<h2>./error_message</h2>
<p>You do not have permission to access this resource.</p>
<br>
<p>Check the <a href="https://status.forust.xyz">System Status</a> if you believe this is an
error.</p>
</section>
<footer>
<p>root@error:~$ sudo access_resource</p>
<p>User is not in the sudoers file. This incident will be reported.</p>
<p>&copy; XRock - Just Signal.</p>
</footer>
</div>
</body>
</html>
-207
View File
@@ -1,207 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>404 // Not Found</title>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1 class="glitch" data-text="404">404</h1>
<p class="subtitle">> Page Not Found / Lost in the Void.</p>
</header>
<hr>
<section id="message">
<h2>./error_message</h2>
<p>The page you are looking for does not exist or has been moved.</p>
<br>
<p>Check the <a href="https://status.forust.xyz">System Status</a> if you believe this is an error.</p>
</section>
<footer>
<p>root@error:~$ ping target</p>
<p>Destination Host Unreachable</p>
<p>&copy; XRock - Just Signal.</p>
</footer>
</div>
</body>
</html>
-207
View File
@@ -1,207 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>500 // Server Error</title>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1 class="glitch" data-text="500">500</h1>
<p class="subtitle">> Internal Server Error / System Failure.</p>
</header>
<hr>
<section id="message">
<h2>./error_message</h2>
<p>Something went wrong on our end. We are working to fix it.</p>
<br>
<p>Check the <a href="https://status.forust.xyz">System Status</a> for more information.</p>
</section>
<footer>
<p>root@error:~$ systemctl status service</p>
<p>Active: failed (Result: core-dump)</p>
<p>&copy; XRock - Just Signal.</p>
</footer>
</div>
</body>
</html>
-207
View File
@@ -1,207 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>502 // Bad Gateway</title>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1 class="glitch" data-text="502">502</h1>
<p class="subtitle">> Bad Gateway / System Failure.</p>
</header>
<hr>
<section id="message">
<h2>./error_message</h2>
<p>The server received an invalid response from the upstream server.</p>
<br>
<p>Check the <a href="https://status.forust.xyz">System Status</a> for more information.</p>
</section>
<footer>
<p>root@error:~$ curl -I upstream_host</p>
<p>HTTP/1.1 502 Bad Gateway</p>
<p>&copy; XRock - Just Signal.</p>
</footer>
</div>
</body>
</html>
-207
View File
@@ -1,207 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>503 // Service Unavailable</title>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1 class="glitch" data-text="503">503</h1>
<p class="subtitle">> Service Unavailable / System Failure.</p>
</header>
<hr>
<section id="message">
<h2>./error_message</h2>
<p>The server is currently unable to handle the request due to maintenance or overload.</p>
<br>
<p>Check the <a href="https://status.forust.xyz">System Status</a> for more information.</p>
</section>
<footer>
<p>root@error:~$ systemctl start service</p>
<p>Job for service failed because the control process exited with error code.</p>
<p>&copy; XRock - Just Signal.</p>
</footer>
</div>
</body>
</html>
-207
View File
@@ -1,207 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>504 // Gateway Timeout</title>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1 class="glitch" data-text="504">504</h1>
<p class="subtitle">> Gateway Timeout / System Failure.</p>
</header>
<hr>
<section id="message">
<h2>./error_message</h2>
<p>The server did not receive a timely response from the upstream server.</p>
<br>
<p>Check the <a href="https://status.forust.xyz">System Status</a> for more information.</p>
</section>
<footer>
<p>root@error:~$ timeout 30s curl upstream</p>
<p>curl: (28) Operation timed out after 30001 milliseconds with 0 bytes received</p>
<p>&copy; XRock - Just Signal.</p>
</footer>
</div>
</body>
</html>
-33
View File
@@ -1,33 +0,0 @@
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
---
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: error-pages
+6 -6
View File
@@ -1,6 +1,6 @@
services: services:
server: server:
image: docker.gitea.com/gitea:1.26 image: docker.gitea.com/gitea:1.25.1
container_name: gitea container_name: gitea
restart: always restart: always
environment: environment:
@@ -31,28 +31,28 @@ services:
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.gitea.loadbalancer.server.port=3000" - "traefik.http.services.gitea.loadbalancer.server.port=3000"
# Prod Router # Prod Router
- "traefik.http.routers.gitea.rule=Host(`gitea.forust.xyz`)" - "traefik.http.routers.gitea.rule=Host(`gitea.forust.xyz`)"
- "traefik.http.routers.gitea.entrypoints=websecure" - "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls.certresolver" - "traefik.http.routers.gitea.middlewares=security-headers@file"
- "traefik.http.routers.gitea.tls=true"
# Local Router # Local Router
- "traefik.http.routers.gitea-local.rule=Host(`gitea.workstation.internal`)" - "traefik.http.routers.gitea-local.rule=Host(`gitea.workstation.internal`)"
- "traefik.http.routers.gitea-local.entrypoints=websecure" - "traefik.http.routers.gitea-local.entrypoints=websecure"
- "traefik.http.routers.gitea-local.middlewares=security-headers@file"
- "traefik.http.routers.gitea-local.tls=true" - "traefik.http.routers.gitea-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.gitea-dev.rule=Host(`gitea.gigaforust.internal`)" - "traefik.http.routers.gitea-dev.rule=Host(`gitea.gigaforust.internal`)"
- "traefik.http.routers.gitea-dev.entrypoints=websecure" - "traefik.http.routers.gitea-dev.entrypoints=websecure"
- "traefik.http.routers.gitea-dev.middlewares=security-headers@file"
- "traefik.http.routers.gitea-dev.tls=true" - "traefik.http.routers.gitea-dev.tls=true"
# SSH Router # SSH Router
- "traefik.tcp.services.gitea.loadbalancer.server.port=22" - "traefik.tcp.services.gitea.loadbalancer.server.port=22"
- "traefik.tcp.routers.gitea.entrypoints=ssh" - "traefik.tcp.routers.gitea.entrypoints=ssh"
- "traefik.tcp.routers.gitea.rule=HostSNI(`*`)" - "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"
ports: ports:
- "2221:22" - "2221:22"
networks: networks:
-20
View File
@@ -1,20 +0,0 @@
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"
-71
View File
@@ -1,71 +0,0 @@
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
---
-64
View File
@@ -1,64 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: gitea-prod
namespace: gitea
spec:
entryPoints:
- websecure
routes:
- match: Host(`gitea.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
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: Host(`gitea.workstation.internal`) || Host(`gitea.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
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: gitea
-62
View File
@@ -1,62 +0,0 @@
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
-9
View File
@@ -1,9 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: gitea-secrets
namespace: gitea
type: Opaque
stringData:
GITEA__database__USER: "gitea"
GITEA__database__PASSWD: "gitea"
+8 -8
View File
@@ -12,22 +12,22 @@ services:
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy" - "traefik.docker.network=proxy"
- "traefik.services.glance.loadbalancer.server.port=8080" # FIXME: traefik.services.glance.loadbalancer.server.port ??
# Prod Router # Prod Router
- "traefik.http.routers.glance.rule=(Host(`forust.xyz`) || Host(`www.forust.xyz`)) && PathPrefix(`/glance`)" - "traefik.http.routers.glance.rule=Host(`glance.forust.xyz`)"
- "traefik.http.routers.glance.entrypoints=websecure" - "traefik.http.routers.glance.entrypoints=websecure"
- "traefik.http.routers.glance.priority=50" - "traefik.http.routers.glance.middlewares=security-headers@file"
- "traefik.http.routers.glance.tls.certresolver=letsencrypt" - "traefik.http.routers.glance.tls=true"
# Local Router # Local Router
- "traefik.http.routers.glance-local.rule=Host(`workstation.internal`) && PathPrefix(`/glance`)" - "traefik.http.routers.glance-local.rule=Host(`glance.workstation.internal`)"
- "traefik.http.routers.glance-local.entrypoints=websecure" - "traefik.http.routers.glance-local.entrypoints=websecure"
- "traefik.http.routers.glance-local.priority=50" - "traefik.http.routers.glance-local.middlewares=security-headers@file"
- "traefik.http.routers.glance-local.tls=true" - "traefik.http.routers.glance-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.glance-dev.rule=Host(`gigaforust.internal`) && PathPrefix(`/glance`)" - "traefik.http.routers.glance-dev.rule=Host(`glance.gigaforust.internal`)"
- "traefik.http.routers.glance-dev.entrypoints=websecure" - "traefik.http.routers.glance-dev.entrypoints=websecure"
- "traefik.http.routers.glance-dev.priority=50" - "traefik.http.routers.glance-dev.middlewares=security-headers@file"
- "traefik.http.routers.glance-dev.tls=true" - "traefik.http.routers.glance-dev.tls=true"
networks: networks:
- proxy - proxy
+1
View File
@@ -65,6 +65,7 @@
- symbol: MSFT - symbol: MSFT
name: Microsoft name: Microsoft
- type: releases - type: releases
cache: 1d cache: 1d
# Without authentication the Github API allows for up to 60 requests per hour. You can create a # Without authentication the Github API allows for up to 60 requests per hour. You can create a
+2
View File
@@ -11,3 +11,5 @@
widgets: widgets:
- type: docker-containers - type: docker-containers
hide-by-default: false hide-by-default: false
-211
View File
@@ -1,211 +0,0 @@
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
proxied: true
base-url: /glance
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
-78
View File
@@ -1,78 +0,0 @@
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: "30Mi"
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
-47
View File
@@ -1,47 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: glance-prod
namespace: glance
spec:
entryPoints:
- websecure
routes:
- match: (Host(`forust.xyz`) || Host(`www.forust.xyz`)) && PathPrefix(`/glance`)
kind: Rule
priority: 50
middlewares:
- name: glance-stripprefix
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: (Host(`glance.workstation.internal`) || Host(`glance.gigaforust.internal`)) && PathPrefix(`/glance`)
kind: Rule
middlewares:
- name: glance-stripprefix
priority: 50
services:
- name: glance-service
port: 8080
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: glance-stripprefix
namespace: glance
spec:
stripPrefix:
prefixes:
- /glance
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: glance
+9 -30
View File
@@ -4,18 +4,15 @@ services:
restart: unless-stopped restart: unless-stopped
container_name: headscale-server container_name: headscale-server
command: serve command: serve
ports:
- 18080:8080
- 19090:9090
networks: networks:
- proxy - proxy
volumes: volumes:
- ./config/headscale.yaml:/etc/headscale/config.yaml - ./config/headscale.yaml:/etc/headscale/config.yaml
- data:/var/lib/headscale - data:/var/lib/headscale
- ./config/policy.json:/var/lib/headscale/policy.json
labels: labels:
- "me.tale.headplane.target: headscale" - "me.tale.headplane.target: headscale"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.headscale.loadbalancer.server.port=8080" - "traefik.http.services.headscale.loadbalancer.server.port=8080"
- "traefik.http.services.headscale-metrics.loadbalancer.server.port=9090" - "traefik.http.services.headscale-metrics.loadbalancer.server.port=9090"
@@ -24,7 +21,7 @@ services:
- "traefik.http.routers.headscale.rule=Host(`hs.forust.xyz`)" - "traefik.http.routers.headscale.rule=Host(`hs.forust.xyz`)"
- "traefik.http.routers.headscale.entrypoints=websecure" - "traefik.http.routers.headscale.entrypoints=websecure"
- "traefik.http.routers.headscale.service=headscale" - "traefik.http.routers.headscale.service=headscale"
- "traefik.http.routers.headscale.tls.certresolver=letsencrypt" - "traefik.http.routers.headscale.tls=true"
# Local Router # Local Router
- "traefik.http.routers.headscale-local.rule=Host(`hs.workstation.internal`)" - "traefik.http.routers.headscale-local.rule=Host(`hs.workstation.internal`)"
- "traefik.http.routers.headscale-local.entrypoints=websecure" - "traefik.http.routers.headscale-local.entrypoints=websecure"
@@ -57,7 +54,7 @@ services:
container_name: headplane container_name: headplane
restart: unless-stopped restart: unless-stopped
ports: ports:
- "13000:3000" - '3000:3000'
volumes: volumes:
- ./config/headplane.yaml:/etc/headplane/config.yaml - ./config/headplane.yaml:/etc/headplane/config.yaml
- ./config/headscale.yaml:/etc/headscale/config.yaml - ./config/headscale.yaml:/etc/headscale/config.yaml
@@ -65,30 +62,12 @@ services:
- /var/run/docker.sock:/var/run/docker.sock:ro - /var/run/docker.sock:/var/run/docker.sock:ro
networks: networks:
- proxy - proxy
web: healthcheck:
image: goodieshq/headscale-admin:latest test: [ "CMD", "/bin/hp_healthcheck" ]
restart: unless-stopped interval: 30s
ports: timeout: 5s
- 10080:80 start_period: 5s
labels: retries: 3
- "traefik.enable=true"
- "traefik.http.services.headscale-ui.loadbalancer.server.port=80"
# Prod Router
- "traefik.http.routers.headscale-ui.rule=Host(`hs.forust.xyz`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headscale-ui.entrypoints=websecure"
- "traefik.http.routers.headscale-ui.middlewares=security-chain@file"
- "traefik.http.routers.headscale-ui.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.headscale-ui-local.rule=Host(`hs.workstation.internal`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headscale-ui-local.entrypoints=websecure"
- "traefik.http.routers.headscale-ui-local.tls=true"
# Dev Router
- "traefik.http.routers.headscale-ui-dev.rule=Host(`hs.gigaforust.internal`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headscale-ui-dev.entrypoints=websecure"
- "traefik.http.routers.headscale-ui-dev.tls=true"
networks:
- proxy
volumes: volumes:
data: data:
headplane-data: headplane-data:
+2 -3
View File
@@ -33,9 +33,7 @@ derp:
auto_update_enabled: true auto_update_enabled: true
update_frequency: 24h update_frequency: 24h
disable_check_updates: false disable_check_updates: false
node: ephemeral_node_inactivity_timeout: 30m
ephemeral:
inactivity_timeout: 30m
database: database:
type: sqlite type: sqlite
debug: false debug: false
@@ -78,3 +76,4 @@ unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770" unix_socket_permission: "0770"
logtail: logtail:
enabled: false enabled: false
randomize_client_port: false
-27
View File
@@ -1,27 +0,0 @@
{
"groups": {
"group:admin": [
"admin@"
],
"group:users": []
},
"tagOwners": {},
"hosts": {},
"acls": [
{
"randomizeClientPort": false,
"#ha-meta": {
"name": "users",
"open": true
},
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"autogroup:self:*"
]
}
],
"ssh": []
}
-59
View File
@@ -1,59 +0,0 @@
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"
-106
View File
@@ -1,106 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-server-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: Host(`hs.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
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: Host(`hs.workstation.internal`) || Host(`hs.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: Host(`hs.forust.xyz`) && PathPrefix(`/admin`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
- 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: Host(`hs.forust.xyz`) && PathPrefix(`/metrics`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
services:
- name: headscale-server-external
port: 9090
tls:
certResolver: letsencrypt
domains:
- main: hs.forust.xyz
---
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
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: headscale
+12 -11
View File
@@ -3,8 +3,6 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile.forust dockerfile: Dockerfile.forust
image: gcr.forust.xyz/forust/forust-homepage:latest
pull_policy: build
# ports: # ports:
# - "8085:80" # - "8085:80"
restart: unless-stopped restart: unless-stopped
@@ -14,29 +12,28 @@ services:
- proxy - proxy
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.forust-homepage.loadbalancer.server.port=80" - "traefik.http.services.forust-homepage.loadbalancer.server.port=80"
# Prod Router # Prod Router
- "traefik.http.routers.forust-homepage.rule=Host(`forust.xyz`) || Host(`www.forust.xyz`)" - "traefik.http.routers.forust-homepage.rule=Host(`forust.xyz`)"
- "traefik.http.routers.forust-homepage.entrypoints=websecure" - "traefik.http.routers.forust-homepage.entrypoints=websecure"
- "traefik.http.routers.forust-homepage.priority=10" - "traefik.http.routers.forust-homepage.middlewares=security-headers@file"
- "traefik.http.routers.forust-homepage.tls.certresolver=letsencrypt" - "traefik.http.routers.forust-homepage.tls=true"
# Local Router # Local Router
- "traefik.http.routers.forust-homepage-local.rule=Host(`landing.workstation.internal`)" - "traefik.http.routers.forust-homepage-local.rule=Host(`landing.workstation.internal`)"
- "traefik.http.routers.forust-homepage-local.entrypoints=websecure" - "traefik.http.routers.forust-homepage-local.entrypoints=websecure"
- "traefik.http.routers.forust-homepage-local.priority=10" - "traefik.http.routers.forust-homepage-local.middlewares=security-headers@file"
- "traefik.http.routers.forust-homepage-local.tls=true" - "traefik.http.routers.forust-homepage-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.forust-homepage-dev.rule=Host(`landing.gigaforust.internal`)" - "traefik.http.routers.forust-homepage-dev.rule=Host(`landing.gigaforust.internal`)"
- "traefik.http.routers.forust-homepage-dev.entrypoints=websecure" - "traefik.http.routers.forust-homepage-dev.entrypoints=websecure"
- "traefik.http.routers.forust-homepage-dev.priority=10" - "traefik.http.routers.forust-homepage-dev.middlewares=security-headers@file"
- "traefik.http.routers.forust-homepage-dev.tls=true" - "traefik.http.routers.forust-homepage-dev.tls=true"
xdfnx: xdfnx:
build: build:
context: . context: .
dockerfile: Dockerfile.xdfnx dockerfile: Dockerfile.xdfnx
image: gcr.forust.xyz/forust/xdfnx-homepage:latest
pull_policy: build
restart: unless-stopped restart: unless-stopped
# ports: # ports:
# - "8086:80" # - "8086:80"
@@ -44,19 +41,23 @@ services:
- ./xdfnx_files:/usr/share/nginx/html - ./xdfnx_files:/usr/share/nginx/html
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.xdfnx-homepage.loadbalancer.server.port=80" - "traefik.http.services.xdfnx-homepage.loadbalancer.server.port=80"
# Prod Router # Prod Router
- "traefik.http.routers.xdfnx.rule=Host(`xdfnx.cfd`) || Host(`www.xdfnx.cfd`)" - "traefik.http.routers.xdfnx.rule=Host(`xdfnx.cfd`)"
- "traefik.http.routers.xdfnx.entrypoints=websecure" - "traefik.http.routers.xdfnx.entrypoints=websecure"
- "traefik.http.routers.xdfnx.tls.certresolver=letsencrypt" - "traefik.http.routers.xdfnx.middlewares=security-headers@file"
- "traefik.http.routers.xdfnx.tls=true"
# Local Router # Local Router
- "traefik.http.routers.xdfnx-local.rule=Host(`xdfnx.workstation.internal`)" - "traefik.http.routers.xdfnx-local.rule=Host(`xdfnx.workstation.internal`)"
- "traefik.http.routers.xdfnx-local.entrypoints=websecure" - "traefik.http.routers.xdfnx-local.entrypoints=websecure"
- "traefik.http.routers.xdfnx-local.middlewares=security-headers@file"
- "traefik.http.routers.xdfnx-local.tls=true" - "traefik.http.routers.xdfnx-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.xdfnx-dev.rule=Host(`xdfnx.gigaforust.internal`)" - "traefik.http.routers.xdfnx-dev.rule=Host(`xdfnx.gigaforust.internal`)"
- "traefik.http.routers.xdfnx-dev.entrypoints=websecure" - "traefik.http.routers.xdfnx-dev.entrypoints=websecure"
- "traefik.http.routers.xdfnx-dev.middlewares=security-headers@file"
- "traefik.http.routers.xdfnx-dev.tls=true" - "traefik.http.routers.xdfnx-dev.tls=true"
networks: networks:
- proxy - proxy
Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

+6 -33
View File
@@ -20,7 +20,6 @@
<hr> <hr>
<div class="grid-2">
<section id="socials"> <section id="socials">
<h2>./socials</h2> <h2>./socials</h2>
<ul class="link-list"> <ul class="link-list">
@@ -42,7 +41,7 @@
</li> </li>
<li> <li>
<i class="fas fa-envelope"></i> <i class="fas fa-envelope"></i>
<a href="mailto:contact@forust.xyz">mail/contact@forust.xyz</a> <a href="mailto:forust@forust.xyz">mail/contact@forust.xyz</a>
</li> </li>
<li> <li>
<i class="fa-solid fa-key"></i> <i class="fa-solid fa-key"></i>
@@ -54,39 +53,14 @@
</ul> </ul>
</section> </section>
<section id="tools">
<h2>./tools</h2>
<ul class="link-list">
<li>
<i class="fa fa-pie-chart"></i>
<a href="https://forust.xyz/glance" target="_blank">forust/dashboard</a>
</li>
<li>
<i class="fa fa-refresh"></i>
<a href="https://forust.xyz/convert" target="_blank">forust/converter</a>
</li>
<li>
<i class="fa-solid fa-file-pdf"></i>
<a href="https://pdf.forust.xyz" target="_blank">pdf.forust.xyz</a>
</li>
</ul>
</section>
</div>
<section id="stack"> <section id="stack">
<h2>./skills</h2> <h2>./skills_and_tools</h2>
<div class="grid-2"> <div class="grid-2">
<div> <div>
<div class="skill-item"> <div class="skill-item">
<span>ArchLinux # btw</span> <span>ArchLinux # btw</span>
<span class="level">[#######...]</span> <span class="level">[#######...]</span>
</div> </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"> <div class="skill-item">
<span>Docker Compose</span> <span class="level">[#####.....]</span> <span>Docker Compose</span> <span class="level">[#####.....]</span>
</div> </div>
@@ -96,6 +70,9 @@
<div class="skill-item"> <div class="skill-item">
<span>Burpsuite</span> <span class="level">[#####.....]</span> <span>Burpsuite</span> <span class="level">[#####.....]</span>
</div> </div>
<div class="skill-item">
<span>Docker</span> <span class="level">[####......]</span>
</div>
<div class="skill-item"> <div class="skill-item">
<span>Steganography</span> <span class="level">[####......]</span> <span>Steganography</span> <span class="level">[####......]</span>
</div> </div>
@@ -139,7 +116,7 @@
<div class="avatar" <div class="avatar"
style="background-image: url('assets/images/team/anna.jpg'); background-size: cover; background-position: center;"> style="background-image: url('assets/images/team/anna.jpg'); background-size: cover; background-position: center;">
</div> </div>
<a href="./assets/images/love.png" target="_blank">Anna~</a> <a href="" target="_blank">Anna~</a>
</div> </div>
<div class="member"> <div class="member">
@@ -180,10 +157,6 @@
<a href="https://github.com/unhappychoice/gitlogue" target="_blank">unhappychoice/gitlogue</a> <a href="https://github.com/unhappychoice/gitlogue" target="_blank">unhappychoice/gitlogue</a>
<span class="comment">// nice git log visualizer</span> <span class="comment">// nice git log visualizer</span>
</li> </li>
<li>
<a href="https://github.com/tstack/lnav" target="_blank">tstack/lnav</a>
<span class="comment">// powerful log reader</span>
</li>
<li> <li>
<a href="https://github.com/mountain-loop/yaak" target="_blank">mountain-loop/yaak</a> <a href="https://github.com/mountain-loop/yaak" target="_blank">mountain-loop/yaak</a>
<span class="comment">// modern, fancy api client</span> <span class="comment">// modern, fancy api client</span>
-81
View File
@@ -1,81 +0,0 @@
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
imagePullPolicy: Always
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
imagePullPolicy: Always
ports:
- containerPort: 80
resources:
requests:
memory: "10Mi"
cpu: "20m"
limits:
memory: "100Mi"
cpu: "50m"
-69
View File
@@ -1,69 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: forust-homepage-prod
namespace: homepages
spec:
entryPoints:
- websecure
routes:
- match: Host(`forust.xyz`) || Host(`www.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
priority: 10
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: Host(`landing.workstation.internal`) || Host(`landing.gigaforust.internal`)
kind: Rule
priority: 10
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: Host(`xdfnx.cfd`) || Host(`www.xdfnx.cfd`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
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: Host(`xdfnx.workstation.internal`) || Host(`xdfnx.gigaforust.internal`)
kind: Rule
services:
- name: xdfnx-homepage-service
port: 80
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: homepages
-54
View File
@@ -1,54 +0,0 @@
# Resolved: Overlay FS failure (and so containers)
15-12-2025 03:02 AM EET: Degraded control panels' performances, following by full cascade docker failure
15-12-2025 04:36 AM EET: Identified: Services are terminated due to server software (Overlay FS) + hardware issues (HDD).
15-12-2025 08:45 PM EET: Restored NextCloud service with few tweaks to lower I/O
---
16-12-2025 08:34 PM EET: Ordered new HDD, ETA 22nd of December - 2nd of January
---
17-12-2025 02:47 AM EET: To avoid additional I/O into kuma's database, disabled uptime monitoring for non-critical services, such as:
- Game servers
- Gitea (no public projects being hosted yet)
- Landings
- Cloud services
- PenPot
- Auth provider
- Secondary management tools
- Chernuha's non-important infrastructure
These can be identified by seeing ">2m ago" under monitor's heartbeats.
---
09-01-2026 02:32 PM EET: NextCloud's frontend files are corrupted due to the unknown issue. All user data is integrity-verified. To prevent user data corruption, NextCloud service will be restored after new hardware will be available.
---
14-01-2026 08:42 PM EET: After planned updating and restarting server, critical firmware software were corrupted because of physical degradation of the disk. Server inaccessible in any way
---
15-01-2026 11:30 AM EET: A new NAS-Grade HDD (Seagate IronWolf Pro) was ordered. ETA 16-01-2026 EET Before 12:00 PM
---
16-01-2026 12:47 AM EET: New server system is installed, data backed up. Experiencing docker memory leak.
---
17-01-2026 01:27 PM EET: All services except NextCloud and Satisfactory server are online.
17-01-2026 03:48 PM EET: Nextcloud is online. Satisfactory will be provided on-demand. Monitoring status
---
##### Status: All services are online
**Solution: moving all infrastructure onto new NAS-Grade HDD with fresh OS install**
-3
View File
@@ -1,3 +0,0 @@
KENER_SECRET_KEY=your_secret_key_here
ORIGIN=http://localhost:3000
TZ=Etc/UTC
-59
View File
@@ -1,59 +0,0 @@
services:
kener:
image: rajnandan1/kener:4.0.23
container_name: kener
restart: unless-stopped
# ports:
# - 3000:3000/tcp
environment:
- KENER_SECRET_KEY=${KENER_SECRET_KEY?Kener requires a secret key}
- ORIGIN=${ORIGIN:-http://localhost:3000}
- REDIS_URL=redis://redis:6379
- TZ:${TZ:-Etc/UTC}
depends_on:
redis:
condition: service_healthy
volumes:
- db:/app/database
- uploads:/app/uploads
labels:
- "traefik.enable=true"
- "traefik.http.services.kener.loadbalancer.server.port=3000"
# Prod Router
- "traefik.http.routers.kener.rule=Host(`status.forust.xyz`)"
- "traefik.http.routers.kener.entrypoints=websecure"
- "traefik.http.routers.kener.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.kener-local.rule=Host(`status.workstation.internal`)"
- "traefik.http.routers.kener-local.entrypoints=websecure"
- "traefik.http.routers.kener-local.tls=true"
# Dev Router
- "traefik.http.routers.kener-dev.rule=Host(`status.gigaforust.internal`)"
- "traefik.http.routers.kener-dev.entrypoints=websecure"
- "traefik.http.routers.kener-dev.tls=true"
networks:
- proxy
- kener
redis:
image: redis:7-alpine
container_name: kener-redis
restart: unless-stopped
volumes:
- redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 6s
timeout: 5s
retries: 5
networks:
- kener
volumes:
db:
uploads:
redis:
networks:
proxy:
external: true
kener:
external: false
-9
View File
@@ -1,9 +0,0 @@
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"
-33
View File
@@ -1,33 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: kener-prod
namespace: kener
spec:
entryPoints:
- websecure
routes:
- match: Host(`status.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
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: Host(`status.workstation.internal`) || Host(`status.gigaforust.internal`)
kind: Rule
services:
- name: kener-service
port: 3000
Loaded 100 of 285 files, more files were not shown because too many files have changed in this diff. Show more