Compare commits

..

92 Commits

Author SHA1 Message Date
forust ace23ad1f9 fix: remove www.xdfnx.cfd from ingress, add Gitea access log config
ci / lint-prettier (push) Successful in 13s
ci / lint-ruff (push) Successful in 7s
ci / lint-yaml (push) Successful in 17s
ci / lint-dockerfiles (push) Successful in 14s
ci / validate (push) Successful in 15s
ci / build (push) Successful in 26s
2026-07-20 11:40:41 +02:00
forust 92aa731e44 deleted crowdsec stack from the repo. will figure something else
ci / lint-prettier (push) Successful in 18s
ci / lint-ruff (push) Successful in 6s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 6s
ci / build (push) Successful in 43s
Signed-off-by: mr-forust <vzlomdsisma@gmail.com>
2026-07-19 23:16:14 +02:00
forust 87ca3fd40c chore: updatet chernuha's pfp, added projects sections for forust.xyz
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 3s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 6s
ci / validate (push) Successful in 7s
ci / build (push) Successful in 18s
2026-07-05 02:59:31 +02:00
forust 82bcd30ed8 updated xdfnx's page
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 11s
ci / build (push) Successful in 19s
2026-07-04 01:01:05 +02:00
forust 620262d98c ci: fetch full history for change detection after rebase
ci / lint-prettier (push) Successful in 9s
ci / lint-ruff (push) Successful in 6s
ci / lint-yaml (push) Successful in 9s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 3s
2026-07-04 00:55:46 +02:00
forust 831f3a46b0 updated xdfnx's page
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 3s
2026-07-04 00:46:13 +02:00
forust f7902e74e8 ci: require lint and validate before build
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 3s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 2s
2026-06-30 01:23:53 +02:00
forust eb8d1b361e ci: add branch tags to docker builds
ci / lint (push) Successful in 15s
ci / validate (push) Successful in 8s
ci / build (push) Successful in 3s
2026-06-30 01:20:51 +02:00
forust 6e2cafb206 ci: merge lint validate and docker builds
ci / lint (push) Successful in 14s
ci / validate (push) Successful in 19s
ci / build (push) Successful in 2s
2026-06-30 01:17:31 +02:00
forust 67b0c0824f ci: restore docker-based lint and validate jobs
lint / prettier (push) Successful in 7s
lint / ruff (push) Successful in 3s
lint / yamllint (push) Successful in 5s
lint / hadolint (push) Successful in 4s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 4s
2026-06-30 01:12:23 +02:00
forust 8e72e0a920 ci: run lint and validate tools locally
lint / prettier (push) Failing after 2s
lint / ruff (push) Successful in 2s
lint / yamllint (push) Successful in 3s
lint / hadolint (push) Failing after 2s
validate / yaml (push) Successful in 2s
validate / k8s (push) Failing after 1s
2026-06-30 00:14:14 +02:00
forust 73a1132beb Align Traefik Helm log values with chart v41
lint / prettier (push) Successful in 1m59s
lint / ruff (push) Successful in 4s
lint / yamllint (push) Successful in 5s
lint / hadolint (push) Successful in 4s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 3s
2026-06-29 23:02:26 +02:00
forust a128523c24 Fix CrowdSec middleware references in Traefik ingresses 2026-06-29 22:47:21 +02:00
forust ee881acd0e refactor: update xdfnx homepage index.html
lint / prettier (push) Successful in 14s
lint / ruff (push) Successful in 5s
lint / yamllint (push) Successful in 9s
lint / hadolint (push) Successful in 17s
validate / yaml (push) Successful in 8s
validate / k8s (push) Successful in 7s
2026-06-28 11:59:57 +02:00
forust bacb2f4b9f fix: correct Traefik rule syntax for local IngressRoutes
Move parentheses outside Host() calls so that || and && operators
are properly grouped in Traefik rule expressions.
2026-06-28 11:59:52 +02:00
forust 91211e7b78 fix: resolve CrowdSec Helm upgrade failure - remove duplicate DISABLE_ONLINE_API env and add metrics config 2026-06-28 11:59:46 +02:00
forust 9b3a7aadb4 fix: resolve pyrogram imports by adding venv and pyright config
lint / prettier (push) Successful in 7s
lint / ruff (push) Successful in 4s
lint / yamllint (push) Successful in 6s
lint / hadolint (push) Successful in 4s
validate / yaml (push) Successful in 5s
validate / k8s (push) Successful in 5s
- Create .venv with pyrofork and all dependencies installed
- Add pyrightconfig.json at workspace root and in userbot/
- Enable pyright as language server for Python in Zed settings
- Update uv.lock with resolved dependency tree
2026-06-21 22:33:04 +02:00
forust b123621ead chore: remove github obsolete prod deploy workflow
lint / prettier (push) Successful in 7s
lint / ruff (push) Successful in 4s
lint / yamllint (push) Successful in 6s
lint / hadolint (push) Successful in 4s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 4s
2026-06-21 22:24:30 +02:00
forust a2df8504f5 Fix DL3013: pin pip version in webinar-checker Dockerfile
lint / prettier (push) Successful in 8s
lint / ruff (push) Successful in 4s
lint / yamllint (push) Successful in 6s
lint / hadolint (push) Successful in 4s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 4s
2026-06-21 22:07:44 +02:00
forust fb43306571 Fix all lint issues: Dockerfiles (DL3015/DL3013/DL4006) + Ruff (173→0 errors)
lint / prettier (push) Successful in 8s
lint / ruff (push) Successful in 5s
lint / yamllint (push) Successful in 7s
lint / hadolint (push) Failing after 4s
validate / yaml (push) Successful in 5s
validate / k8s (push) Successful in 5s
Dockerfile fixes:
- edu_master/phpsessid-bot: add --no-install-recommends, pin pip versions
- edu_master/webinar-checker: pin pip versions with --no-cache-dir
- userbot: add SHELL with pipefail for pipe operations

Ruff fixes (173 → 0):
- W293/W291/W292: whitespace clean via ruff format
- N806: camelCase → snake_case (anilist, safone, hearts, flux, etc.)
- ARG001/ARG002: prefix unused params with _
- SIM115: use context managers for file I/O
- SIM117: combine nested with statements
- S608: noqa on SQL f-strings (module name is validated)
- E402/N812/N817: import fixes
- B023: pass loop variable as argument
- I001: auto-sorted imports
- syntax: fixed = vs == in dtek_notif/main.py
2026-06-21 22:01:51 +02:00
forust f424d91405 Tighten lint workflow scope
lint / prettier (push) Successful in 8s
lint / ruff (push) Failing after 5s
lint / yamllint (push) Successful in 6s
lint / hadolint (push) Failing after 4s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 4s
2026-06-21 21:51:20 +02:00
forust 88a8f2987f Unify workflow job naming
lint / prettier (push) Failing after 9s
lint / ruff (push) Failing after 5s
lint / yamllint (push) Successful in 7s
lint / hadolint (push) Failing after 13s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 5s
2026-06-21 21:46:22 +02:00
forust 17027b232b Rename workflows to yaml 2026-06-21 21:45:16 +02:00
forust 6ecbbb39b4 Fix yamllint workflow invocation
validate / yaml (push) Successful in 7s
validate / k8s (push) Successful in 5s
2026-06-21 21:40:11 +02:00
forust 175cbc8860 Fix validation workflows for self-hosted runner
validate / yaml (push) Failing after 15s
validate / k8s (push) Successful in 9s
2026-06-21 21:37:30 +02:00
forust 6363d050b0 Add YAML validation workflows 2026-06-21 21:27:31 +02:00
forust c855764bc6 feat: add vaultwarden deployment config (compose + k8s)
Deploy to Server / deploy (push) Failing after 1s
2026-06-21 01:02:09 +02:00
forust 7d92b85e21 Merge commit '4355f451d4b4288d43468e08cad1f377e511f98a'
Deploy to Server / deploy (push) Has been cancelled
2026-06-19 23:23:28 +02:00
forust 9364392bc0 Merge commit '3eaef5dc90b716cc0fa391cbe2394be56d5f6041' as 'userbot'
Deploy to Server / deploy (push) Has been cancelled
2026-06-19 23:20:23 +02:00
forust 4355f451d4 Merge commit '3eaef5dc90b716cc0fa391cbe2394be56d5f6041' as 'userbot' 2026-06-19 23:20:23 +02:00
forust 3eaef5dc90 Squashed 'userbot/' content from commit 7fb0a0e
git-subtree-dir: userbot
git-subtree-split: 7fb0a0e179
2026-06-19 23:20:23 +02:00
forust 69ffd3682e refactor: userbot to subtree 2026-06-19 23:20:13 +02:00
forust 1930600c40 Revert "refactor: extract userbot to standalone repo, add as git submodule"
This reverts commit 3c383db9a7.
2026-06-19 23:11:27 +02:00
forust d74a705d53 chore(k8s): rewritten ingressroute to include headplane AND headscale-admin ui
Deploy to Server / deploy (push) Has been cancelled
new routes groupping style
2026-06-19 23:02:22 +02:00
forust 3c383db9a7 refactor: extract userbot to standalone repo, add as git submodule
Deploy to Server / deploy (push) Has been cancelled
userbot now lives at ssh://git@gitssh.forust.xyz:2221/forust/userbot.git
and is included in homelab as a submodule at userbot/
2026-06-19 15:39:00 +02:00
forust 7fb0a0e179 chore: batch lint fixes across userbot and edu_master
- S113: Add timeout=10 to all requests calls (74 fixes)
- E722: Replace bare except: with except Exception:
- B904: Replace redundant re-raise with bare raise
- E402: Add noqa for intentional late imports after import_library()
- S102/S307/S310/S311/S603/S605/S606/S607/S108: Add noqa for intentional usage
- F601: Fix duplicate dict key in unsplash.py
- N802: Rename ReplyCheck -> reply_check with backward compat alias
- N813: Rename bs -> BS in icons.py
- B007/B020: Rename loop var _j in animations.py
- SIM102: Collapse nested if in autofwd.py
- SIM113: Use enumerate() in calculator.py
- A002: Add noqa for builtin shadowing in admlist.py
- F811: Add noqa for cohere redefinition
- edu_master: Fix ARG001, S108, S110, SIM117, apply --unsafe-fixes
- Add modules_list.txt with full module inventory
2026-06-19 15:36:25 +02:00
forust 227e5fda27 chore: batch lint fixes across userbot and edu_master
- S113: Add timeout=10 to all requests calls (74 fixes)
- E722: Replace bare except: with except Exception:
- B904: Replace redundant re-raise with bare raise
- E402: Add noqa for intentional late imports after import_library()
- S102/S307/S310/S311/S603/S605/S606/S607/S108: Add noqa for intentional usage
- F601: Fix duplicate dict key in unsplash.py
- N802: Rename ReplyCheck -> reply_check with backward compat alias
- N813: Rename bs -> BS in icons.py
- B007/B020: Rename loop var _j in animations.py
- SIM102: Collapse nested if in autofwd.py
- SIM113: Use enumerate() in calculator.py
- A002: Add noqa for builtin shadowing in admlist.py
- F811: Add noqa for cohere redefinition
- edu_master: Fix ARG001, S108, S110, SIM117, apply --unsafe-fixes
- Add modules_list.txt with full module inventory
2026-06-19 15:36:25 +02:00
forust 20bce5b31c fix(userbot): add missing safone.py imports, apply ruff --unsafe-fixes
- Add missing aiohttp, PIL, BytesIO imports to safone.py (F821 runtime bugs)
- Apply ruff --unsafe-fixes (27 fixes): ternary operators, .get() patterns,
  contextlib.suppress, enumerate(), collapsible if/else, remove .keys()
2026-06-19 15:27:12 +02:00
forust 70d7855f06 fix(userbot): add missing safone.py imports, apply ruff --unsafe-fixes
- Add missing aiohttp, PIL, BytesIO imports to safone.py (F821 runtime bugs)
- Apply ruff --unsafe-fixes (27 fixes): ternary operators, .get() patterns,
  contextlib.suppress, enumerate(), collapsible if/else, remove .keys()
2026-06-19 15:27:12 +02:00
forust c905bbd039 chore(userbot): optimize Dockerfile with multi-stage build and static ffmpeg
- Multi-stage build: pip deps built in separate stage
- Static ffmpeg binary instead of apt package (avoid 200+ deps)
- Keep only git, mediainfo, wget via apt
2026-06-19 14:56:37 +02:00
forust fc83176522 chore(userbot): optimize Dockerfile with multi-stage build and static ffmpeg
Deploy to Server / deploy (push) Has been cancelled
- Multi-stage build: pip deps built in separate stage
- Static ffmpeg binary instead of apt package (avoid 200+ deps)
- Keep only git, mediainfo, wget via apt
2026-06-19 14:56:37 +02:00
forust 7ba6bc44f2 chore(userbot): apply ruff check --fix and ruff format
- ruff check --fix: 210 auto-fixed errors (import sorting, trailing
  whitespace, unused imports, f-string fixups, deprecated annotations)
- ruff format: 104 files reformatted to consistent style
- 268 non-auto-fixable issues remain (S113 requests timeout, etc.)
2026-06-19 12:19:01 +02:00
forust 0506aaaac8 chore(userbot): apply ruff check --fix and ruff format
- ruff check --fix: 210 auto-fixed errors (import sorting, trailing
  whitespace, unused imports, f-string fixups, deprecated annotations)
- ruff format: 104 files reformatted to consistent style
- 268 non-auto-fixable issues remain (S113 requests timeout, etc.)
2026-06-19 12:19:01 +02:00
forust bd9724da69 Revert "chore: switch yaml formatter to prettier, disable yaml-language-server validation (yamllint covers it)"
This reverts commit 3bad433f1a.
2026-06-19 12:15:14 +02:00
forust 3bad433f1a chore: switch yaml formatter to prettier, disable yaml-language-server validation (yamllint covers it) 2026-06-19 12:11:58 +02:00
forust 2bd7a5176f Revert "chore: disable yaml-language-server formatting (handled by prettier), set yamlVersion 1.2"
This reverts commit a9ff01261b.
2026-06-19 12:08:42 +02:00
forust a9ff01261b chore: disable yaml-language-server formatting (handled by prettier), set yamlVersion 1.2 2026-06-19 12:06:16 +02:00
forust 95cec59263 chore(userbot): apply prettier formatting across manifests 2026-06-19 12:03:13 +02:00
forust 1362ebc3c2 chore(userbot): apply prettier formatting across manifests 2026-06-19 12:03:13 +02:00
forust 2de6131ba7 chore: apply prettier formatting across compose files and configs 2026-06-19 12:03:11 +02:00
forust 1762962f32 chore(k8s): fix indentation in ingress manifests (3-space -> 2-space) 2026-06-19 12:03:02 +02:00
forust 7fb9e46c05 chore: remove singleQuote from prettier config to preserve original quotes 2026-06-19 12:02:59 +02:00
forust b33488342a chore: add truthy allowed-values to yamllint config 2026-06-19 12:01:11 +02:00
forust d53b14b1de chore: apply yaml lint fixes across compose files
- Fix trailing whitespace in compose files
- Add missing final newlines (EOF)
- Fix indentation in dockmon (3-space -> 2-space) and glance monitor.yml
- Align comments consistently
2026-06-19 11:57:14 +02:00
forust a6a6d933da chore: add linter configs (editorconfig, hadolint, markdownlint, prettier, yamllint, ruff, zed) 2026-06-19 11:57:04 +02:00
forust 0803f3efff chore(k8s): returned to Host || Host standart instead of regexp.
Deploy to Server / deploy (push) Has been cancelled
Yaml lint (yamllint)
2026-06-18 21:02:40 +02:00
forust ec0420962b hotfix: update headscale config for v0.29.0 breaking changes
- ephemeral_node_inactivity_timeout → node.ephemeral.inactivity_timeout
- randomize_client_port → randomizeClientPort in policy file
2026-06-18 14:26:58 +02:00
forust b407202e53 chore(k8s): imagepullpolicy always for homepages
Deploy to Server / deploy (push) Has been cancelled
tools column on the forust.xyz landing
2026-06-17 01:53:00 +02:00
forust b9b8474455 feat(k8s): protect all prod routers with crowdsec middleware 2026-06-17 01:50:33 +02:00
forust 76853637bc feat: traefik prometheus metrics 2026-06-17 01:41:45 +02:00
forust dac3777fc4 fix: authentik k8s url 2026-06-17 01:41:13 +02:00
forust bb5a3697f2 feat: bentopdf k8s manifests 2026-06-16 13:35:03 +02:00
forust e73aacb900 feat: add bentopdf pdf suite to converters stack 2026-06-16 12:36:31 +02:00
forust ea483da645 feat: kube-prometeus-stack 2026-06-16 12:36:31 +02:00
forust 85d35f86a7 feat: switch adguard dns to a dedicated metallb IP 2026-06-16 12:36:31 +02:00
forust 3d03ab1ea4 fix: priority for homepage's router 2026-06-16 12:36:26 +02:00
forust 4ca3ccdad3 chore(k8s): router rewrite
- returned to Host matcher instead of Hostregexp
- switched dockercompose labels to letsencrypt
- renamed DoH route
2026-06-16 12:34:15 +02:00
forust 10e26cda72 feat: crowdsec
- moved bouncer tokens to secrets
- experimental host ssh log parsing
- moved crowdsec to it's own directory
2026-06-16 00:23:29 +02:00
forust c648dfd147 chore(k8s): renamed gitea ingressroute to ingress
Deploy to Server / deploy (push) Has been cancelled
2026-06-14 23:24:24 +02:00
forust 2f97821dc6 feat: crowdsec lapi helm
Deploy to Server / deploy (push) Has been cancelled
2026-06-14 23:21:37 +02:00
forust 3d78b90f3a updated kener to v4.1.0 2026-06-14 23:02:35 +02:00
forust 3dc8228e22 matched dns record and the searxng's route 2026-06-14 23:01:58 +02:00
forust 93171ad8e6 fixed and tweaked glance app 2026-06-14 23:00:29 +02:00
forust dca7ad0902 fix: race condition convertx and homepage
typo in glance stripprefix
glance placed at /glance
2026-06-14 22:48:50 +02:00
forust 20b8c93275 chore(k8s): make dockmon statefulset
+ adjusted userbot sys reqs
2026-06-10 19:40:45 +02:00
forust bb821e138a chore(k8): adjusted system resources requests and limits based on manual monitoring 2026-06-10 19:37:16 +02:00
forust b7854447af lint: yaml spaces and tabs 2026-06-09 12:59:36 +02:00
forust 444bb97f8e feat: add userbot k8s deployment method
- Kustomize: base + overlays/dev + overlays/prod
2026-06-07 19:41:28 +02:00
forust 4f01cdac31 fix: removed git checkout (was destructive)
- Remove git init/fetch/checkout from utils/misc.py
- Hardcode userbot_version to 2.5.0
2026-06-07 19:40:52 +02:00
forust cb40b10ecf chore: add gitea container registry compose support for localy builded apps 2026-06-07 14:37:57 +02:00
forust bed58c84ef refactor: update .dockerignore
pull_policy never to use local images
2026-05-25 01:43:46 +02:00
forust 56e5d79e3e refactor: improved error handling, timeouts and use temp files 2026-05-21 22:14:29 +02:00
forust cd0ce06246 refactor: imporved layer caching for dockerfile
using existing built image for account 2
2026-05-21 22:12:33 +02:00
forust a699ceb935 refactor: userbots' compose-files cleanup 2025-12-09 21:45:24 +01:00
forust ce66a546f1 chore: update gitignore, add translations 2025-11-27 18:58:17 +01:00
forust a30bda4940 Renamed userbot's dockercompose for easy access 2025-11-13 04:00:23 +01:00
forust b722467991 Remove unnecessary network and development configurations from userbot Docker Compose file 2025-11-13 03:48:50 +01:00
forust 5f8fd05266 Add userbot Docker Compose configuration for userbot_forust and userbot_anna services 2025-11-13 00:17:26 +01:00
forust 1c7afe5bb3 Move userbot Docker Compose configuration for forust and anna services 2025-11-11 01:57:44 +01:00
forust 4ff80c07b0 deleting that install shit 2025-11-11 01:41:24 +01:00
forust 3a5652daa7 userbot/install.sh, start 2025-11-11 01:39:53 +01:00
forust 4e18cd0eb3 init, .gitignore 2025-11-11 00:02:49 +01:00
214 changed files with 8570 additions and 8178 deletions
+191
View File
@@ -0,0 +1,191 @@
# Инструкция: Анализ хранилища Kubernetes и настройка NFS
## Цель
Проанализировать текущую конфигурацию хранилища Kubernetes и подготовить план внедрения NFS StorageClass для сохранения данных при удалении namespace.
## 1. Собрать информацию о кластере
### 1.1. Версия Kubernetes и тип дистрибутива
```bash
kubectl version --short
# или
kubectl version
```
Определить, используется ли k3s, k8s, microk8s и т.д.:
```bash
# Проверить наличие k3s
which k3s
# Проверить процесс
ps aux | grep -E 'kube|k3s'
```
### 1.2. StorageClass
```bash
kubectl get storageclass -o wide
```
Запомнить:
- `PROVISIONER` — какой драйвер используется
- `RECLAIMPOLICY` — Delete или Retain
- Какой StorageClass помечен как `(default)`
### 1.3. Существующие PV и PVC
```bash
kubectl get pv -o wide
kubectl get pvc --all-namespaces
```
Посмотреть, какие PVC привязаны к каким PV, и какой reclaimPolicy у PV.
### 1.4. Нода и диски
```bash
# Список нод
kubectl get nodes -o wide
# На каждой ноде (через ssh или локально):
lsblk
df -h
cat /etc/fstab
```
Определить:
- Есть ли отдельный раздел/диск для данных
- Куда смонтированы разделы
- Сколько свободного места
- Есть ли монтирование NTFS-разделов (как `/media/forust/Programs`)
### 1.5. Где local-path хранит данные (для k3s)
```bash
ls -la /var/lib/rancher/k3s/storage/ 2>/dev/null
# или для microk8s
ls -la /var/snap/microk8s/common/ 2>/dev/null
```
## 2. Анализ: сохраняются ли данные при удалении namespace?
| Сценарий | Результат |
|---|---|
| `kubectl delete ns <ns>` | Все PVC в namespace удаляются |
| PVC → PV c `reclaimPolicy: Delete` | PV и данные удалены |
| PVC → PV c `reclaimPolicy: Retain` | PV остаётся (статус Released), данные целы |
**Вывод:** Если reclaimPolicy в StorageClass = `Delete`, то данные **пропадут**. Если `Retain` — сохранятся.
## 3. План внедрения NFS
### 3.1. Проверить, установлен ли NFS
```bash
which nfsstat exportfs mount.nfs
systemctl status nfs-server 2>/dev/null || systemctl status nfs-kernel-server 2>/dev/null
```
### 3.2. Выбрать директорию для NFS-экспорта
Варианты (выбрать подходящий):
- `/var/lib/k8s-nfs/` — на корневом разделе
- `<путь к отдельному разделу>/k8s-nfs/` — если есть отдельный диск/раздел
- Не рекомендуется использовать NTFS-раздел (проблемы с правами и производительностью)
Требования:
- Файловая система: ext4 или xfs (не ntfs!)
- Достаточно свободного места
- Права: `755`, владелец root
### 3.3. Установить NFS-сервер
```bash
# Debian/Ubuntu
apt update && apt install -y nfs-kernel-server
# RHEL/Fedora
dnf install -y nfs-utils
```
### 3.4. Настроить экспорт
Создать директорию:
```bash
mkdir -p /var/lib/k8s-nfs
chmod 755 /var/lib/k8s-nfs
```
Добавить в `/etc/exports`:
```
/var/lib/k8s-nfs *(rw,sync,no_subtree_check,no_root_squash)
```
Применить:
```bash
exportfs -rav
```
Проверить:
```bash
showmount -e localhost
```
### 3.5. Выбрать способ интеграции с Kubernetes
#### Вариант A: nfs-subdir-external-provisioner (проще)
```bash
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm install nfs-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--namespace kube-system \
--set nfs.server=127.0.0.1 \
--set nfs.path=/var/lib/k8s-nfs \
--set storageClass.name=nfs \
--set storageClass.defaultClass=false \
--set storageClass.reclaimPolicy=Retain
```
#### Вариант B: NFS CSI Driver
```bash
helm repo add csi-driver-nfs https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts
helm install csi-driver-nfs csi-driver-nfs/csi-driver-nfs --namespace kube-system
```
После установки CSI драйвера создать StorageClass:
```yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs
provisioner: nfs.csi.k8s.io
parameters:
server: 127.0.0.1
share: /var/lib/k8s-nfs
reclaimPolicy: Retain
volumeBindingMode: Immediate
```
### 3.6. Проверить результат
```bash
kubectl get storageclass
kubectl get pods -n kube-system | grep -E 'nfs|provisioner'
```
## 4. Итоговая конфигурация
После внедрения в кластере будет два StorageClass:
| Имя | Provisioner | ReclaimPolicy | Назначение |
|---|---|---|---|
| `local-path` (default) | rancher.io/local-path | Delete | Временные данные, stateless |
| `nfs` | nfs-subdir-external-provisioner или nfs.csi.k8s.io | Retain | Данные, которые нужно сохранять |
**Главное преимущество:** PVC c `storageClassName: nfs` при удалении namespace сохраняют данные на диске, так как NFS-провизор использует `reclaimPolicy: Retain` или файлы физически остаются в NFS-экспорте.
## 5. Ответы на частые вопросы
**В:** Не упадёт ли local-path при установке NFS?
**О:** Нет, они независимы. local-path продолжает работать как обычно.
**В:** Данные NFS и local-path будут на одном диске?
**О:** Да, можно настроить оба на одном разделе, в разных каталогах.
**В:** Что если у меня несколько нод?
**О:** NFS сервер нужно поднять на одной ноде, а с других нод должна быть доступна шари. Для multi-node лучше использовать отдельный сервер или distributed storage (Longhorn, Rook/Ceph).
**В:** Можно ли использовать существующий NTFS-раздел для NFS?
**О:** Не рекомендуется — NTFS не поддерживает права Linux (no_root_squash не сработает корректно), возможны проблемы с блокировками и производительностью.
+24
View File
@@ -0,0 +1,24 @@
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
+326
View File
@@ -0,0 +1,326 @@
name: ci
on:
push:
branches:
- "**"
pull_request:
workflow_dispatch:
env:
REGISTRY: gcr.forust.xyz
jobs:
lint-prettier:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check formatting with Prettier
shell: bash
run: |
mapfile -t prettier_files < <(
git ls-files \
| grep -E '\.(md|json|ya?ml|html|css)$' \
| grep -Ev '^(\.docs/|\.zed/|errorpages/html/|homepages/(forust_files|xdfnx_files)/)'
)
if [ "${#prettier_files[@]}" -eq 0 ]; then
echo "No Prettier-managed files found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
node:22-alpine \
sh -lc 'npx --yes prettier@3 --check --ignore-unknown "$@"' sh "${prettier_files[@]}"
lint-ruff:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint Python with Ruff
shell: bash
run: |
docker run --rm \
-v "$PWD:/work" \
-w /work \
ghcr.io/astral-sh/ruff:latest \
check .
lint-yaml:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint YAML syntax
shell: bash
run: |
docker run --rm \
-v "$PWD:/work" \
-w /work \
cytopia/yamllint:latest \
-c .yamllint .
lint-dockerfiles:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint Dockerfiles
shell: bash
run: |
mapfile -t dockerfiles < <(
git ls-files ':(glob)**/Dockerfile' ':(glob)**/Dockerfile.*'
)
if [ "${#dockerfiles[@]}" -eq 0 ]; then
echo "No Dockerfiles found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
--entrypoint hadolint \
hadolint/hadolint:latest-debian \
-c .hadolint.yaml "${dockerfiles[@]}"
validate:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Validate Kubernetes manifests
shell: bash
run: |
mapfile -t manifests < <(
git ls-files ':(glob)**/k8s/**/*.yaml' ':(glob)**/k8s/**/*.yml' \
| grep -Ev '(^|/)(kustomization\.ya?ml|.*\.example\.ya?ml|.*values\.ya?ml|patch-.*\.ya?ml)$'
)
if [ "${#manifests[@]}" -eq 0 ]; then
echo "No Kubernetes manifests found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
ghcr.io/yannh/kubeconform:latest \
-strict \
-ignore-missing-schemas \
-summary \
"${manifests[@]}"
build:
needs: [lint-prettier, lint-ruff, lint-yaml, lint-dockerfiles, validate]
if: github.event_name != 'pull_request' && (github.ref_name == 'main' || github.ref_name == 'dev')
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect changed docker-built services
id: services
shell: bash
run: |
base="${{ github.event.before }}"
if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ]; then
base="$(git rev-list --max-parents=0 HEAD)"
fi
mapfile -t changed_files < <(git diff --name-only "$base" "${GITHUB_SHA}")
services=()
add_service() {
local name="$1"
local seen=0
for existing in "${services[@]}"; do
if [ "$existing" = "$name" ]; then
seen=1
break
fi
done
if [ "$seen" -eq 0 ]; then
services+=("$name")
fi
}
for file in "${changed_files[@]}"; do
case "$file" in
dtek_notif/*)
add_service dtek_notif
;;
errorpages/*)
add_service errorpages
;;
userbot/*)
add_service userbot
;;
homepages/*)
add_service homepages
;;
edu_master/phpsessid-bot/*|edu_master/webinar-checker/*|edu_master/compose.yaml)
add_service edu_master
;;
esac
done
if [ "${#services[@]}" -eq 0 ]; then
echo "No docker-built services changed."
echo "services=" >> "$GITHUB_OUTPUT"
exit 0
fi
printf '%s\n' "${services[@]}" | tee /tmp/services.txt
echo "services=$(paste -sd, /tmp/services.txt)" >> "$GITHUB_OUTPUT"
- name: Log in to registry
if: steps.services.outputs.services != ''
shell: bash
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login "${REGISTRY}" \
-u "${{ secrets.REGISTRY_USERNAME }}" \
--password-stdin
- name: Build and push changed images
if: steps.services.outputs.services != ''
shell: bash
run: |
IFS=, read -r -a services <<< "${{ steps.services.outputs.services }}"
for service in "${services[@]}"; do
case "$service" in
dtek_notif)
image="${REGISTRY}/forust/dtek-notif"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" dtek_notif
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
errorpages)
image="${REGISTRY}/forust/error-pages"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" errorpages
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
userbot)
image="${REGISTRY}/forust/userbot"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" userbot
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
homepages)
for service in forust xdfnx; do
case "$service" in
forust)
image="${REGISTRY}/forust/forust-homepage"
;;
xdfnx)
image="${REGISTRY}/forust/xdfnx-homepage"
;;
esac
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" -f "homepages/Dockerfile.${service}" homepages
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
done
;;
edu_master)
for service in session-keeper webinar-checker; do
case "$service" in
session-keeper)
context="edu_master/phpsessid-bot"
image="${REGISTRY}/forust/session-keeper"
;;
webinar-checker)
context="edu_master/webinar-checker"
image="${REGISTRY}/forust/webinar-checker"
;;
esac
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" "$context"
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
done
;;
esac
done
-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
+326
View File
@@ -0,0 +1,326 @@
name: ci
on:
push:
branches:
- "**"
pull_request:
workflow_dispatch:
env:
REGISTRY: gcr.forust.xyz
jobs:
lint-prettier:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check formatting with Prettier
shell: bash
run: |
mapfile -t prettier_files < <(
git ls-files \
| grep -E '\.(md|json|ya?ml|html|css)$' \
| grep -Ev '^(\.docs/|\.zed/|errorpages/html/|homepages/(forust_files|xdfnx_files)/)'
)
if [ "${#prettier_files[@]}" -eq 0 ]; then
echo "No Prettier-managed files found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
node:22-alpine \
sh -lc 'npx --yes prettier@3 --check --ignore-unknown "$@"' sh "${prettier_files[@]}"
lint-ruff:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint Python with Ruff
shell: bash
run: |
docker run --rm \
-v "$PWD:/work" \
-w /work \
ghcr.io/astral-sh/ruff:latest \
check .
lint-yaml:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint YAML syntax
shell: bash
run: |
docker run --rm \
-v "$PWD:/work" \
-w /work \
cytopia/yamllint:latest \
-c .yamllint .
lint-dockerfiles:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint Dockerfiles
shell: bash
run: |
mapfile -t dockerfiles < <(
git ls-files ':(glob)**/Dockerfile' ':(glob)**/Dockerfile.*'
)
if [ "${#dockerfiles[@]}" -eq 0 ]; then
echo "No Dockerfiles found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
--entrypoint hadolint \
hadolint/hadolint:latest-debian \
-c .hadolint.yaml "${dockerfiles[@]}"
validate:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Validate Kubernetes manifests
shell: bash
run: |
mapfile -t manifests < <(
git ls-files ':(glob)**/k8s/**/*.yaml' ':(glob)**/k8s/**/*.yml' \
| grep -Ev '(^|/)(kustomization\.ya?ml|.*\.example\.ya?ml|.*values\.ya?ml|patch-.*\.ya?ml)$'
)
if [ "${#manifests[@]}" -eq 0 ]; then
echo "No Kubernetes manifests found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
ghcr.io/yannh/kubeconform:latest \
-strict \
-ignore-missing-schemas \
-summary \
"${manifests[@]}"
build:
needs: [lint-prettier, lint-ruff, lint-yaml, lint-dockerfiles, validate]
if: github.event_name != 'pull_request' && (github.ref_name == 'main' || github.ref_name == 'dev')
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect changed docker-built services
id: services
shell: bash
run: |
base="${{ github.event.before }}"
if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ]; then
base="$(git rev-list --max-parents=0 HEAD)"
fi
mapfile -t changed_files < <(git diff --name-only "$base" "${GITHUB_SHA}")
services=()
add_service() {
local name="$1"
local seen=0
for existing in "${services[@]}"; do
if [ "$existing" = "$name" ]; then
seen=1
break
fi
done
if [ "$seen" -eq 0 ]; then
services+=("$name")
fi
}
for file in "${changed_files[@]}"; do
case "$file" in
dtek_notif/*)
add_service dtek_notif
;;
errorpages/*)
add_service errorpages
;;
userbot/*)
add_service userbot
;;
homepages/*)
add_service homepages
;;
edu_master/phpsessid-bot/*|edu_master/webinar-checker/*|edu_master/compose.yaml)
add_service edu_master
;;
esac
done
if [ "${#services[@]}" -eq 0 ]; then
echo "No docker-built services changed."
echo "services=" >> "$GITHUB_OUTPUT"
exit 0
fi
printf '%s\n' "${services[@]}" | tee /tmp/services.txt
echo "services=$(paste -sd, /tmp/services.txt)" >> "$GITHUB_OUTPUT"
- name: Log in to registry
if: steps.services.outputs.services != ''
shell: bash
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login "${REGISTRY}" \
-u "${{ secrets.REGISTRY_USERNAME }}" \
--password-stdin
- name: Build and push changed images
if: steps.services.outputs.services != ''
shell: bash
run: |
IFS=, read -r -a services <<< "${{ steps.services.outputs.services }}"
for service in "${services[@]}"; do
case "$service" in
dtek_notif)
image="${REGISTRY}/forust/dtek-notif"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" dtek_notif
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
errorpages)
image="${REGISTRY}/forust/error-pages"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" errorpages
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
userbot)
image="${REGISTRY}/forust/userbot"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" userbot
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
homepages)
for service in forust xdfnx; do
case "$service" in
forust)
image="${REGISTRY}/forust/forust-homepage"
;;
xdfnx)
image="${REGISTRY}/forust/xdfnx-homepage"
;;
esac
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" -f "homepages/Dockerfile.${service}" homepages
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
done
;;
edu_master)
for service in session-keeper webinar-checker; do
case "$service" in
session-keeper)
context="edu_master/phpsessid-bot"
image="${REGISTRY}/forust/session-keeper"
;;
webinar-checker)
context="edu_master/webinar-checker"
image="${REGISTRY}/forust/webinar-checker"
;;
esac
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" "$context"
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
done
;;
esac
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
+2 -1
View File
@@ -40,7 +40,7 @@ traefik/letsencrypt/acme.json
traefik/dynamic/fileservers.yml
traefik/dynamic/*.local.y*ml.*
traefik/dynamic/*.external.y*ml
traefik/k8s/fileservers.y*ml
traefik/logs/*
@@ -104,4 +104,5 @@ temp/*
*/k8s/*secret*
!*/k8s/*secret*.example
traefik/k8s/local-tls.yaml
converters/k8s/config.yaml
convertx/k8s/config.yaml
+10
View File
@@ -0,0 +1,10 @@
ignored:
- DL3008
- DL3042
- DL3018
- DL3059
trustedRegistries:
- docker.io
- ghcr.io
- quay.io
- gcr.forust.xyz
+8
View File
@@ -0,0 +1,8 @@
{
"default": true,
"MD013": false,
"MD024": false,
"MD033": false,
"MD041": false,
"MD046": false
}
+7
View File
@@ -0,0 +1,7 @@
bracketSameLine: true
htmlWhitespaceSensitivity: css
printWidth: 120
tabWidth: 2
trailingComma: all
proseWrap: preserve
endOfLine: lf
+22
View File
@@ -0,0 +1,22 @@
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"
+40
View File
@@ -0,0 +1,40 @@
{
"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",
"language_servers": ["pyright", "ruff"],
"formatter": {
"language_server": { "name": "ruff" },
},
},
},
"lsp": {
"yaml-language-server": {
"settings": {
"yaml": {
"schemas": {
"kubernetes": ["**/k8s/*.yaml", "**/k8s/*.yml"],
},
"validate": true,
"completion": true,
"format": {
"enable": true,
},
},
},
},
},
}
+4 -4
View File
@@ -21,7 +21,7 @@ services:
# Prod Router
- "traefik.http.routers.adguard.rule=Host(`dns.forust.xyz`) || Host(`adguard.forust.xyz`)"
- "traefik.http.routers.adguard.entrypoints=websecure"
- "traefik.http.routers.adguard.tls=true"
- "traefik.http.routers.adguard.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.adguard-local.rule=Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`)"
- "traefik.http.routers.adguard-local.entrypoints=websecure"
@@ -31,9 +31,9 @@ services:
- "traefik.http.routers.adguard-dev.entrypoints=websecure"
- "traefik.http.routers.adguard-dev.tls=true"
# DoH Router
- "traefik.http.routers.dns.rule=(Host(`dns.forust.xyz`) && PathPrefix(`/dns-query`))"
- "traefik.http.routers.dns.entrypoints=websecure"
- "traefik.http.routers.dns.tls.certresolver=letsencrypt"
- "traefik.http.routers.dns-over-https.rule=(Host(`dns.forust.xyz` || Host(`adguard.forust.xyz`)) && PathPrefix(`/dns-query`))"
- "traefik.http.routers.dns-over-https.entrypoints=websecure"
- "traefik.http.routers.dns-over-https.tls.certresolver=letsencrypt"
# Glance Metadata
- glance.name=adguard
+26
View File
@@ -1,5 +1,31 @@
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
+10 -29
View File
@@ -7,8 +7,15 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^(adguard|dns)\.forust\.xyz$`)
- match: Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)
kind: Rule
middlewares:
services:
- name: adguard-service
port: 3000
- match: (Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)) && PathPrefix(`/dns-query`)
kind: Rule
middlewares:
services:
- name: adguard-service
port: 3000
@@ -24,39 +31,13 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^(adguard|dns)\.(workstation|gigaforust)\.internal$`)
- 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: HostRegexp(`^(adguard|dns)\.forust\.xyz$`) && PathPrefix(`/dns-query`)
- match: (Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`) || Host(`adguard.gigaforust.internal`) || Host(`dns.gigaforust.internal`)) && PathPrefix(`/dns-query`)
kind: Rule
services:
- name: adguard-service
port: 3000
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: adguard-dot
namespace: adguard
spec:
entryPoints:
- dot
routes:
- match: HostSNI(`*`)
services:
- name: adguard-service
port: 853
+1 -1
View File
@@ -47,7 +47,7 @@ services:
# Prod Router
- "traefik.http.routers.authentik-server.rule=Host(`auth.forust.xyz`)"
- "traefik.http.routers.authentik-server.entrypoints=websecure"
- "traefik.http.routers.authentik-server.tls=true"
- "traefik.http.routers.authentik-server.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.authentik-server-local.rule=Host(`auth.workstation.internal`)"
- "traefik.http.routers.authentik-server-local.entrypoints=websecure"
+3 -3
View File
@@ -7,8 +7,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^auth\.forust\.xyz$`)
- match: Host(`auth.forust.xyz`)
kind: Rule
middlewares:
services:
- name: authentik-server-service
port: 9000
@@ -24,9 +25,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^auth\.(workstation|gigaforust)\.internal$`)
- match: Host(`auth.workstation.internal`) || Host(`auth.gigaforust.internal`)
kind: Rule
services:
- name: authentik-server-service
port: 9000
+1 -1
View File
@@ -5,7 +5,7 @@ services:
restart: unless-stopped
security_opt:
- no-new-privileges:true
network_mode: 'host'
network_mode: "host"
# https://github.com/timothymiller/cloudflare-ddns#-quick-start
environment:
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN:?Cloudflare API token is required}
+1 -1
View File
@@ -7,7 +7,7 @@
"api_key": {
"api_key": "api_key_here",
"account_email": "your_email_here"
}
},
"zone_id": "your_zone-id",
"subdomains": [
{ "name": "", "proxied": true },
+1 -1
View File
@@ -21,7 +21,7 @@ services:
# Prod Router
- "traefik.http.routers.checkmk.rule=Host(`cmk.forust.xyz`)"
- "traefik.http.routers.checkmk.entrypoints=websecure"
- "traefik.http.routers.checkmk.tls=true"
- "traefik.http.routers.checkmk.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.checkmk-local.rule=Host(`cmk.workstation.internal`)"
- "traefik.http.routers.checkmk-local.entrypoints=websecure"
+3 -3
View File
@@ -7,8 +7,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^cmk\.forust\.xyz$`)
- match: Host(`cmk.forust.xyz`)
kind: Rule
middlewares:
services:
- name: checkmk-service
port: 5000
@@ -24,9 +25,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^cmk\.(workstation|gigaforust)\.internal$`)
- match: Host(`cmk.workstation.internal`) || Host(`cmk.gigaforust.internal`)
kind: Rule
services:
- name: checkmk-service
port: 5000
+9
View File
@@ -0,0 +1,9 @@
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
@@ -0,0 +1,70 @@
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
@@ -0,0 +1,42 @@
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"
@@ -3,7 +3,7 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: convertx-config
namespace: convertx
namespace: converters
data:
ACCOUNT_REGISTRATION: "false"
HTTP_ALLOWED: "false"
@@ -2,7 +2,7 @@ apiVersion: v1
kind: Service
metadata:
name: convertx-service
namespace: convertx
namespace: converters
spec:
selector:
app: convertx
@@ -14,7 +14,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: convertx-deployment
namespace: convertx
namespace: converters
spec:
replicas: 1
selector:
@@ -54,7 +54,7 @@ apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: convertx-pvc
namespace: convertx
namespace: converters
spec:
accessModes:
- ReadWriteOnce
+65
View File
@@ -0,0 +1,65 @@
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
@@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: convertx
name: converters
@@ -2,6 +2,7 @@ apiVersion: v1
kind: Secret
metadata:
name: convertx-secrets
namespace: converters
type: Opaque
stringData:
jwt-secret: ""
-43
View File
@@ -1,43 +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(`convert.forust.xyz`)"
- "traefik.http.routers.convertx.entrypoints=websecure"
- "traefik.http.routers.convertx.tls=true"
# Local Router
- "traefik.http.routers.convertx-local.rule=Host(`convert.workstation.internal`)"
- "traefik.http.routers.convertx-local.entrypoints=websecure"
- "traefik.http.routers.convertx-local.tls=true"
# Dev Router
- "traefik.http.routers.convertx-dev.rule=Host(`convertx.gigaforust.internal`)"
- "traefik.http.routers.convertx-dev.entrypoints=websecure"
- "traefik.http.routers.convertx-dev.tls=true"
networks:
- proxy
volumes:
- data:/app/data
networks:
proxy:
external: true
volumes:
data:
-32
View File
@@ -1,32 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: convertx-prod
namespace: convertx
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^forust\.xyz$`) && PathPrefix(`/convert`)
kind: Rule
services:
- name: convertx-service
port: 3000
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: convertx-local
namespace: convertx
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^(workstation|gigaforust)\.internal$`) && PathPrefix(`/convert`)
kind: Rule
services:
- name: convertx-service
port: 3000
+1 -1
View File
@@ -23,7 +23,7 @@ services:
- "traefik.http.routers.dockmon.rule=Host(`dockmon.forust.xyz`)"
- "traefik.http.routers.dockmon.entrypoints=websecure"
- "traefik.http.routers.dockmon.middlewares=security-headers@file"
- "traefik.http.routers.dockmon.tls=true"
- "traefik.http.routers.dockmon.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.dockmon-local.rule=Host(`dockmon.workstation.internal`)"
- "traefik.http.routers.dockmon-local.entrypoints=websecure"
+2 -3
View File
@@ -15,7 +15,7 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^dockmon\.forust\.xyz$`)
- match: Host(`dockmon.forust.xyz`)
kind: Rule
middlewares:
- name: security-headers@file
@@ -35,10 +35,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^dockmon\.(workstation|gigaforust)\.internal$`)
- match: Host(`dockmon.workstation.internal`) || Host(`dockmon.gigaforust.internal`)
kind: Rule
services:
- name: dockmon-service
port: 443
serversTransport: dockmon-transport
+1 -1
View File
@@ -15,7 +15,7 @@ services:
- "traefik.http.routers.downtify.rule=Host(`downtify.forust.xyz`)"
- "traefik.http.routers.downtify.entrypoints=websecure"
- "traefik.http.routers.downtify.middlewares=security-chain@file"
- "traefik.http.routers.downtify.tls=true"
- "traefik.http.routers.downtify.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.downtify-local.rule=Host(`downtify.workstation.internal`)"
- "traefik.http.routers.downtify-local.entrypoints=websecure"
+2 -3
View File
@@ -7,7 +7,7 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^downtify\.forust\.xyz$`)
- match: Host(`downtify.forust.xyz`)
kind: Rule
middlewares:
- name: security-chain@file
@@ -26,9 +26,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^downtify\.(workstation|gigaforust)\.internal$`)
- match: Host(`downtify.workstation.internal`) || Host(`downtify.gigaforust.internal`)
kind: Rule
services:
- name: downtify-service
port: 8000
+284 -314
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -3,10 +3,10 @@ FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y redis-tools && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y --no-install-recommends redis-tools && rm -rf /var/lib/apt/lists/*
# Install dependencies
RUN pip install requests redis
RUN pip install --no-cache-dir requests==2.32.3 redis==5.2.1
# Copy application code
COPY . .
+36 -33
View File
@@ -1,17 +1,16 @@
import logging
import os
import time
import requests
import logging
import redis
from datetime import datetime
import redis
import requests
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Load configuration (adapted to .env keys)
def _env(key, default=None):
v = os.getenv(key, default)
@@ -19,21 +18,26 @@ def _env(key, default=None):
return v[1:-1]
return v
LOGIN = _env('KEEPER_LOGIN')
PASSWORD = _env('KEEPER_PASSWORD')
EDU_BASE = _env('EDU_URL_BASE', 'https://edu.edu.vn.ua')
EDU_LOGIN_PATH = _env('EDU_URL_LOGIN', '/user/login')
EDU_COURSES_PATH = _env('EDU_URL_COURSES', '/course/userlist')
URL_LOGIN = f"{EDU_BASE.rstrip('/')}/{EDU_LOGIN_PATH.lstrip('/')}"
URL_VERIFY = f"{EDU_BASE.rstrip('/')}/{EDU_COURSES_PATH.lstrip('/')}"
URL_LOGIN = f'{EDU_BASE.rstrip("/")}/{EDU_LOGIN_PATH.lstrip("/")}'
URL_VERIFY = f'{EDU_BASE.rstrip("/")}/{EDU_COURSES_PATH.lstrip("/")}'
INTERVAL = int(_env('KEEPER_INTERVAL', 10))
USER_AGENT = _env('USER_AGENT', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36')
USER_AGENT = _env(
'USER_AGENT',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36',
)
REDIS_HOST = _env('REDIS_HOST', 'redis')
REDIS_PORT = int(_env('REDIS_PORT', 6379))
SUCCESS_FILE = '/tmp/last_success'
SUCCESS_FILE = '/tmp/last_success' # noqa: S108
def touch_success_file():
"""Updates the timestamp of the success file for healthchecks."""
@@ -41,18 +45,19 @@ def touch_success_file():
with open(SUCCESS_FILE, 'w') as f:
f.write(str(datetime.now().timestamp()))
except Exception as e:
logger.error(f"Failed to touch success file: {e}")
logger.error(f'Failed to touch success file: {e}')
def main():
logger.info("Starting Session Keeper Bot")
logger.info('Starting Session Keeper Bot')
# Connect to Redis
try:
redis_client = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, decode_responses=True)
redis_client.ping()
logger.info(f"Connected to Redis at {REDIS_HOST}:{REDIS_PORT}")
logger.info(f'Connected to Redis at {REDIS_HOST}:{REDIS_PORT}')
except Exception as e:
logger.error(f"Failed to connect to Redis: {e}")
logger.error(f'Failed to connect to Redis: {e}')
return
session = requests.Session()
@@ -72,19 +77,16 @@ def main():
'Sec-Ch-Ua-Mobile': '?0',
'Sec-Ch-Ua-Platform': '"Linux"',
'Accept-Encoding': 'gzip, deflate, br',
'Priority': 'u=0, i'
'Priority': 'u=0, i',
}
session.headers.update(headers)
while True:
try:
logger.info("Attempting login...")
logger.info('Attempting login...')
# Login payload
payload = {
'login': LOGIN,
'password': PASSWORD
}
payload = {'login': LOGIN, 'password': PASSWORD}
# Perform Login
# Note: The user request shows a POST to /user/login with form data
@@ -93,17 +95,17 @@ def main():
login_response = session.post(URL_LOGIN, data=payload, allow_redirects=True)
logger.info(f"Login Response Status: {login_response.status_code}")
logger.info(f"Cookies after login: {session.cookies.get_dict()}")
logger.info(f'Login Response Status: {login_response.status_code}')
logger.info(f'Cookies after login: {session.cookies.get_dict()}')
# Verify Session
logger.info("Verifying session...")
logger.info('Verifying session...')
verify_response = session.get(URL_VERIFY, allow_redirects=False)
logger.info(f"Verify Response Status: {verify_response.status_code}")
logger.info(f'Verify Response Status: {verify_response.status_code}')
if verify_response.status_code == 200:
logger.info("Session verification SUCCESS (200 OK).")
logger.info('Session verification SUCCESS (200 OK).')
touch_success_file()
# Save PHPSESSID to Redis
@@ -111,19 +113,20 @@ def main():
if phpsessid:
try:
redis_client.set('EDU_PHPSESSID', phpsessid)
logger.info(f"Saved PHPSESSID to Redis: {phpsessid}")
logger.info(f'Saved PHPSESSID to Redis: {phpsessid}')
except Exception as e:
logger.error(f"Failed to save PHPSESSID to Redis: {e}")
logger.error(f'Failed to save PHPSESSID to Redis: {e}')
elif verify_response.status_code == 302:
logger.warning("Session verification FAILED (302 Redirect). Session might be invalid.")
logger.warning('Session verification FAILED (302 Redirect). Session might be invalid.')
else:
logger.warning(f"Session verification returned unexpected status: {verify_response.status_code}")
logger.warning(f'Session verification returned unexpected status: {verify_response.status_code}')
except Exception as e:
logger.error(f"An error occurred: {e}")
logger.error(f'An error occurred: {e}')
logger.info(f"Sleeping for {INTERVAL} minutes...")
logger.info(f'Sleeping for {INTERVAL} minutes...')
time.sleep(INTERVAL * 60)
if __name__ == "__main__":
if __name__ == '__main__':
main()
+1 -1
View File
@@ -3,7 +3,7 @@ FROM python:3.11-slim
WORKDIR /app
# Install dependencies
RUN pip install --upgrade pip && pip install playwright==1.56.0 redis requests "python-telegram-bot[job-queue]"
RUN pip install --no-cache-dir pip==25.0.1 && pip install --no-cache-dir playwright==1.56.0 redis==5.2.1 requests==2.32.3 "python-telegram-bot[job-queue]==21.10"
COPY checker.py .
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -36,7 +36,7 @@ services:
# Prod Router
- "traefik.http.routers.gitea.rule=Host(`gitea.forust.xyz`)"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls=true"
- "traefik.http.routers.gitea.tls.certresolver"
# Local Router
- "traefik.http.routers.gitea-local.rule=Host(`gitea.workstation.internal`)"
- "traefik.http.routers.gitea-local.entrypoints=websecure"
@@ -53,7 +53,6 @@ services:
- "traefik.http.routers.gitea-registry.rule=Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)"
- "traefik.http.routers.gitea-registry.entrypoints=websecure"
- "traefik.http.routers.gitea-registry.tls.certresolver=letsencrypt"
- "traefik.http.routers.gitea-registry.tls=true"
ports:
- "2221:22"
networks:
+2
View File
@@ -16,5 +16,7 @@ data:
GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES: "*"
GITEA__mailer__ENABLED: "false"
GITEA__log__logger__access__MODE: "console, file"
USER_UID: "1000"
USER_GID: "1000"
@@ -7,8 +7,15 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^gitea\.forust\.xyz$`)
- match: Host(`gitea.forust.xyz`)
kind: Rule
middlewares:
services:
- name: gitea-service
port: 3000
- match: Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)
kind: Rule
middlewares:
services:
- name: gitea-service
port: 3000
@@ -24,29 +31,16 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^gitea\.(workstation|gigaforust)\.internal$`)
- 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`)
- match: (Host(`gcr.workstation.internal`) || Host(`gcr.gigaforust.internal`)) && PathPrefix(`/v2`)
kind: Rule
services:
- name: gitea-service
port: 3000
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
+7 -4
View File
@@ -15,16 +15,19 @@ services:
- "traefik.services.glance.loadbalancer.server.port=8080"
# Prod Router
- "traefik.http.routers.glance.rule=Host(`glance.forust.xyz`)"
- "traefik.http.routers.glance.rule=(Host(`forust.xyz`) || Host(`www.forust.xyz`)) && PathPrefix(`/glance`)"
- "traefik.http.routers.glance.entrypoints=websecure"
- "traefik.http.routers.glance.tls=true"
- "traefik.http.routers.glance.priority=50"
- "traefik.http.routers.glance.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.glance-local.rule=Host(`glance.workstation.internal`)"
- "traefik.http.routers.glance-local.rule=Host(`workstation.internal`) && PathPrefix(`/glance`)"
- "traefik.http.routers.glance-local.entrypoints=websecure"
- "traefik.http.routers.glance-local.priority=50"
- "traefik.http.routers.glance-local.tls=true"
# Dev Router
- "traefik.http.routers.glance-dev.rule=Host(`glance.gigaforust.internal`)"
- "traefik.http.routers.glance-dev.rule=Host(`gigaforust.internal`) && PathPrefix(`/glance`)"
- "traefik.http.routers.glance-dev.entrypoints=websecure"
- "traefik.http.routers.glance-dev.priority=50"
- "traefik.http.routers.glance-dev.tls=true"
networks:
- proxy
-1
View File
@@ -65,7 +65,6 @@
- symbol: MSFT
name: Microsoft
- type: releases
cache: 1d
# Without authentication the Github API allows for up to 60 requests per hour. You can create a
-2
View File
@@ -11,5 +11,3 @@
widgets:
- type: docker-containers
hide-by-default: false
+2
View File
@@ -56,6 +56,8 @@ data:
glance.yml: |
server:
assets-path: /app/assets
proxied: true
base-url: /glance
theme:
# Перевели #050505 и #e0e0e0 в формат HSL для Glance
background-color: 0 0 2 # Истинно черный фон
+1 -1
View File
@@ -56,7 +56,7 @@ spec:
readOnly: true
resources:
requests:
memory: "10Mi"
memory: "30Mi"
cpu: "20m"
limits:
memory: "100Mi"
+17 -5
View File
@@ -7,10 +7,11 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^forust\.xyz$`)
- match: (Host(`forust.xyz`) || Host(`www.forust.xyz`)) && PathPrefix(`/glance`)
kind: Rule
priority: 50
middlewares:
- name: glance-strupprefix
- name: glance-stripprefix
services:
- name: glance-service
port: 8080
@@ -26,10 +27,21 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^glance\.(workstation|gigaforust)\.internal$`)
- 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
+37 -3
View File
@@ -24,7 +24,7 @@ services:
- "traefik.http.routers.headscale.rule=Host(`hs.forust.xyz`)"
- "traefik.http.routers.headscale.entrypoints=websecure"
- "traefik.http.routers.headscale.service=headscale"
- "traefik.http.routers.headscale.tls=true"
- "traefik.http.routers.headscale.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.headscale-local.rule=Host(`hs.workstation.internal`)"
- "traefik.http.routers.headscale-local.entrypoints=websecure"
@@ -57,7 +57,7 @@ services:
container_name: headplane
restart: unless-stopped
ports:
- '13000:3000'
- "13000:3000"
volumes:
- ./config/headplane.yaml:/etc/headplane/config.yaml
- ./config/headscale.yaml:/etc/headscale/config.yaml
@@ -65,6 +65,40 @@ services:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.services.headplane.loadbalancer.server.port=3000"
# Middleware: add /admin prefix for root requests
- "traefik.http.middlewares.headplane-prefix.addPrefix.prefix=/admin"
# Prod Root Router
- "traefik.http.routers.headplane-root.rule=Host(`hp.forust.xyz`)"
- "traefik.http.routers.headplane-root.entrypoints=websecure"
- "traefik.http.routers.headplane-root.middlewares=headplane-prefix"
- "traefik.http.routers.headplane-root.tls.certresolver=letsencrypt"
# Prod Router
- "traefik.http.routers.headplane.rule=Host(`hp.forust.xyz`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headplane.entrypoints=websecure"
- "traefik.http.routers.headplane.tls.certresolver=letsencrypt"
# Local Root Router
- "traefik.http.routers.headplane-root-local.rule=Host(`hp.workstation.internal`)"
- "traefik.http.routers.headplane-root-local.entrypoints=websecure"
- "traefik.http.routers.headplane-root-local.middlewares=headplane-prefix"
- "traefik.http.routers.headplane-root-local.tls=true"
# Local Router
- "traefik.http.routers.headplane-local.rule=Host(`hp.workstation.internal`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headplane-local.entrypoints=websecure"
- "traefik.http.routers.headplane-local.tls=true"
# Dev Root Router
- "traefik.http.routers.headplane-root-dev.rule=Host(`hp.gigaforust.internal`)"
- "traefik.http.routers.headplane-root-dev.entrypoints=websecure"
- "traefik.http.routers.headplane-root-dev.middlewares=headplane-prefix"
- "traefik.http.routers.headplane-root-dev.tls=true"
# Dev Router
- "traefik.http.routers.headplane-dev.rule=Host(`hp.gigaforust.internal`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headplane-dev.entrypoints=websecure"
- "traefik.http.routers.headplane-dev.tls=true"
web:
image: goodieshq/headscale-admin:latest
restart: unless-stopped
@@ -78,7 +112,7 @@ services:
- "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=true"
- "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"
+3 -2
View File
@@ -33,7 +33,9 @@ derp:
auto_update_enabled: true
update_frequency: 24h
disable_check_updates: false
ephemeral_node_inactivity_timeout: 30m
node:
ephemeral:
inactivity_timeout: 30m
database:
type: sqlite
debug: false
@@ -76,4 +78,3 @@ unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
logtail:
enabled: false
randomize_client_port: false
+4 -9
View File
@@ -1,25 +1,20 @@
{
"groups": {
"group:admin": [
"admin@"
],
"group:admin": ["admin@"],
"group:users": []
},
"tagOwners": {},
"hosts": {},
"acls": [
{
"randomizeClientPort": false,
"#ha-meta": {
"name": "users",
"open": true
},
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"autogroup:self:*"
]
"src": ["autogroup:member"],
"dst": ["autogroup:self:*"]
}
],
"ssh": []
+27
View File
@@ -57,3 +57,30 @@ ports:
endpoints:
- addresses:
- "192.168.88.100"
---
apiVersion: v1
kind: Service
metadata:
name: headplane-external
namespace: headscale
spec:
ports:
- port: 3000
targetPort: 13000
name: http
---
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: headplane-external
namespace: headscale
labels:
kubernetes.io/service-name: headplane-external
addressType: IPv4
ports:
- port: 13000
protocol: TCP
name: http
endpoints:
- addresses:
- "192.168.88.100"
+70 -64
View File
@@ -1,82 +1,36 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
kind: Middleware
metadata:
name: headscale-server-prod
name: headplane-prefix
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.forust\.xyz$`)
kind: Rule
services:
- name: headscale-server-external
port: 8080
tls:
certResolver: letsencrypt
addPrefix:
prefix: "/admin"
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-server-local
name: headscale-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`)
kind: Rule
services:
- name: headscale-server-external
port: 8080
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-ui-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.forust\.xyz$`) && PathPrefix(`/admin`)
- match: Host(`hs.forust.xyz`)
kind: Rule
middlewares:
services:
- name: headscale-server-external
port: 8080
- match: Host(`hs.forust.xyz`) && PathPrefix(`/admin`)
kind: Rule
middlewares:
- name: security-chain@file
services:
- name: headscale-ui-external
port: 80
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-ui-local
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`) && PathPrefix(`/admin`)
kind: Rule
services:
- name: headscale-ui-external
port: 80
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-metrics-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.forust\.xyz$`) && PathPrefix(`/metrics`)
- match: Host(`hs.forust.xyz`) && PathPrefix(`/metrics`)
kind: Rule
middlewares:
services:
- name: headscale-server-external
port: 9090
@@ -86,16 +40,68 @@ spec:
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-metrics-local
name: headplane-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`) && PathPrefix(`/metrics`)
- match: Host(`hp.forust.xyz`)
kind: Rule
middlewares:
- name: headplane-prefix
services:
- name: headplane-external
port: 3000
- match: Host(`hp.forust.xyz`) && PathPrefix(`/admin`)
kind: Rule
services:
- name: headplane-external
port: 3000
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-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
- match: (Host(`hs.workstation.internal`) || Host(`hs.gigaforust.internal`)) && PathPrefix(`/admin`)
kind: Rule
services:
- name: headscale-ui-external
port: 80
- match: (Host(`hs.workstation.internal`) || Host(`hs.gigaforust.internal`)) && PathPrefix(`/metrics`)
kind: Rule
services:
- name: headscale-server-external
port: 9090
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headplane-local
namespace: headscale
spec:
routes:
- match: Host(`hp.workstation.internal`) || Host(`hp.gigaforust.internal`)
kind: Rule
middlewares:
- name: headplane-prefix
services:
- name: headplane-external
port: 3000
- match: (Host(`hp.workstation.internal`) || Host(`hp.gigaforust.internal`)) && PathPrefix(`/admin`)
kind: Rule
services:
- name: headplane-external
port: 3000
+4 -2
View File
@@ -19,14 +19,17 @@ services:
# Prod Router
- "traefik.http.routers.forust-homepage.rule=Host(`forust.xyz`) || Host(`www.forust.xyz`)"
- "traefik.http.routers.forust-homepage.entrypoints=websecure"
- "traefik.http.routers.forust-homepage.tls=true"
- "traefik.http.routers.forust-homepage.priority=10"
- "traefik.http.routers.forust-homepage.tls.certresolver=letsencrypt"
# Local Router
- "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.priority=10"
- "traefik.http.routers.forust-homepage-local.tls=true"
# Dev Router
- "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.priority=10"
- "traefik.http.routers.forust-homepage-dev.tls=true"
xdfnx:
build:
@@ -47,7 +50,6 @@ services:
- "traefik.http.routers.xdfnx.rule=Host(`xdfnx.cfd`) || Host(`www.xdfnx.cfd`)"
- "traefik.http.routers.xdfnx.entrypoints=websecure"
- "traefik.http.routers.xdfnx.tls.certresolver=letsencrypt"
- "traefik.http.routers.xdfnx.tls=true"
# Local Router
- "traefik.http.routers.xdfnx-local.rule=Host(`xdfnx.workstation.internal`)"
- "traefik.http.routers.xdfnx-local.entrypoints=websecure"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 53 KiB

+99 -70
View File
@@ -1,27 +1,26 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MrForust // XRock</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">
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
<link rel="stylesheet" href="assets/css/style.css" />
</head>
<body>
<div class="container">
<header>
<h1 class="glitch" data-text="MrForust">Mr-Forust</h1>
<p class="subtitle">> CTF Player / XRock_Team / Just Signal.</p>
</header>
<hr>
<hr />
<section id="socials">
<h2>./socials</h2>
<div class="grid-2">
<section id="contacts">
<h2>./contacts</h2>
<ul class="link-list">
<li>
<i class="fab fa-github"></i>
@@ -43,14 +42,6 @@
<i class="fas fa-envelope"></i>
<a href="mailto:contact@forust.xyz">mail/contact@forust.xyz</a>
</li>
<li>
<i class="fa fa-pie-chart"></i>
<a href="https://forust.xyz/glance">forust/dashboard</a>
</li>
<li>
<i class="fa fa-refresh"></i>
<a href="https://forust.xyz/convert">forust/converter</a>
</li>
<li>
<i class="fa-solid fa-key"></i>
<a href=".well-known/pgp-key.asc">security/PGP Key</a>
@@ -61,52 +52,53 @@
</ul>
</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>
<p class="comment"># Glance dashboard</p>
</li>
<li>
<i class="fa fa-refresh"></i>
<a href="https://forust.xyz/convert" target="_blank">forust/converter</a>
<p class="comment"># ConvertX instance</p>
</li>
<li>
<i class="fa-solid fa-file-pdf"></i>
<a href="https://pdf.forust.xyz" target="_blank">pdf.forust.xyz</a>
<p class="comment"># BentoPDF instance</p>
</li>
</ul>
</section>
</div>
<section id="stack">
<h2>./skills_and_tools</h2>
<h2>./skills</h2>
<div class="grid-2">
<div>
<div class="skill-item">
<span>ArchLinux # btw</span>
<span class="level">[#######...]</span>
</div>
<div class="skill-item"><span>Kubernetes</span> <span class="level">[###.......]</span></div>
<div class="skill-item"><span>Docker</span> <span class="level">[####......]</span></div>
<div class="skill-item">
<span>Kubernetes</span> <span class="level">[###.......]</span>
</div>
<div class="skill-item">
<span>Docker</span> <span class="level">[####......]</span>
</div>
<div class="skill-item">
<span>Docker Compose</span> <span class="level">[#####.....]</span>
</div>
<div class="skill-item">
<span>Web Pentest</span> <span class="level">[#####.....]</span>
</div>
<div class="skill-item">
<span>Burpsuite</span> <span class="level">[#####.....]</span>
</div>
<div class="skill-item">
<span>Steganography</span> <span class="level">[####......]</span>
<span>Docker Compose</span>
<span class="level">[#####.....]</span>
</div>
<div class="skill-item"><span>Web Pentest</span> <span class="level">[#####.....]</span></div>
<div class="skill-item"><span>Burpsuite</span> <span class="level">[#####.....]</span></div>
<div class="skill-item"><span>Steganography</span> <span class="level">[####......]</span></div>
</div>
<div>
<div class="skill-item">
<span>Cryptography</span> <span class="level">[####......]</span>
</div>
<div class="skill-item">
<span>OSINT</span> <span class="level">[####......]</span>
</div>
<div class="skill-item">
<span>Python</span> <span class="level">[###.......]</span>
</div>
<div class="skill-item">
<span>HTML</span> <span class="level">[###.......]</span>
</div>
<div class="skill-item">
<span>Bash</span> <span class="level">[##........]</span>
</div>
<div class="skill-item">
<span>Golang</span> <span class="level">[#.........]</span>
</div>
<div class="skill-item"><span>Cryptography</span> <span class="level">[####......]</span></div>
<div class="skill-item"><span>OSINT</span> <span class="level">[####......]</span></div>
<div class="skill-item"><span>Python</span> <span class="level">[###.......]</span></div>
<div class="skill-item"><span>HTML</span> <span class="level">[###.......]</span></div>
<div class="skill-item"><span>Bash</span> <span class="level">[##........]</span></div>
<div class="skill-item"><span>Golang</span> <span class="level">[#.........]</span></div>
</div>
</div>
</section>
@@ -117,42 +109,77 @@
<div class="team-grid">
<div class="member">
<div class="avatar"
style="background-image: url('assets/images/team/mrforust.jpg'); background-size: cover; background-position: center;">
</div>
<div
class="avatar"
style="
background-image: url(&quot;assets/images/team/mrforust.jpg&quot;);
background-size: cover;
background-position: center;
"
></div>
<a href="https://github.com/mr-forust" target="_blank">MrForust</a>
</div>
<div class="member">
<div class="avatar"
style="background-image: url('assets/images/team/anna.jpg'); background-size: cover; background-position: center;">
</div>
<div
class="avatar"
style="
background-image: url(&quot;assets/images/team/anna.jpg&quot;);
background-size: cover;
background-position: center;
"
></div>
<a href="./assets/images/love.png" target="_blank">Anna~</a>
</div>
<div class="member">
<div class="avatar"
style="background-image: url('assets/images/team/chernuha.jpg'); background-size: cover; background-position: center;">
</div>
<div
class="avatar"
style="
background-image: url(&quot;assets/images/team/chernuha.jpg&quot;);
background-size: cover;
background-position: center;
"
></div>
<a href="https://chernuha.space" target="_blank">Chernuha</a>
</div>
<div class="member">
<div class="avatar"
style="background-image: url('assets/images/team/hudan.jpg'); background-size: cover; background-position: center;">
</div>
<div
class="avatar"
style="
background-image: url(&quot;assets/images/team/hudan.jpg&quot;);
background-size: cover;
background-position: center;
"
></div>
<a href="https://hudan.xyz" target="_blank">p1ngvi</a>
</div>
<div class="member">
<div class="avatar"
style="background-image: url('assets/images/team/xdfnx.jpg'); background-size: cover; background-position: center;">
</div>
<div
class="avatar"
style="
background-image: url(&quot;assets/images/team/xdfnx.jpg&quot;);
background-size: cover;
background-position: center;
"
></div>
<a href="https://xdfnx.cfd" target="_blank">xdfnx</a>
</div>
</div>
</section>
<section id="projects">
<h2>./projects</h2>
<ul class="repo-list">
<li>
<a href="https://gitea.forust.xyz/forust/gosleep" target="_blank">forust/gosleep</a>
<span class="comment">// linux sleep timer written in rust (originally in go)</span>
</li>
</ul>
</section>
<section id="repos">
<h2>./favorite_repos</h2>
<ul class="repo-list">
@@ -168,6 +195,10 @@
<a href="https://github.com/unhappychoice/gitlogue" target="_blank">unhappychoice/gitlogue</a>
<span class="comment">// nice git log visualizer</span>
</li>
<li>
<a href="https://github.com/tstack/lnav" target="_blank">tstack/lnav</a>
<span class="comment">// powerful log reader</span>
</li>
<li>
<a href="https://github.com/mountain-loop/yaak" target="_blank">mountain-loop/yaak</a>
<span class="comment">// modern, fancy api client</span>
@@ -190,7 +221,5 @@
<p>&copy; XRock - Just Signal.</p>
</footer>
</div>
</body>
</html>
+2
View File
@@ -28,6 +28,7 @@ spec:
containers:
- name: forust-homepage
image: gcr.forust.xyz/forust/forust-homepage:latest
imagePullPolicy: Always
ports:
- containerPort: 80
resources:
@@ -68,6 +69,7 @@ spec:
containers:
- name: xdfnx-homepage
image: gcr.forust.xyz/forust/xdfnx-homepage:latest
imagePullPolicy: Always
ports:
- containerPort: 80
resources:
+8 -5
View File
@@ -7,8 +7,10 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^(forust\.xyz|www\.forust\.xyz)$`)
- match: Host(`forust.xyz`) || Host(`www.forust.xyz`)
kind: Rule
middlewares:
priority: 10
services:
- name: forust-homepage-service
port: 80
@@ -24,8 +26,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^landing\.(workstation|gigaforust)\.internal$`)
- match: Host(`landing.workstation.internal`) || Host(`landing.gigaforust.internal`)
kind: Rule
priority: 10
services:
- name: forust-homepage-service
port: 80
@@ -39,8 +42,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^(xdfnx\.cfd|www\.xdfnx\.cfd)$`)
- match: Host(`xdfnx.cfd`)
kind: Rule
middlewares:
services:
- name: xdfnx-homepage-service
port: 80
@@ -56,9 +60,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^xdfnx\.(workstation|gigaforust)\.internal$`)
- match: Host(`xdfnx.workstation.internal`) || Host(`xdfnx.gigaforust.internal`)
kind: Rule
services:
- name: xdfnx-homepage-service
port: 80
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -23,7 +23,7 @@ services:
# Prod Router
- "traefik.http.routers.kener.rule=Host(`status.forust.xyz`)"
- "traefik.http.routers.kener.entrypoints=websecure"
- "traefik.http.routers.kener.tls=true"
- "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"
+3 -3
View File
@@ -7,8 +7,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^status\.forust\.xyz$`)
- match: Host(`status.forust.xyz`)
kind: Rule
middlewares:
services:
- name: kener-service
port: 3000
@@ -24,9 +25,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^status\.(workstation|gigaforust)\.internal$`)
- match: Host(`status.workstation.internal`) || Host(`status.gigaforust.internal`)
kind: Rule
services:
- name: kener-service
port: 3000
+1 -1
View File
@@ -27,7 +27,7 @@ spec:
spec:
containers:
- name: kener
image: rajnandan1/kener:4.0.23
image: rajnandan1/kener:4.1.0
envFrom:
- configMapRef:
name: kener-config
+1 -1
View File
@@ -20,7 +20,7 @@ services:
- "traefik.http.routers.metube.rule=Host(`metube.forust.xyz`)"
- "traefik.http.routers.metube.entrypoints=websecure"
- "traefik.http.routers.metube.middlewares=security-chain@file"
- "traefik.http.routers.metube.tls=true"
- "traefik.http.routers.metube.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.metube-local.rule=Host(`metube.workstation.internal`)"
- "traefik.http.routers.metube-local.entrypoints=websecure"
+2 -3
View File
@@ -7,7 +7,7 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^metube\.forust\.xyz$`)
- match: Host(`metube.forust.xyz`)
kind: Rule
middlewares:
- name: security-headers@file
@@ -26,9 +26,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^metube\.(workstation|gigaforust)\.internal$`)
- match: Host(`metube.workstation.internal`) || Host(`metube.gigaforust.internal`)
kind: Rule
services:
- name: metube-service
port: 8081
+1 -1
View File
@@ -32,7 +32,7 @@ services:
# Prod Router
- "traefik.http.routers.n8n.rule=Host(`n8n.forust.xyz`)"
- "traefik.http.routers.n8n.entrypoints=websecure"
- "traefik.http.routers.n8n.tls=true"
- "traefik.http.routers.n8n.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.n8n-local.rule=Host(`n8n.workstation.internal`)"
- "traefik.http.routers.n8n-local.entrypoints=websecure"
+3 -3
View File
@@ -7,8 +7,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^n8n\.forust\.xyz$`)
- match: Host(`n8n.forust.xyz`)
kind: Rule
middlewares:
services:
- name: n8n-service
port: 5678
@@ -24,9 +25,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^n8n\.(workstation|gigaforust)\.internal$`)
- match: Host(`n8n.workstation.internal`) || Host(`n8n.gigaforust.internal`)
kind: Rule
services:
- name: n8n-service
port: 5678
+1 -2
View File
@@ -16,7 +16,7 @@ services:
# Prod Router
- "traefik.http.routers.netronome.rule=Host(`nm.forust.xyz`)"
- "traefik.http.routers.netronome.entrypoints=websecure"
- "traefik.http.routers.netronome.tls=true"
- "traefik.http.routers.netronome.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.netronome-local.rule=Host(`nm.workstation.internal`)"
- "traefik.http.routers.netronome-local.entrypoints=websecure"
@@ -51,7 +51,6 @@ services:
volumes:
data:
networks:
proxy:
external: true
+3 -3
View File
@@ -7,8 +7,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^nm\.forust\.xyz$`)
- match: Host(`nm.forust.xyz`)
kind: Rule
middlewares:
services:
- name: netronome-service
port: 7575
@@ -24,9 +25,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^nm\.(workstation|gigaforust)\.internal$`)
- match: Host(`nm.workstation.internal`) || Host(`nm.gigaforust.internal`)
kind: Rule
services:
- name: netronome-service
port: 7575
+1 -1
View File
@@ -25,7 +25,7 @@ services:
# - "traefik.http.routers.nextcloud-aio.rule=Host(`naio.forust.xyz`)"
# - "traefik.http.routers.nextcloud-aio.entrypoints=websecure"
# - "traefik.http.routers.nextcloud-aio.middlewares=security-chain@file"
# - "traefik.http.routers.nextcloud-aio.tls=true"
# - "traefik.http.routers.nextcloud-aio.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.nextcloud-aio-local.rule=Host(`naio.workstation.internal`)"
- "traefik.http.routers.nextcloud-aio-local.entrypoints=websecure"
+22 -24
View File
@@ -8,7 +8,7 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^nextcloud\.forust\.xyz$`)
- match: Host(`nextcloud.forust.xyz`)
kind: Rule
middlewares:
- name: nextcloud-chain@file
@@ -27,34 +27,33 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^nextcloud\.(workstation|gigaforust)\.internal$`)
- match: Host(`nextcloud.workstation.internal`) || Host(`nextcloud.gigaforust.internal`)
kind: Rule
middlewares:
- name: nextcloud-chain@file
services:
- name: nextcloud-apache
port: 11000
---
# ---
# Nextcloud AIO
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: naio-prod
namespace: nextcloud
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^naio\.forust\.xyz$`)
kind: Rule
services:
- name: nextcloud-aio
port: 8888
scheme: https
serversTransport: insecure-transport # <-- Ссылка на ваш CRD ресурс вместо @file
tls:
certResolver: letsencrypt
# apiVersion: traefik.io/v1alpha1
# kind: IngressRoute
# metadata:
# name: naio-prod
# namespace: nextcloud
# spec:
# entryPoints:
# - websecure
# routes:
# - match: Host(`naio.forust.xyz`)
# kind: Rule
# services:
# - name: nextcloud-aio
# port: 8888
# scheme: https
# serversTransport: insecure-transport
# tls:
# certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
@@ -65,11 +64,10 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^naio\.(workstation|gigaforust)\.internal$`)
- match: Host(`naio.workstation.internal`) || Host(`naio.gigaforust.internal`)
kind: Rule
services:
- name: nextcloud-aio
port: 8888
scheme: https
serversTransport: insecure-transport
+1 -1
View File
@@ -107,7 +107,7 @@ services:
# Prod Router
- "traefik.http.routers.penpot.rule=Host(`penpot.forust.xyz`)"
- "traefik.http.routers.penpot.entrypoints=websecure"
- "traefik.http.routers.penpot.tls=true"
- "traefik.http.routers.penpot.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.penpot-local.rule=Host(`penpot.workstation.internal`)"
- "traefik.http.routers.penpot-local.entrypoints=websecure"
+1 -1
View File
@@ -16,7 +16,7 @@ services:
# Prod Router
- "traefik.http.routers.portainer.rule=Host(`portainer.forust.xyz`)"
- "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.tls=true"
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.portainer-local.rule=Host(`portainer.workstation.internal`)"
- "traefik.http.routers.portainer-local.entrypoints=websecure"
+3 -3
View File
@@ -7,8 +7,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^portainer\.forust\.xyz$`)
- match: Host(`portainer.forust.xyz`)
kind: Rule
middlewares:
services:
- name: portainer-service
port: 9000
@@ -24,9 +25,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^portainer\.(workstation|gigaforust)\.internal$`)
- match: Host(`portainer.workstation.internal`) || Host(`portainer.gigaforust.internal`)
kind: Rule
services:
- name: portainer-service
port: 9000
+2
View File
@@ -0,0 +1,2 @@
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=changeme
+5
View File
@@ -0,0 +1,5 @@
route:
receiver: default
receivers:
- name: default
+66
View File
@@ -0,0 +1,66 @@
services:
grafana:
image: grafana/grafana:11.6.0
container_name: prometheus-grafana
restart: unless-stopped
env_file:
- .env
environment:
GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER:-admin}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:?grafana admin password required}
volumes:
- grafana-data:/var/lib/grafana
labels:
- "traefik.enable=true"
- "traefik.http.services.prometheus-grafana.loadbalancer.server.port=3000"
# Prod Router
- "traefik.http.routers.grafana.rule=Host(`grafana.forust.xyz`)"
- "traefik.http.routers.grafana.entrypoints=websecure"
- "traefik.http.routers.grafana.tls=true"
# Local Router
- "traefik.http.routers.grafana-local.rule=Host(`grafana.workstation.internal`)"
- "traefik.http.routers.grafana-local.entrypoints=websecure"
- "traefik.http.routers.grafana-local.tls=true"
# Dev Router
- "traefik.http.routers.grafana-dev.rule=Host(`grafana.gigaforust.internal`)"
- "traefik.http.routers.grafana-dev.entrypoints=websecure"
- "traefik.http.routers.grafana-dev.tls=true"
networks:
- proxy
prometheus:
image: prom/prometheus:v3.2.1
container_name: prometheus-prometheus
restart: unless-stopped
command:
- "--config.file=/etc/prometheus/prometheus.yaml"
- "--storage.tsdb.path=/prometheus"
- "--storage.tsdb.retention.time=90d"
volumes:
- prometheus-data:/prometheus
- ./prometheus.yaml:/etc/prometheus/prometheus.yaml:ro
networks:
- proxy
alertmanager:
image: prom/alertmanager:v0.28.1
container_name: prometheus-alertmanager
restart: unless-stopped
command:
- "--config.file=/etc/alertmanager/alertmanager.yaml"
- "--storage.path=/alertmanager"
volumes:
- alertmanager-data:/alertmanager
- ./alertmanager.yaml:/etc/alertmanager/alertmanager.yaml:ro
networks:
- proxy
volumes:
grafana-data:
prometheus-data:
alertmanager-data:
networks:
proxy:
external: true
+52
View File
@@ -0,0 +1,52 @@
grafana:
grafana.ini:
server:
domain: grafana.forust.xyz
root_url: https://grafana.forust.xyz
auth.anonymous:
enabled: false
users:
allow_sign_up: false
admin:
existingSecret: grafana-admin
userKey: admin-user
passwordKey: admin-password
persistence:
enabled: true
size: 10Gi
ingress:
enabled: false
service:
port: 80
prometheus:
prometheusSpec:
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: "local-path"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 40Gi
resources:
requests:
memory: "700Mi"
cpu: 200m
limits:
memory: "2Gi"
alertmanager:
alertmanagerSpec:
storage:
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
+35
View File
@@ -0,0 +1,35 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: grafana-prod
namespace: prometheus
spec:
entryPoints:
- websecure
routes:
- match: Host(`grafana.forust.xyz`)
kind: Rule
middlewares:
- name: "security-chain@file"
services:
- name: prometheus-stack-grafana
port: 80
tls:
certResolver: letsencrypt
domains:
- main: grafana.forust.xyz
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: grafana-local
namespace: prometheus
spec:
entryPoints:
- websecure
routes:
- match: Host(`grafana.workstation.internal`) || Host(`grafana.gigaforust.internal`)
kind: Rule
services:
- name: prometheus-stack-grafana
port: 80
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: prometheus
@@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: grafana-admin
namespace: prometheus
type: Opaque
stringData:
admin-user: "admin"
admin-password: ""
+8
View File
@@ -0,0 +1,8 @@
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ["localhost:9090"]
+4
View File
@@ -0,0 +1,4 @@
{
"venvPath": "/home/forust/homelab/userbot",
"venv": ".venv"
}
+11
View File
@@ -0,0 +1,11 @@
target-version = "py311"
line-length = 120
[lint]
select = ["E", "F", "W", "I", "N", "UP", "S", "B", "A", "C4", "SIM", "ARG"]
ignore = ["E501", "S101"]
[format]
quote-style = "single"
indent-style = "space"
line-ending = "lf"
+2 -2
View File
@@ -12,9 +12,9 @@ services:
- "traefik.enable=true"
- "traefik.http.services.searxng.loadbalancer.server.port=8080"
# Prod Router
- "traefik.http.routers.searxng.rule=Host(`s.forust.xyz` || `searxng.forust.xyz`)"
- "traefik.http.routers.searxng.rule=Host(`s.forust.xyz` || `search.forust.xyz`)"
- "traefik.http.routers.searxng.entrypoints=websecure"
- "traefik.http.routers.searxng.tls=true"
- "traefik.http.routers.searxng.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.searxng-local.rule=Host(`s.workstation.internal` || `searxng.workstation.internal`)"
- "traefik.http.routers.searxng-local.entrypoints=websecure"
+3 -3
View File
@@ -7,8 +7,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^(s|searxng)\.forust\.xyz$`)
- match: Host(`s.forust.xyz`) || Host(`search.forust.xyz`)
kind: Rule
middlewares:
services:
- name: searxng-service
port: 8080
@@ -24,9 +25,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^(s|searxng)\.(workstation|gigaforust)\.internal$`)
- match: Host(`s.workstation.internal`) || Host(`searxng.workstation.internal`) || Host(`s.gigaforust.internal`) || Host(`searxng.gigaforust.internal`)
kind: Rule
services:
- name: searxng-service
port: 8080
+1 -1
View File
@@ -16,7 +16,7 @@ services:
# Prod Router
- "traefik.http.routers.termix.rule=Host(`termix.forust.xyz`)"
- "traefik.http.routers.termix.entrypoints=websecure"
- "traefik.http.routers.termix.tls=true"
- "traefik.http.routers.termix.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.termix-local.rule=Host(`termix.workstation.internal`)"
- "traefik.http.routers.termix-local.entrypoints=websecure"
+3 -3
View File
@@ -7,8 +7,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^termix\.forust\.xyz$`)
- match: Host(`termix.forust.xyz`)
kind: Rule
middlewares:
services:
- name: termix-service
port: 8080
@@ -24,9 +25,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^termix\.(workstation|gigaforust)\.internal$`)
- match: Host(`termix.workstation.internal`) || Host(`termix.gigaforust.internal`)
kind: Rule
services:
- name: termix-service
port: 8080
+1 -1
View File
@@ -49,7 +49,7 @@ services:
- "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
- "traefik.http.routers.traefik-dashboard.middlewares=security-chain@file"
- "traefik.http.routers.traefik-dashboard.service=api@internal"
- "traefik.http.routers.traefik-dashboard.tls=true"
- "traefik.http.routers.traefik-dashboard.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.traefik-dashboard-local.rule=Host(`traefik.workstation.internal`)"
- "traefik.http.routers.traefik-dashboard-local.entrypoints=websecure"
+2 -1
View File
@@ -8,7 +8,8 @@ http:
service: nextcloud
middlewares:
- nextcloud-chain
tls: {}
tls:
certresolver: letsencrypt
# Nextcloud dev
nextcloud-local:
+23
View File
@@ -0,0 +1,23 @@
http:
routers:
fs1-public:
rule: "Host(`fs1.domain.xyz`)"
entrypoints:
- websecure
service: fs1
middlewares:
- security-chain@file
tls: {}
fs1-workstation:
rule: "Host(`fs1.workstation.internal`)"
entrypoints:
- websecure
service: fs1
tls: {}
services:
fs1:
loadBalancer:
servers:
- url: "http://127.0.0.1:3923" # Copyparty port example
+3 -3
View File
@@ -8,8 +8,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^traefik\.forust\.xyz$`)
- match: Host(`traefik.forust.xyz`)
kind: Rule
middlewares:
services:
- name: api@internal
kind: TraefikService
@@ -25,9 +26,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^traefik\.(workstation|gigaforust)\.internal$`)
- match: Host(`traefik.workstation.internal`) || Host(`traefik.gigaforust.internal`)
kind: Rule
services:
- name: api@internal
kind: TraefikService
+1 -1
View File
@@ -50,7 +50,7 @@ data:
- security-headers@file
authentik:
forwardAuth:
address: "http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
address: "http://authentik-server-service.authentik.svc:9000/outpost.goauthentik.io/auth/traefik"
trustForwardHeader: true
maxResponseBodySize: 1048576
authResponseHeaders:
+27 -19
View File
@@ -1,5 +1,9 @@
# Auto-generated by forust | See https://github.com/traefik/traefik-helm-chart/blob/master/values.yaml
hostNetwork: false
image:
registry: docker.io/library
repository: traefik
tag: v3.7.6
securityContext:
capabilities:
@@ -13,6 +17,8 @@ service:
type: LoadBalancer
annotations:
metallb.io/loadBalancerIPs: "192.168.80.2"
spec:
externalTrafficPolicy: Local
api:
dashboard: true
insecure: true
@@ -21,16 +27,7 @@ updateStrategy:
type: Recreate
deployment:
initContainers:
- name: volume-permissions
image: busybox:latest
command:
- sh
- -c
- "mkdir -p /data/letsencrypt && touch /data/letsencrypt/acme.json && chmod 600 /data/letsencrypt/acme.json"
volumeMounts:
- name: data
mountPath: /data
enabled: true
providers:
kubernetesIngress:
@@ -75,12 +72,22 @@ ports:
protocol: UDP
expose:
default: true
dot:
port: 853
exposedPort: 853
metrics:
port: 9100
exposedPort: 9100
protocol: TCP
expose:
default: true
default: false
metrics:
prometheus:
enabled: true
entryPoint: metrics
serviceMonitor:
enabled: true
additionalLabels:
release: prometheus-stack
namespace: prometheus
ingressRoute:
dashboard:
@@ -111,14 +118,15 @@ volumes:
- name: traefik-dynamic
mountPath: /etc/traefik/dynamic
type: configMap
additionalArguments:
- "--providers.file.directory=/etc/traefik/dynamic"
- "--providers.file.watch=true"
- "--providers.kubernetesCRD.allowCrossNamespace=true"
- "--entryPoints.websecure.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,192.168.1.1,192.168.1.0/24,192.168.88.0/24,192.168.88.1"
- "--entryPoints.web.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,192.168.1.1,192.168.1.0/24,192.168.88.0/24,192.168.88.1"
logs:
general:
log:
level: INFO
format: json
access:
accessLog:
enabled: true
format: common
+1 -1
View File
@@ -14,7 +14,7 @@ services:
# Prod Router
- "traefik.http.routers.uptime-kuma.rule=Host(`uptime.forust.xyz`)"
- "traefik.http.routers.uptime-kuma.entrypoints=websecure"
- "traefik.http.routers.uptime-kuma.tls=true"
- "traefik.http.routers.uptime-kuma.tls.certresolver=letsencrypt"
# Local Router
- "traefik.http.routers.uptime-kuma-local.rule=Host(`uptime.workstation.internal`)"
- "traefik.http.routers.uptime-kuma-local.entrypoints=websecure"
+3 -3
View File
@@ -7,8 +7,9 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^uptime\.forust\.xyz$`)
- match: Host(`uptime.forust.xyz`)
kind: Rule
middlewares:
services:
- name: uptime-kuma-service
port: 3001
@@ -24,9 +25,8 @@ spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^uptime\.(workstation|gigaforust)\.internal$`)
- match: Host(`uptime.workstation.internal`) || Host(`uptime.gigaforust.internal`)
kind: Rule
services:
- name: uptime-kuma-service
port: 3001
+1 -7
View File
@@ -2,13 +2,7 @@
"name": "Moon-userbot",
"description": "A Simple, Fast, Customizable, Ai powered Userbot for Telegram with most easiest installation.",
"logo": "https://camo.githubusercontent.com/1efdfa6416b3cd08471d865ca9ebf0fbdd38602ea95425f18a9bec6aeeefe49b/68747470733a2f2f74656c656772612e70682f66696c652f3063333763326662306631393463633163303334342e6a7067",
"keywords": [
"telegram",
"Moon-userbot",
"bot",
"python",
"pyrogram"
],
"keywords": ["telegram", "Moon-userbot", "bot", "python", "pyrogram"],
"env": {
"API_ID": {
"description": "Get it from my.telegram.org",
+3 -3
View File
@@ -3,10 +3,10 @@ from flask import Flask
app = Flask(__name__)
@app.route("/")
@app.route('/')
def hello_world():
return "This is Moon"
return 'This is Moon'
if __name__ == "__main__":
if __name__ == '__main__':
app.run()
+21 -7
View File
@@ -1,17 +1,31 @@
FROM python:3.11-slim AS builder
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
WORKDIR /src
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.11-slim
WORKDIR /app
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN apt-get update && apt-get install -y --no-install-recommends \
git wget ffmpeg mediainfo && \
rm -rf /var/lib/apt/lists/*
git \
mediainfo \
wget \
xz-utils \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt /app/
RUN python -m pip install --no-cache-dir --upgrade pip && \
python -m pip install --no-cache-dir -r /app/requirements.txt
RUN wget -qO- https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz | \
tar xJ && \
cp ffmpeg-*-static/ffmpeg /usr/local/bin/ && \
cp ffmpeg-*-static/ffprobe /usr/local/bin/ && \
rm -rf ffmpeg-*
COPY --from=builder /root/.local /usr/local
COPY . /app
WORKDIR /app
ENV PYTHONUNBUFFERED=1
+40 -45
View File
@@ -1,115 +1,110 @@
import re
import requests
import random
import re
from io import BytesIO
from bs4 import BeautifulSoup as bs
import requests
from bs4 import BeautifulSoup
from pyrogram import Client, filters
from pyrogram.types import Message, InputMediaPhoto
from pyrogram.errors import RPCError
from pyrogram.types import InputMediaPhoto, Message
from utils.misc import modules_help, prefix
@Client.on_message(filters.command("icon", prefix) & filters.me)
@Client.on_message(filters.command('icon', prefix) & filters.me)
async def search_icon(_, message: Message):
if not len(message.command) == 2:
return await message.edit_text(
"Please provide some text to search icons from Flaticon.com."
)
if len(message.command) != 2:
return await message.edit_text('Please provide some text to search icons from Flaticon.com.')
query = message.text.split(maxsplit=1)[1]
await message.edit_text("Searching for icons...")
search_query = query.replace(" ", "%20")
url = f"https://www.flaticon.com/search?word={search_query}"
await message.edit_text('Searching for icons...')
search_query = query.replace(' ', '%20')
url = f'https://www.flaticon.com/search?word={search_query}'
try:
html_content = requests.get(url).text
soup = bs(html_content, "html.parser")
html_content = requests.get(url, timeout=10).text
soup = BeautifulSoup(html_content, 'html.parser')
results = soup.find_all(
"img",
src=re.compile(r"https://cdn-icons-png.flaticon.com/128/[0-9]+/[0-9]+.png"),
'img',
src=re.compile(r'https://cdn-icons-png.flaticon.com/128/[0-9]+/[0-9]+.png'),
)
if not results:
return await message.edit("No results found.")
return await message.edit('No results found.')
random.shuffle(results)
icons = []
for i in range(5):
icons.append(results[i]["src"].replace("128", "512"))
icons.append(results[i]['src'].replace('128', '512'))
for icon in icons:
await message.reply_document(icon)
return await message.delete()
except Exception as e:
await message.edit(f"An error occurred: {e}")
print(f"Error: {e}")
await message.edit(f'An error occurred: {e}')
print(f'Error: {e}')
@Client.on_message(filters.command("freepik", prefix) & filters.me)
@Client.on_message(filters.command('freepik', prefix) & filters.me)
async def freepik_search(client: Client, message: Message):
parts = message.text.split(" ", 1)
parts = message.text.split(' ', 1)
if len(parts) < 2:
await message.edit_text("Please provide a search query!")
await message.edit_text('Please provide a search query!')
return
query = parts[1]
limit = 5
if " ; " in query:
match, limit_str = query.split(" ; ", 1)
if ' ; ' in query:
match, limit_str = query.split(' ; ', 1)
try:
limit = int(limit_str)
except ValueError:
await message.edit_text("Invalid limit! Using the default value of 5.")
await message.edit_text('Invalid limit! Using the default value of 5.')
else:
match = query
match = match.replace(" ", "%20")
await message.edit_text("Searching Freepik...")
match = match.replace(' ', '%20')
await message.edit_text('Searching Freepik...')
try:
url = f"https://www.freepik.com/api/regular/search?locale=en&term={match}"
json_content = requests.get(url).json()
url = f'https://www.freepik.com/api/regular/search?locale=en&term={match}'
json_content = requests.get(url, timeout=10).json()
results = []
for i in json_content["items"]:
results.append(i["preview"]["url"])
for i in json_content['items']:
results.append(i['preview']['url'])
if results is None:
return await message.edit_text("No results found.")
return await message.edit_text('No results found.')
random.shuffle(results)
img_urls = results[:limit]
media_group = []
for img_url in img_urls:
icon = requests.get(img_url)
icon = requests.get(img_url, timeout=10)
if icon.status_code == 200:
media_group.append(InputMediaPhoto(media=BytesIO(icon.content)))
if not media_group:
await message.edit_text("No images could be downloaded.")
await message.edit_text('No images could be downloaded.')
return
try:
await client.send_media_group(chat_id=message.chat.id, media=media_group)
except RPCError:
await message.edit_text(
"Failed to send some images. Retrying individually..."
)
await message.edit_text('Failed to send some images. Retrying individually...')
for media in media_group:
try:
await message.reply_photo(photo=media.media)
except Exception as e:
await message.edit_text(f"Error sending image: {e}")
await message.edit_text(f'Error sending image: {e}')
except Exception as e:
await message.edit_text(f"Failed to fetch data: {e}")
print(f"Error: {e}")
await message.edit_text(f'Failed to fetch data: {e}')
print(f'Error: {e}')
modules_help["icons"] = {
"icon [query]": "Search for icons on Flaticon.",
"freepik [query] [limit]": "Search for images on Freepik. Limit is optional and defaults to 5.",
modules_help['icons'] = {
'icon [query]': 'Search for icons on Flaticon.',
'freepik [query] [limit]': 'Search for images on Freepik. Limit is optional and defaults to 5.',
}

Some files were not shown because too many files have changed in this diff Show More