Compare commits

...
Author SHA1 Message Date
renovate-bot acfc5a3467 chore(deps): update container patch updates
ci / lint-prettier (push) Successful in 10s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
ci / lint-prettier (pull_request) Successful in 7s
ci / lint-ruff (pull_request) Successful in 4s
ci / lint-yaml (pull_request) Successful in 6s
ci / lint-dockerfiles (pull_request) Successful in 4s
ci / validate (pull_request) Successful in 9s
renovate-ci / validate-renovate (pull_request) Successful in 10s
ci / deploy-userbot-panel (pull_request) Has been skipped
ci / build (push) Has been skipped
ci / build (pull_request) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-18 10:17:59 +00:00
forust 92bd920113 Merge pull request 'chore(deps): update postgres docker tag to v17.11' (#34) from renovate/postgres-17.x into main
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 4s
ci / validate (push) Successful in 5s
renovate-ci / validate-renovate (push) Successful in 7s
ci / build (push) Successful in 2s
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/34
2026-09-17 18:04:58 +00:00
renovate-bot 8007f82d52 chore(deps): update postgres docker tag to v17.11
ci / lint-dockerfiles (pull_request) Successful in 4s
ci / lint-prettier (pull_request) Successful in 6s
ci / lint-ruff (pull_request) Successful in 4s
ci / lint-yaml (pull_request) Successful in 7s
ci / validate (pull_request) Successful in 4s
renovate-ci / validate-renovate (pull_request) Successful in 8s
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 (pull_request) Has been skipped
ci / build (push) Has been skipped
ci / deploy-userbot-panel (pull_request) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-17 17:59:25 +00:00
forust 60b9766449 Merge pull request 'chore(deps): update ghcr.io/henriquesebastiao/downtify docker tag to v2.13.0' (#32) from renovate/ghcr.io-henriquesebastiao-downtify-2.x into main
renovate-ci / validate-renovate (push) Successful in 7s
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 3s
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
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/32
2026-09-17 17:58:27 +00:00
renovate-bot 0ebb7264bc chore(deps): update ghcr.io/henriquesebastiao/downtify docker tag to v2.13.0 2026-09-17 17:58:27 +00:00
forust ce21c60eba Merge pull request 'chore(deps): update renovate/renovate docker tag to v44.97.2' (#33) from renovate/renovate-renovate-44.x into main
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 4s
renovate-ci / validate-renovate (push) Successful in 7s
ci / build (push) Successful in 2s
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/33
2026-09-17 17:58:15 +00:00
renovate-bot 53638f831d chore(deps): update renovate/renovate docker tag to v44.97.2
ci / lint-prettier (pull_request) Successful in 8s
ci / lint-ruff (pull_request) Successful in 5s
ci / lint-yaml (pull_request) Successful in 7s
ci / lint-dockerfiles (pull_request) Successful in 4s
ci / validate (pull_request) Successful in 6s
renovate-ci / validate-renovate (pull_request) Successful in 8s
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 4s
ci / validate (push) Successful in 5s
ci / build (pull_request) Has been skipped
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
ci / deploy-userbot-panel (pull_request) Has been skipped
2026-09-17 17:57:23 +00:00
forust 4953da2dd7 Merge pull request 'Feat/centralized postgres' (#26) from feat/centralized-postgres into main
ci / lint-prettier (push) Successful in 9s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 8s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 8s
renovate-ci / validate-renovate (push) Successful in 9s
ci / build (push) Successful in 2s
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/26
2026-09-17 17:55:58 +00:00
forust 4ac65f743c lint(postgres): 126:77 error no new line character at the end of file (new-line-at-end-of-file)
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 / lint-ruff (pull_request) Successful in 5s
ci / validate (push) Successful in 6s
ci / lint-prettier (pull_request) Successful in 7s
ci / lint-yaml (pull_request) Successful in 8s
ci / lint-dockerfiles (pull_request) Successful in 7s
ci / validate (pull_request) Successful in 6s
renovate-ci / validate-renovate (pull_request) Successful in 8s
ci / build (push) Has been skipped
ci / build (pull_request) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
ci / deploy-userbot-panel (pull_request) Has been skipped
2026-09-17 17:55:50 +00:00
forust 8f2e9d66c8 chore(gite): updated deprecated access log config 2026-09-17 17:55:50 +00:00
forust c7d42fb90a feat(postgres): migrate gitea to shared postgres database 2026-09-17 17:55:50 +00:00
forust 003b1e5dca feat(postgres): upgrade shared database to PostgreSQL 17
Move the shared postgres service from 15.19 to 17.6 as the postgres17 StatefulSet with its own PVC, extend the initdb and ingress policy with the statuspage database, and drop the now-unused per-app postgres manifests for authentik, gitea and netronome.
2026-09-17 17:55:50 +00:00
forustandCopilot b3463705c3 feat(postgres): migrate apps to shared database
Move Authentik and Netronome to the shared PostgreSQL service after logical dump and restore.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-17 17:55:50 +00:00
forust 52e1f50a80 feat(postgres): add shared database deployments 2026-09-17 17:55:50 +00:00
forust cdc2f10fe8 Merge pull request 'chore(deps): update container patch updates' (#30) from renovate/container-patch-updates into main
ci / lint-prettier (push) Successful in 7s
ci / lint-yaml (push) Successful in 7s
ci / lint-ruff (push) Successful in 5s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 6s
renovate-ci / validate-renovate (push) Successful in 9s
ci / build (push) Successful in 3s
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/30
2026-09-17 17:55:32 +00:00
renovate-bot 89fbdef10e chore(deps): update container patch updates 2026-09-17 17:55:32 +00:00
forust ac795feeed Merge pull request 'chore(deps): update ghcr.io/alexta69/metube docker tag to v2026.09.15' (#31) from renovate/ghcr.io-alexta69-metube-2026.x into main
ci / validate (push) Successful in 5s
renovate-ci / validate-renovate (push) Successful in 8s
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 8s
ci / lint-dockerfiles (push) Successful in 4s
ci / build (push) Successful in 3s
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/31
2026-09-17 17:55:11 +00:00
renovate-bot 3af5ecd07f chore(deps): update ghcr.io/alexta69/metube docker tag to v2026.09.15
ci / lint-prettier (pull_request) Successful in 8s
ci / lint-ruff (pull_request) Successful in 5s
ci / lint-yaml (pull_request) Successful in 7s
ci / lint-dockerfiles (pull_request) Successful in 5s
ci / validate (pull_request) Successful in 5s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 6s
renovate-ci / validate-renovate (pull_request) Successful in 9s
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 6s
ci / build (pull_request) Has been skipped
ci / build (push) Has been skipped
ci / deploy-userbot-panel (pull_request) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-17 17:54:43 +00:00
forust 77be606912 Merge pull request 'chore(deps): update grafana/grafana docker tag to v13.2.2' (#28) from renovate/container-patch-updates into main
ci / build (push) Successful in 2s
ci / deploy-userbot-panel (push) Has been skipped
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 9s
ci / validate (push) Successful in 6s
renovate-ci / validate-renovate (push) Successful in 8s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/28
2026-09-15 12:07:56 +00:00
renovate-bot 4eab6a43c8 chore(deps): update grafana/grafana docker tag to v13.2.2 2026-09-15 12:07:56 +00:00
forust 6c24d4fb17 Merge pull request 'chore(deps): update renovate/renovate docker tag to v44.91.0' (#27) from renovate/renovate-renovate-44.x into main
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
ci / deploy-userbot-panel (push) Has been skipped
renovate-ci / validate-renovate (push) Successful in 9s
ci / build (push) Successful in 2s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/27
2026-09-15 12:07:44 +00:00
renovate-bot e36595a045 chore(deps): update renovate/renovate docker tag to v44.91.0 2026-09-15 12:07:44 +00:00
forust e07537ff8b Merge pull request 'chore(deps): update docker.n8n.io/n8nio/n8n docker tag to v2.40.0' (#29) from renovate/docker.n8n.io-n8nio-n8n-2.x into main
ci / lint-prettier (push) Successful in 13s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 8s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 6s
renovate-ci / validate-renovate (push) Successful in 11s
ci / deploy-userbot-panel (push) Has been skipped
ci / build (push) Successful in 2s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/29
2026-09-15 12:07:27 +00:00
renovate-bot 303eaaa71b chore(deps): update docker.n8n.io/n8nio/n8n docker tag to v2.40.0
ci / lint-prettier (pull_request) Successful in 9s
renovate-ci / validate-renovate (pull_request) Successful in 9s
ci / lint-ruff (pull_request) Successful in 5s
ci / lint-yaml (pull_request) Successful in 7s
ci / lint-dockerfiles (pull_request) Successful in 5s
ci / validate (pull_request) Successful in 6s
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 5s
ci / build (push) Has been skipped
ci / build (pull_request) Has been skipped
ci / deploy-userbot-panel (pull_request) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-15 10:18:03 +00:00
forust 68fb5eb45e Merge pull request 'chore(deps): update renovate/renovate docker tag to v44.85.0' (#25) from renovate/renovate-renovate-44.x into main
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
ci / deploy-userbot-panel (push) Has been skipped
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 6s
renovate-ci / validate-renovate (push) Successful in 7s
ci / build (push) Successful in 2s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/25
2026-09-14 09:48:39 +00:00
renovate-bot 1c58c78892 chore(deps): update renovate/renovate docker tag to v44.85.0
ci / lint-prettier (pull_request) Successful in 7s
ci / lint-ruff (pull_request) Successful in 4s
ci / lint-yaml (pull_request) Successful in 6s
ci / lint-dockerfiles (pull_request) Successful in 4s
ci / validate (pull_request) Successful in 5s
ci / lint-prettier (push) Successful in 9s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 9s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
renovate-ci / validate-renovate (pull_request) Successful in 7s
ci / build (pull_request) Has been skipped
ci / build (push) Has been skipped
ci / deploy-userbot-panel (pull_request) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-14 09:48:21 +00:00
forust 82124017c0 Merge pull request 'chore(deps): update redis docker tag to v8.10.1' (#23) from renovate/redis-8.x into main
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
renovate-ci / validate-renovate (push) Successful in 8s
ci / build (push) Successful in 17s
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/23
2026-09-14 09:46:49 +00:00
renovate-bot e502f46f43 chore(deps): update redis docker tag to v8.10.1 2026-09-14 09:46:49 +00:00
forust a4f8218b5e Merge pull request 'chore(deps): update valkey/valkey docker tag to v9' (#24) from renovate/valkey-valkey-9.x into main
ci / lint-prettier (push) Successful in 6s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 6s
renovate-ci / validate-renovate (push) Successful in 10s
ci / build (push) Successful in 1s
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/24
2026-09-14 09:46:24 +00:00
renovate-bot d162a50bba chore(deps): update valkey/valkey docker tag to v9
ci / lint-prettier (pull_request) Successful in 8s
ci / lint-ruff (pull_request) Successful in 4s
ci / lint-yaml (pull_request) Successful in 7s
ci / lint-dockerfiles (pull_request) Successful in 4s
ci / validate (pull_request) Successful in 5s
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 4s
renovate-ci / validate-renovate (pull_request) Successful in 6s
ci / build (pull_request) Has been skipped
ci / build (push) Has been skipped
ci / deploy-userbot-panel (pull_request) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-14 09:44:41 +00:00
forust 9ca8514a0a Merge pull request 'chore(deps): update renovate/renovate docker tag to v44.84.0' (#21) from renovate/renovate-renovate-44.x into main
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 3s
ci / deploy-userbot-panel (push) Has been skipped
ci / validate (push) Successful in 5s
renovate-ci / validate-renovate (push) Successful in 8s
ci / build (push) Successful in 2s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/21
2026-09-14 09:07:55 +00:00
renovate-bot 6fa809a8d2 chore(deps): update renovate/renovate docker tag to v44.84.0 2026-09-14 09:07:55 +00:00
forust c6d8df2317 Merge pull request 'chore(deps): update ghcr.io/goauthentik/server docker tag to v2026' (#22) from renovate/ghcr.io-goauthentik-server-2026.x into main
renovate-ci / validate-renovate (push) Successful in 7s
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 4s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 2s
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/22
2026-09-14 09:07:41 +00:00
renovate-bot c28d7323b3 chore(deps): update ghcr.io/goauthentik/server docker tag to v2026
ci / lint-prettier (pull_request) Successful in 7s
ci / lint-ruff (pull_request) Successful in 4s
ci / lint-yaml (pull_request) Successful in 7s
ci / lint-dockerfiles (pull_request) Successful in 6s
ci / validate (pull_request) Successful in 5s
renovate-ci / validate-renovate (pull_request) Successful in 7s
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 4s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (pull_request) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
ci / build (pull_request) Has been skipped
2026-09-14 09:06:56 +00:00
forust 25f547ff78 Merge pull request 'chore(deps): update docker.n8n.io/n8nio/n8n docker tag to v2.39.5' (#18) from renovate/docker.n8n.io-n8nio-n8n-2.x into main
renovate-ci / validate-renovate (push) Successful in 7s
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 4s
ci / build (push) Successful in 2s
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/18
2026-09-14 09:04:42 +00:00
renovate-bot 50911b4ec1 chore(deps): update docker.n8n.io/n8nio/n8n docker tag to v2.39.5
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 4s
ci / lint-prettier (pull_request) Successful in 6s
ci / lint-ruff (pull_request) Successful in 4s
ci / lint-yaml (pull_request) Successful in 6s
ci / lint-dockerfiles (pull_request) Successful in 5s
ci / validate (pull_request) Successful in 4s
renovate-ci / validate-renovate (pull_request) Successful in 7s
ci / build (push) Has been skipped
ci / build (pull_request) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
ci / deploy-userbot-panel (pull_request) Has been skipped
2026-09-14 09:04:30 +00:00
forust 663675f9a0 Merge pull request 'chore(deps): update ghcr.io/goauthentik/server docker tag to v2025.12.6' (#19) from renovate/ghcr.io-goauthentik-server-2025.x into main
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 6s
renovate-ci / validate-renovate (push) Successful in 7s
ci / build (push) Successful in 2s
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/19
2026-09-14 09:03:35 +00:00
renovate-bot 8b28bd24ff chore(deps): update ghcr.io/goauthentik/server docker tag to v2025.12.6
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 6s
ci / validate (push) Successful in 7s
ci / lint-prettier (pull_request) Successful in 14s
ci / lint-ruff (pull_request) Successful in 4s
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (pull_request) Successful in 7s
ci / validate (pull_request) Successful in 5s
ci / lint-dockerfiles (pull_request) Successful in 4s
renovate-ci / validate-renovate (pull_request) Successful in 10s
ci / build (push) Has been skipped
ci / build (pull_request) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
ci / deploy-userbot-panel (pull_request) Has been skipped
2026-09-14 09:03:24 +00:00
forust b5d6f75330 Merge pull request 'chore(deps): update mcr.microsoft.com/playwright docker tag to v1.63.0' (#20) from renovate/mcr.microsoft.com-playwright-1.x into main
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
ci / lint-prettier (push) Successful in 7s
renovate-ci / validate-renovate (push) Successful in 7s
ci / build (push) Successful in 24s
ci / deploy-userbot-panel (push) Has been skipped
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/20
2026-09-14 09:02:49 +00:00
renovate-bot f5b5ecaafa chore(deps): update mcr.microsoft.com/playwright docker tag to v1.63.0
ci / lint-prettier (pull_request) Successful in 8s
ci / lint-ruff (pull_request) Successful in 4s
ci / lint-yaml (pull_request) Successful in 6s
ci / lint-dockerfiles (pull_request) Successful in 4s
ci / validate (pull_request) Successful in 5s
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 3s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
renovate-ci / validate-renovate (pull_request) Successful in 8s
ci / build (pull_request) Has been skipped
ci / build (push) Has been skipped
ci / deploy-userbot-panel (pull_request) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-14 09:01:58 +00:00
forust 7799b676ca ci: validate Renovate manifests with kubeconform
ci / lint-prettier (push) Successful in 11s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 7s
ci / validate (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 5s
renovate-ci / validate-renovate (push) Successful in 1m21s
ci / build (push) Successful in 3s
ci / deploy-userbot-panel (push) Has been skipped
2026-09-14 10:51:40 +02:00
forustandCopilot 24d3686f60 ci: fix formatting and YAML lint scope
ci / lint-prettier (push) Successful in 13s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 6s
renovate-ci / validate-renovate (push) Failing after 2s
ci / build (push) Successful in 2s
ci / deploy-userbot-panel (push) Has been skipped
Lint tracked YAML files without scanning generated dependencies.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-14 09:30:55 +02:00
forust b8b3bba264 Merge branch 'feat/renovate'
ci / lint-yaml (push) Failing after 6s
ci / lint-prettier (push) Failing after 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
renovate-ci / validate-renovate (push) Failing after 2s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-14 09:16:43 +02:00
forustandCopilot abfbc04067 fix(infra): align monitoring and Gitea database config
Keep CrowdSec scraping explicit and define Gitea's database name.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-14 09:16:01 +02:00
forustandCopilot 23ed72826a chore(images): pin service image updates
Replace floating service images with reviewable tags or digests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-14 09:16:01 +02:00
forustandCopilot 7288058df6 feat(renovate): add Gitea update automation
Run Renovate in Kubernetes to create reviewed image update PRs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-14 09:16:01 +02:00
forust 6715f9e9af chore(k8s): raise resource limits for glance, edu and crowdsec 2026-09-14 01:29:28 +02:00
forust ccec1102ef ci(deploy): helm upgrade kube-prometheus-stack when active 2026-09-14 01:29:24 +02:00
forust 360a6fc5dc feat(prometheus): add alerting rules and alertmanager config 2026-09-14 01:21:27 +02:00
forust 9a806724af chore(crowdsec): remove crowdsec bouncer from dns and headscale ingresses 2026-09-14 01:15:55 +02:00
forustandCopilot ed1ddaad5d feat(crowdsec): restore web traffic protection
Protect public Traefik routes with CrowdSec HTTP decisions and restore access logging for web traffic analysis.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-12 21:05:12 +02:00
forustandCopilot 726b3ee544 fix(edu): run redis as statefulset
ci / deploy-userbot-panel (push) Has been skipped
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 7s
ci / build (push) Successful in 3s
ci / lint-prettier (push) Successful in 11s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
Keep the existing Redis PVC and data while migrating the edu-master workload from Deployment to StatefulSet.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-10 23:35:59 +02:00
forust 13309b26e0 fix: add checkmk agent entrypoint
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
ci / deploy-userbot-panel (push) Has been skipped
ci / lint-prettier (push) Successful in 10s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 7s
ci / build (push) Successful in 2s
update traefik to v3.7.13
2026-09-10 14:52:49 +02:00
forust eddc256bed chore: remove esp32/ingress.yaml from main
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 4s
ci / deploy-userbot-panel (push) Has been skipped
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 3s
2026-09-10 12:12:54 +02:00
forust 52f821cbba Merge branch 'main' of ssh://gitssh.forust.xyz:2221/forust/homelab
ci / lint-prettier (push) Failing after 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Failing after 7s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-10 11:47:25 +02:00
forust 0dbc2fff13 Merge branch 'sidetree' 2026-09-10 11:47:25 +02:00
forust 91ec83bc1c Merge branch 'main' of ssh://gitssh.forust.xyz:2221/forust/homelab
ci / lint-ruff (push) Successful in 4s
ci / lint-prettier (push) Failing after 8s
ci / lint-yaml (push) Failing after 7s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 6s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-10 11:47:20 +02:00
forust 9fec1dae39 Merge branch 'sidetree' 2026-09-10 11:47:15 +02:00
forust e5626b7b2d chore: remove untracked README.md
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 4s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-10 11:45:00 +02:00
forust 8fb12a2176 chore: remove untracked README.md
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 4s
ci / validate (push) Successful in 5s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-10 11:44:23 +02:00
forust fe0c7067b6 Merge branch 'main' of ssh://gitssh.forust.xyz:2221/forust/homelab
ci / validate (push) Successful in 4s
ci / build (push) Has been skipped
ci / lint-prettier (push) Failing after 8s
ci / lint-ruff (push) Successful in 7s
ci / lint-yaml (push) Failing after 6s
ci / lint-dockerfiles (push) Successful in 4s
ci / deploy-userbot-panel (push) Has been skipped
2026-09-10 11:42:17 +02:00
forust d0f0843774 Merge branch 'sidetree' 2026-09-10 11:41:35 +02:00
forust 81a5b207ac Merge branch 'main' of ssh://gitssh.forust.xyz:2221/forust/homelab
ci / lint-prettier (push) Failing after 8s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Failing after 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-10 11:41:31 +02:00
forust e3d5970ae3 chore: remove untracked README.md
ci / lint-prettier (push) Failing after 11s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Failing after 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-10 11:39:20 +02:00
forust 85f05c26cb feat(edu): activate k8s management for edu-master 2026-09-10 00:55:22 +02:00
forust 68630eb773 fix(edu): read diary event times directly from DOM, drop 25 AJAX clicks
ci / lint-prettier (push) Successful in 9s
ci / lint-ruff (push) Successful in 6s
ci / lint-yaml (push) Successful in 10s
ci / lint-dockerfiles (push) Successful in 7s
ci / validate (push) Successful in 6s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
_collect_event_times re-clicked every a.event-link and waited ~3s per
event for a visible span.data, but the calendar embeds all times in
div.event-full-info[data-event-full-info-id] span.data already. The old
loop took ~109s for 25 events and collected 0 (original divs stay
sf-hidden), effectively hanging /diary. Now a single evaluate reads all
times (~3.7s), parsing HH:MM from p.date span.data.
2026-09-10 00:31:04 +02:00
forust dad9cf2104 feat(edu): parse event times in /diary and drop weekend days
ci / lint-prettier (push) Successful in 9s
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 6s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
- fetch each event's time via Playwright (click event-link, read span.data, close fancybox) and render as 'title (HH:MM)'
- '08:00' placeholder renders as localized 'unknown' (time_unknown key in ru/uk/en)
- diary week view shows Mon-Fri only (title ends at Friday)
- diary month view skips Sat/Sun by weekday_idx with name-based fallback
- schedule keyboard drops Sat/Sun day buttons
2026-09-10 00:05:56 +02:00
forust 60886e8be2 style(edu): ruff-format webinar-checker/checker.py
ci / lint-prettier (push) Successful in 13s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 6s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-09 23:47:04 +02:00
forust 4528321225 fix(edu): add TZ to .env.example 2026-09-09 11:46:35 +02:00
forust b246a3dea1 fix(edu): review findings for checker.py i18n — group chat language via resolve_lang/chat: keys (default uk), weekday normalization with _norm_day + logging, drop dead translation keys, html.escape, single lang lookup, distinct whitelist emoji 2026-09-09 11:44:17 +02:00
forustandassistant 4c59a2d2fe lang(edu): translate k8s manifest comments to English only
- restore-seed-job.yaml.example: translate runbook to English
- secrets.yaml.example: translate section headers to English
- webinar-checker.yaml: translate initContainer dependency-order comments to English

Co-authored-by: assistant
2026-09-09 10:46:36 +02:00
forust fcc7b0d611 ci(deploy): gate redeploy behind manual workflow_dispatch
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 2s
ci / deploy-userbot-panel (push) Has been skipped
removes automatic redeploy on push to main; deploy now runs only on
explicit manual trigger
2026-09-06 20:55:40 +02:00
forust 9633fe3a10 style(ci): add trailing newline to deploy workflows
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
deploy / redeploy (push) Failing after 1s
ci / build (push) Successful in 2s
ci / deploy-userbot-panel (push) Has been skipped
2026-09-06 20:45:30 +02:00
forust d9f1c8325a feat(userbot): prereqs at startup, SPA path guard, provision lock
ci / lint-prettier (push) Failing after 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Failing after 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
deploy / redeploy (push) Failing after 0s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
- ensure_prerequisites runs on startup, not per-request; kube config
  errors surface as 503 PanelError
- serialize provisioning with a lock; drop per-endpoint prereq checks
- guard SPA fallback against path traversal (relative_to)
- add backend tests for auth flow, k8s service, spa routing; ci comment
  for legacy userbot deployments
2026-09-06 20:39:12 +02:00
forust 861d89d36a ci(deploy): split runtime by k8s/active marker
services marked k8s/active are applied via kubectl; the rest via docker
compose. inactive services with k8s/ keep only routing manifests
(external Services, EndpointSlices, Ingresses) to reach docker backends.
headscale/nextcloud routing moved to k8s/routing/.

validations: compose config --quiet + kubectl apply --dry-run=client.
namespace manifests applied first. pull_policy:build stacks get
build+push before up so the registry image stays fresh.
2026-09-06 20:39:12 +02:00
forust 71cddd6a91 feat(userbot): add Kubernetes control panel
Manage Telegram instances through Kubernetes with legacy adoption for forust and anna. Build and deploy the panel image alongside the runtime.
2026-09-06 20:39:12 +02:00
forust 30e6f05584 fix(edu_master): satisfy ruff in schedule scraper
- rename ambiguous loop var, merge nested if (E741, SIM102)
- use tempfile.gettempdir() for debug dump (S108)
- drop unused total_lessons assignment (F841)
2026-09-06 20:37:18 +02:00
forust bc8d74fd28 feat(schedule): per-user class picker, parser fixes
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Failing after 5s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 4s
ci / build (push) Has been skipped
- fix parser: capture tr attrs via finditer, strip HTML comments before
  cell parse (was leaving '-->' in subject names)
- store class choice in redis: user:{id}:schedule_class (private) and
  chat:{id}:schedule_class (groups, admin-only via /setclass)
- /schedule renders day for stored class, /setclass sets it directly
- drop teacher emoji, format grade as "N клас"
2026-09-06 16:17:48 +02:00
forust d2d4efb0d7 feat: add schedule scraper for lessons table
ci / lint-prettier (push) Successful in 9s
ci / lint-ruff (push) Failing after 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 6s
ci / validate (push) Successful in 7s
ci / build (push) Has been skipped
Add /schedule command to scrape edu.edu.vn.ua/lessons/table via Playwright.
Inline keyboard flow: pick weekday (with today/tomorrow shortcuts),
then pick class. Cache 5h per user. Parse subjects/notes/teachers,
multi-lesson cells (hr-separated).
2026-09-06 15:46:41 +02:00
forust b752bf88bd feat: add edu_master k8s manifests for k0s migration
ci / lint-prettier (push) Successful in 10s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 35s
2026-09-06 15:00:51 +02:00
forust 587611ca88 chore: remove empty middlewares blocks from k8s ingresses 2026-09-02 12:17:04 +02:00
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-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 6s
ci / lint-prettier (push) Successful in 8s
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 / build (push) Successful in 3s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
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-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 6s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 2s
ci / lint-prettier (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 3s
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 / k8s (push) Successful in 5s
validate / yaml (push) Successful in 7s
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
336 changed files with 19461 additions and 8502 deletions

No files matched your search

+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
+370
View File
@@ -0,0 +1,370 @@
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: |
mapfile -t yaml_files < <(
git ls-files '*.yaml' '*.yml' \
':!node_modules/**' \
':!**/.venv/**'
)
if [ "${#yaml_files[@]}" -eq 0 ]; then
echo "No YAML files found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
cytopia/yamllint:latest \
-c .yamllint "${yaml_files[@]}"
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]
outputs:
services: ${{ steps.services.outputs.services }}
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)
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
for target in runtime panel; do
case "$target" in
runtime)
context="userbot"
image="${REGISTRY}/forust/userbot"
;;
panel)
context="userbot/panel"
image="${REGISTRY}/forust/userbot-panel"
;;
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
;;
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
deploy-userbot-panel:
needs: build
if: github.ref_name == 'main' && contains(needs.build.outputs.services, 'userbot')
runs-on: [self-hosted, linux, arch, homelab, prod]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Apply and roll out userbot panel
shell: bash
run: |
kubectl apply -f userbot/k8s/base/panel.yaml
kubectl get secret userbot-common-secrets -n default -o json \
| jq 'del(.metadata.annotations,.metadata.creationTimestamp,.metadata.resourceVersion,.metadata.uid,.metadata.managedFields) | .metadata.namespace = "userbot"' \
| kubectl apply -f -
# Keep legacy deployments (forust/anna) in sync with manifests; they have no replicas field, so apply leaves scaling to the user manager only.
kubectl apply -f userbot/k8s/base/userbots.yaml
kubectl rollout restart deployment/userbot-panel -n userbot
kubectl rollout status deployment/userbot-panel -n userbot --timeout=180s
+152
View File
@@ -0,0 +1,152 @@
name: deploy
on:
workflow_dispatch:
concurrency:
group: deploy-main
cancel-in-progress: false
jobs:
redeploy:
runs-on: [self-hosted, linux, arch, homelab, prod]
steps:
- name: Redeploy workstation
shell: bash
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
# Set APPLY_PRUNE=true to enable kubectl apply --prune. Requires every
# manifest to carry label app.kubernetes.io/managed-by=homelab-deploy,
# otherwise previously applied resources get deleted on the next run.
APPLY_PRUNE: ${{ vars.APPLY_PRUNE }}
run: |
set -euo pipefail
: "${DEPLOY_HOST:?missing DEPLOY_HOST}"
: "${DEPLOY_USER:?missing DEPLOY_USER}"
: "${DEPLOY_KEY:?missing DEPLOY_SSH_KEY}"
deploy_port="${DEPLOY_PORT:-22}"
deploy_path="${DEPLOY_PATH:-/srv/homelab}"
ssh_key="$RUNNER_TEMP/deploy_key"
mkdir -p "$RUNNER_TEMP"
printf '%s\n' "$DEPLOY_KEY" > "$ssh_key"
chmod 600 "$ssh_key"
ssh_opts=(
-i "$ssh_key"
-p "$deploy_port"
-o BatchMode=yes
-o StrictHostKeyChecking=accept-new
)
ssh "${ssh_opts[@]}" "${DEPLOY_USER}@${DEPLOY_HOST}" \
"DEPLOY_PATH=$(printf '%q' \"$deploy_path\") APPLY_PRUNE=$(printf '%q' \"${APPLY_PRUNE:-false}\") bash -se" <<'EOF'
set -euo pipefail
repo="${DEPLOY_PATH:-/srv/homelab}"
if [ ! -d "$repo/.git" ]; then
echo "Repository not found at $repo"
exit 1
fi
git -C "$repo" fetch origin main
git -C "$repo" reset --hard origin/main
# Runtime selection: a service is k8s-managed when $SERVICE/k8s/active
# exists. Otherwise it is compose-managed, and only k8s/routing/*
# manifests (external Services / EndpointSlices / ServersTransport /
# Ingresses that route to docker backends) are applied.
# migrate: touch SERVICE/k8s/active (+ move routing files up)
# rollback: rm SERVICE/k8s/active
collect_k8s() {
find "$1" -type f \( -name '*.yaml' -o -name '*.yml' \) \
! -path '*/routing/*' ! -path '*/overlays/*' \
! -name 'kustomization.y*ml' ! -name '*.example.y*ml' \
! -name '*values.y*ml' ! -name 'patch-*.y*ml' \
| sort
}
collect_k8s_inactive() {
find "$1" -type f \( -name '*.yaml' -o -name '*.yml' \) \
\( -name 'namespace.y*ml' -o -path '*/routing/*' \) \
! -path '*/overlays/*' ! -name '*.example.y*ml' \
| sort
}
mapfile -t compose_stacks < <(
find "$repo" -type f \( -name 'compose.yaml' -o -name 'compose.yml' \) | sort
)
mapfile -t k8s_manifests < <(
for kd in $(find "$repo" -type d -name k8s ! -path '*/.git/*' | sort); do
if [ -f "$kd/active" ]; then
collect_k8s "$kd"
else
collect_k8s_inactive "$kd"
fi
done
)
echo "== Validate compose stacks =="
for cf in "${compose_stacks[@]}"; do
dir=$(dirname "$cf")
if [ -f "$dir/k8s/active" ]; then
echo " skip (k8s-managed): $dir"
continue
fi
echo " config: $cf"
docker compose -f "$cf" config --quiet
done
echo "== Validate k8s manifests (kubectl dry-run) =="
for m in "${k8s_manifests[@]}"; do
echo " apply --dry-run=client $m"
kubectl apply --dry-run=client -f "$m" >/dev/null
done
echo "== Applying Kubernetes manifests =="
ns_files=()
other_files=()
for m in "${k8s_manifests[@]}"; do
case "$m" in
*/namespace.y?ml) ns_files+=("$m") ;;
*) other_files+=("$m") ;;
esac
done
prune_opts=()
if [ "${APPLY_PRUNE:-false}" = "true" ]; then
prune_opts=(--prune -l app.kubernetes.io/managed-by=homelab-deploy)
fi
if [ "${#ns_files[@]}" -gt 0 ]; then
echo " namespaces first: ${ns_files[*]}"
kubectl apply -f "${ns_files[@]}"
fi
if [ "${#other_files[@]}" -gt 0 ]; then
echo " resources: ${other_files[*]}"
kubectl apply "${prune_opts[@]}" -f "${other_files[@]}"
fi
echo "== Redeploying docker compose stacks =="
for cf in "${compose_stacks[@]}"; do
dir=$(dirname "$cf")
if [ -f "$dir/k8s/active" ]; then
echo " skip (k8s-managed): $dir"
continue
fi
echo " compose: $dir"
if grep -Eq '^\s+pull_policy:\s*build\b' "$cf"; then
docker compose -f "$cf" build
docker compose -f "$cf" push
fi
docker compose -f "$cf" up -d --pull always --remove-orphans
done
EOF
-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
+52
View File
@@ -0,0 +1,52 @@
name: renovate-ci
on:
pull_request:
push:
branches:
- main
workflow_dispatch:
jobs:
validate-renovate:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Validate Renovate Compose draft
shell: bash
run: |
set -euo pipefail
trap 'rm -f renovate/.env' EXIT
printf '%s\n' \
'RENOVATE_ENDPOINT=https://gitea.example/api/v1' \
'RENOVATE_TOKEN=test-token' \
'RENOVATE_REPOSITORIES=forust/homelab' \
> renovate/.env
docker compose -f renovate/renovate-compose.yaml config --quiet
- name: Validate Kubernetes manifests
shell: bash
run: |
set -euo pipefail
docker run --rm \
-v "$PWD:/work" \
-w /work \
ghcr.io/yannh/kubeconform:latest \
-strict \
-ignore-missing-schemas \
-summary \
renovate/k8s/namespace.yaml \
renovate/k8s/configmap.yaml \
renovate/k8s/cronjob.yaml
- name: Validate Renovate repository config
shell: bash
run: |
set -euo pipefail
docker run --rm \
-v "$PWD:/work" \
-w /work \
renovate/renovate:44.83.2 \
renovate-config-validator renovate.json
+370
View File
@@ -0,0 +1,370 @@
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: |
mapfile -t yaml_files < <(
git ls-files '*.yaml' '*.yml' \
':!node_modules/**' \
':!**/.venv/**'
)
if [ "${#yaml_files[@]}" -eq 0 ]; then
echo "No YAML files found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
cytopia/yamllint:latest \
-c .yamllint "${yaml_files[@]}"
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]
outputs:
services: ${{ steps.services.outputs.services }}
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)
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
for target in runtime panel; do
case "$target" in
runtime)
context="userbot"
image="${REGISTRY}/forust/userbot"
;;
panel)
context="userbot/panel"
image="${REGISTRY}/forust/userbot-panel"
;;
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
;;
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
deploy-userbot-panel:
needs: build
if: github.ref_name == 'main' && contains(needs.build.outputs.services, 'userbot')
runs-on: [self-hosted, linux, arch, homelab, prod]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Apply and roll out userbot panel
shell: bash
run: |
kubectl apply -f userbot/k8s/base/panel.yaml
kubectl get secret userbot-common-secrets -n default -o json \
| jq 'del(.metadata.annotations,.metadata.creationTimestamp,.metadata.resourceVersion,.metadata.uid,.metadata.managedFields) | .metadata.namespace = "userbot"' \
| kubectl apply -f -
# Keep legacy deployments (forust/anna) in sync with manifests; they have no replicas field, so apply leaves scaling to the user manager only.
kubectl apply -f userbot/k8s/base/userbots.yaml
kubectl rollout restart deployment/userbot-panel -n userbot
kubectl rollout status deployment/userbot-panel -n userbot --timeout=180s
+161
View File
@@ -0,0 +1,161 @@
name: deploy
on:
workflow_dispatch:
concurrency:
group: deploy-main
cancel-in-progress: false
jobs:
redeploy:
runs-on: [self-hosted, linux, arch, homelab, prod]
steps:
- name: Redeploy workstation
shell: bash
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
# Set APPLY_PRUNE=true to enable kubectl apply --prune. Requires every
# manifest to carry label app.kubernetes.io/managed-by=homelab-deploy,
# otherwise previously applied resources get deleted on the next run.
APPLY_PRUNE: ${{ vars.APPLY_PRUNE }}
run: |
set -euo pipefail
: "${DEPLOY_HOST:?missing DEPLOY_HOST}"
: "${DEPLOY_USER:?missing DEPLOY_USER}"
: "${DEPLOY_KEY:?missing DEPLOY_SSH_KEY}"
deploy_port="${DEPLOY_PORT:-22}"
deploy_path="${DEPLOY_PATH:-/srv/homelab}"
ssh_key="$RUNNER_TEMP/deploy_key"
mkdir -p "$RUNNER_TEMP"
printf '%s\n' "$DEPLOY_KEY" > "$ssh_key"
chmod 600 "$ssh_key"
ssh_opts=(
-i "$ssh_key"
-p "$deploy_port"
-o BatchMode=yes
-o StrictHostKeyChecking=accept-new
)
ssh "${ssh_opts[@]}" "${DEPLOY_USER}@${DEPLOY_HOST}" \
"DEPLOY_PATH=$(printf '%q' \"$deploy_path\") APPLY_PRUNE=$(printf '%q' \"${APPLY_PRUNE:-false}\") bash -se" <<'EOF'
set -euo pipefail
repo="${DEPLOY_PATH:-/srv/homelab}"
if [ ! -d "$repo/.git" ]; then
echo "Repository not found at $repo"
exit 1
fi
git -C "$repo" fetch origin main
git -C "$repo" reset --hard origin/main
# Runtime selection: a service is k8s-managed when $SERVICE/k8s/active
# exists. Otherwise it is compose-managed, and only k8s/routing/*
# manifests (external Services / EndpointSlices / ServersTransport /
# Ingresses that route to docker backends) are applied.
# migrate: touch SERVICE/k8s/active (+ move routing files up)
# rollback: rm SERVICE/k8s/active
collect_k8s() {
find "$1" -type f \( -name '*.yaml' -o -name '*.yml' \) \
! -path '*/routing/*' ! -path '*/overlays/*' \
! -name 'kustomization.y*ml' ! -name '*.example.y*ml' \
! -name '*values.y*ml' ! -name 'patch-*.y*ml' \
| sort
}
collect_k8s_inactive() {
find "$1" -type f \( -name '*.yaml' -o -name '*.yml' \) \
\( -name 'namespace.y*ml' -o -path '*/routing/*' \) \
! -path '*/overlays/*' ! -name '*.example.y*ml' \
| sort
}
mapfile -t compose_stacks < <(
find "$repo" -type f \( -name 'compose.yaml' -o -name 'compose.yml' \) | sort
)
mapfile -t k8s_manifests < <(
for kd in $(find "$repo" -type d -name k8s ! -path '*/.git/*' | sort); do
if [ -f "$kd/active" ]; then
collect_k8s "$kd"
else
collect_k8s_inactive "$kd"
fi
done
)
echo "== Validate compose stacks =="
for cf in "${compose_stacks[@]}"; do
dir=$(dirname "$cf")
if [ -f "$dir/k8s/active" ]; then
echo " skip (k8s-managed): $dir"
continue
fi
echo " config: $cf"
docker compose -f "$cf" config --quiet
done
echo "== Validate k8s manifests (kubectl dry-run) =="
for m in "${k8s_manifests[@]}"; do
echo " apply --dry-run=client $m"
kubectl apply --dry-run=client -f "$m" >/dev/null
done
echo "== Applying Kubernetes manifests =="
ns_files=()
other_files=()
for m in "${k8s_manifests[@]}"; do
case "$m" in
*/namespace.y?ml) ns_files+=("$m") ;;
*) other_files+=("$m") ;;
esac
done
prune_opts=()
if [ "${APPLY_PRUNE:-false}" = "true" ]; then
prune_opts=(--prune -l app.kubernetes.io/managed-by=homelab-deploy)
fi
if [ "${#ns_files[@]}" -gt 0 ]; then
echo " namespaces first: ${ns_files[*]}"
kubectl apply -f "${ns_files[@]}"
fi
if [ -f "$repo/prometheus-stack/k8s/active" ]; then
echo "== Upgrading kube-prometheus-stack =="
helm upgrade --install prometheus-stack prometheus-community/kube-prometheus-stack \
--namespace prometheus \
--version 86.2.3 \
--values "$repo/prometheus-stack/k8s/grafana-values.yaml" \
--wait
fi
if [ "${#other_files[@]}" -gt 0 ]; then
echo " resources: ${other_files[*]}"
kubectl apply "${prune_opts[@]}" -f "${other_files[@]}"
fi
echo "== Redeploying docker compose stacks =="
for cf in "${compose_stacks[@]}"; do
dir=$(dirname "$cf")
if [ -f "$dir/k8s/active" ]; then
echo " skip (k8s-managed): $dir"
continue
fi
echo " compose: $dir"
if grep -Eq '^\s+pull_policy:\s*build\b' "$cf"; then
docker compose -f "$cf" build
docker compose -f "$cf" push
fi
docker compose -f "$cf" up -d --pull always --remove-orphans
done
EOF
-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
+6 -4
View File
@@ -32,7 +32,7 @@ streaming/data/*
streaming/qbittorrent/* streaming/qbittorrent/*
streaming/prowlarr/* streaming/prowlarr/*
# Homepage # Homepage
homepages/forust_files/.well-known/* homepages/forust_files/.well-known/*
# Traefik files # Traefik files
@@ -40,7 +40,8 @@ traefik/letsencrypt/acme.json
traefik/dynamic/fileservers.yml traefik/dynamic/fileservers.yml
traefik/dynamic/*.local.y*ml.* traefik/dynamic/*.local.y*ml.*
traefik/dynamic/*.external.y*ml traefik/dynamic/*.external.y*ml
traefik/k8s/fileservers.y*ml
traefik/k8s/aliasHeadersStrategy.md
traefik/logs/* traefik/logs/*
@@ -52,7 +53,7 @@ certs/
# Monitoring # Monitoring
monitoring/prometheus.yml monitoring/prometheus.yml
# Python # Python
.python-version .python-version
venv/ venv/
pyc pyc
@@ -93,7 +94,7 @@ replacements.txt
edu_master/temp/ edu_master/temp/
temp/* temp/*
# Environment # Environment
.env .env
.env.anna .env.anna
.env.forust .env.forust
@@ -104,4 +105,5 @@ temp/*
*/k8s/*secret* */k8s/*secret*
!*/k8s/*secret*.example !*/k8s/*secret*.example
traefik/k8s/local-tls.yaml traefik/k8s/local-tls.yaml
converters/k8s/config.yaml
convertx/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,
},
},
},
},
},
}
+7 -7
View File
@@ -1,6 +1,6 @@
services: services:
adguard: adguard:
image: adguard/adguardhome:latest image: adguard/adguardhome:v0.107.79
container_name: adguardhome container_name: adguardhome
restart: unless-stopped restart: unless-stopped
ports: ports:
@@ -17,11 +17,11 @@ services:
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.services.adguard.loadbalancer.server.port=3000" - "traefik.http.services.adguard.loadbalancer.server.port=3000"
# Prod Router # Prod Router
- "traefik.http.routers.adguard.rule=Host(`dns.forust.xyz`) || Host(`adguard.forust.xyz`)" - "traefik.http.routers.adguard.rule=Host(`dns.forust.xyz`) || Host(`adguard.forust.xyz`)"
- "traefik.http.routers.adguard.entrypoints=websecure" - "traefik.http.routers.adguard.entrypoints=websecure"
- "traefik.http.routers.adguard.tls=true" - "traefik.http.routers.adguard.tls.certresolver=letsencrypt"
# Local Router # Local Router
- "traefik.http.routers.adguard-local.rule=Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`)" - "traefik.http.routers.adguard-local.rule=Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`)"
- "traefik.http.routers.adguard-local.entrypoints=websecure" - "traefik.http.routers.adguard-local.entrypoints=websecure"
@@ -31,10 +31,10 @@ services:
- "traefik.http.routers.adguard-dev.entrypoints=websecure" - "traefik.http.routers.adguard-dev.entrypoints=websecure"
- "traefik.http.routers.adguard-dev.tls=true" - "traefik.http.routers.adguard-dev.tls=true"
# DoH Router # DoH Router
- "traefik.http.routers.dns.rule=(Host(`dns.forust.xyz`) && PathPrefix(`/dns-query`))" - "traefik.http.routers.dns-over-https.rule=(Host(`dns.forust.xyz` || Host(`adguard.forust.xyz`)) && PathPrefix(`/dns-query`))"
- "traefik.http.routers.dns.entrypoints=websecure" - "traefik.http.routers.dns-over-https.entrypoints=websecure"
- "traefik.http.routers.dns.tls.certresolver=letsencrypt" - "traefik.http.routers.dns-over-https.tls.certresolver=letsencrypt"
# Glance Metadata # Glance Metadata
- glance.name=adguard - glance.name=adguard
- glance.url=https://adguard.forust.xyz/ - glance.url=https://adguard.forust.xyz/
View File
Whitespace-only changes.
+27 -1
View File
@@ -1,5 +1,31 @@
apiVersion: v1 apiVersion: v1
kind: Service 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: metadata:
name: adguard-service name: adguard-service
namespace: adguard namespace: adguard
@@ -39,7 +65,7 @@ spec:
spec: spec:
containers: containers:
- name: adguard - name: adguard
image: adguard/adguardhome:latest image: adguard/adguardhome:v0.107.79
resources: resources:
limits: limits:
memory: "1.5Gi" memory: "1.5Gi"
+11 -29
View File
@@ -7,7 +7,15 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^(adguard|dns)\.forust\.xyz$`) - match: Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
services:
- name: adguard-service
port: 3000
- match: (Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)) && PathPrefix(`/dns-query`)
kind: Rule kind: Rule
services: services:
- name: adguard-service - name: adguard-service
@@ -24,39 +32,13 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: 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 kind: Rule
services: services:
- name: adguard-service - name: adguard-service
port: 3000 port: 3000
--- - match: (Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`) || Host(`adguard.gigaforust.internal`) || Host(`dns.gigaforust.internal`)) && PathPrefix(`/dns-query`)
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: adguard-doh
namespace: adguard
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^(adguard|dns)\.forust\.xyz$`) && PathPrefix(`/dns-query`)
kind: Rule kind: Rule
services: services:
- name: adguard-service - name: adguard-service
port: 3000 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
+2 -2
View File
@@ -1,6 +1,6 @@
services: services:
postgresql: postgresql:
image: docker.io/library/postgres:15-alpine image: docker.io/library/postgres:15.19-alpine
restart: unless-stopped restart: unless-stopped
env_file: env_file:
- .env - .env
@@ -47,7 +47,7 @@ services:
# Prod Router # Prod Router
- "traefik.http.routers.authentik-server.rule=Host(`auth.forust.xyz`)" - "traefik.http.routers.authentik-server.rule=Host(`auth.forust.xyz`)"
- "traefik.http.routers.authentik-server.entrypoints=websecure" - "traefik.http.routers.authentik-server.entrypoints=websecure"
- "traefik.http.routers.authentik-server.tls=true" - "traefik.http.routers.authentik-server.tls.certresolver=letsencrypt"
# Local Router # Local Router
- "traefik.http.routers.authentik-server-local.rule=Host(`auth.workstation.internal`)" - "traefik.http.routers.authentik-server-local.rule=Host(`auth.workstation.internal`)"
- "traefik.http.routers.authentik-server-local.entrypoints=websecure" - "traefik.http.routers.authentik-server-local.entrypoints=websecure"
View File
Whitespace-only changes.
+2 -2
View File
@@ -41,7 +41,7 @@ spec:
spec: spec:
containers: containers:
- name: authentik-server - name: authentik-server
image: ghcr.io/goauthentik/server:2025.10.2 image: ghcr.io/goauthentik/server:2026.8.3
args: ["server"] args: ["server"]
envFrom: envFrom:
- configMapRef: - configMapRef:
@@ -75,7 +75,7 @@ spec:
spec: spec:
containers: containers:
- name: authentik-worker - name: authentik-worker
image: ghcr.io/goauthentik/server:2025.10.2 image: ghcr.io/goauthentik/server:2026.8.3
args: ["worker"] args: ["worker"]
securityContext: securityContext:
runAsUser: 0 runAsUser: 0
+1 -1
View File
@@ -6,6 +6,6 @@ metadata:
data: data:
AUTHENTIK_IMAGE: ghcr.io/goauthentik/server AUTHENTIK_IMAGE: ghcr.io/goauthentik/server
AUTHENTIK_TAG: "2025.10.2" AUTHENTIK_TAG: "2025.10.2"
AUTHENTIK_POSTGRESQL__HOST: authentik-postgres-service AUTHENTIK_POSTGRESQL__HOST: postgres.database.svc.cluster.local
AUTHENTIK_POSTGRESQL__NAME: authentik AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_ERROR_REPORTING__ENABLED: "true" AUTHENTIK_ERROR_REPORTING__ENABLED: "true"
+5 -3
View File
@@ -7,8 +7,11 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^auth\.forust\.xyz$`) - match: Host(`auth.forust.xyz`)
kind: Rule kind: Rule
middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
services: services:
- name: authentik-server-service - name: authentik-server-service
port: 9000 port: 9000
@@ -24,9 +27,8 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^auth\.(workstation|gigaforust)\.internal$`) - match: Host(`auth.workstation.internal`) || Host(`auth.gigaforust.internal`)
kind: Rule kind: Rule
services: services:
- name: authentik-server-service - name: authentik-server-service
port: 9000 port: 9000
-66
View File
@@ -1,66 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: authentik-postgres-service
namespace: authentik
spec:
clusterIP: None
selector:
app: authentik-postgres
ports:
- port: 5432
targetPort: 5432
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: authentik-postgres-statefulset
namespace: authentik
spec:
selector:
matchLabels:
app: authentik-postgres
serviceName: authentik-postgres-service
replicas: 1
template:
metadata:
labels:
app: authentik-postgres
spec:
containers:
- name: postgres
image: docker.io/library/postgres:15-alpine
env:
- name: POSTGRES_DB
value: authentik
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: authentik-secrets
key: AUTHENTIK_POSTGRESQL__USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: authentik-secrets
key: AUTHENTIK_POSTGRESQL__PASSWORD
ports:
- containerPort: 5432
name: postgres
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "500m"
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
+2 -2
View File
@@ -1,11 +1,11 @@
services: services:
cloudflare-ddns: cloudflare-ddns:
image: timothyjmiller/cloudflare-ddns:latest image: timothyjmiller/cloudflare-ddns:2.2.0
container_name: cloudflare-ddns container_name: cloudflare-ddns
restart: unless-stopped restart: unless-stopped
security_opt: security_opt:
- no-new-privileges:true - no-new-privileges:true
network_mode: 'host' network_mode: "host"
# https://github.com/timothymiller/cloudflare-ddns#-quick-start # https://github.com/timothymiller/cloudflare-ddns#-quick-start
environment: environment:
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN:?Cloudflare API token is required} - 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": "api_key_here", "api_key": "api_key_here",
"account_email": "your_email_here" "account_email": "your_email_here"
} },
"zone_id": "your_zone-id", "zone_id": "your_zone-id",
"subdomains": [ "subdomains": [
{ "name": "", "proxied": true }, { "name": "", "proxied": true },
View File
Whitespace-only changes.
+1 -1
View File
@@ -18,7 +18,7 @@ spec:
dnsPolicy: ClusterFirstWithHostNet dnsPolicy: ClusterFirstWithHostNet
containers: containers:
- name: cloudflare-ddns - name: cloudflare-ddns
image: timothyjmiller/cloudflare-ddns:latest image: timothyjmiller/cloudflare-ddns:2.2.0
imagePullPolicy: Always imagePullPolicy: Always
resources: resources:
requests: requests:
+2 -2
View File
@@ -1,6 +1,6 @@
services: services:
checkmk: checkmk:
image: "checkmk/check-mk-raw:2.4.0-latest" image: "checkmk/check-mk-raw:2.4.0-2026.09.14"
container_name: "checkmk" container_name: "checkmk"
restart: unless-stopped restart: unless-stopped
# ports: # ports:
@@ -21,7 +21,7 @@ services:
# Prod Router # Prod Router
- "traefik.http.routers.checkmk.rule=Host(`cmk.forust.xyz`)" - "traefik.http.routers.checkmk.rule=Host(`cmk.forust.xyz`)"
- "traefik.http.routers.checkmk.entrypoints=websecure" - "traefik.http.routers.checkmk.entrypoints=websecure"
- "traefik.http.routers.checkmk.tls=true" - "traefik.http.routers.checkmk.tls.certresolver=letsencrypt"
# Local Router # Local Router
- "traefik.http.routers.checkmk-local.rule=Host(`cmk.workstation.internal`)" - "traefik.http.routers.checkmk-local.rule=Host(`cmk.workstation.internal`)"
- "traefik.http.routers.checkmk-local.entrypoints=websecure" - "traefik.http.routers.checkmk-local.entrypoints=websecure"
View File
Whitespace-only changes.
+10 -3
View File
@@ -7,8 +7,12 @@ spec:
selector: selector:
app: checkmk app: checkmk
ports: ports:
- port: 5000 - name: web
port: 5000
targetPort: 5000 targetPort: 5000
- name: agent-receiver
port: 8000
targetPort: 8000
--- ---
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
@@ -27,14 +31,17 @@ spec:
spec: spec:
containers: containers:
- name: checkmk - name: checkmk
image: checkmk/check-mk-raw:2.4.0-latest image: checkmk/check-mk-raw:2.4.0-2026.09.14
envFrom: envFrom:
- secretRef: - secretRef:
name: checkmk-secrets name: checkmk-secrets
- configMapRef: - configMapRef:
name: checkmk-config name: checkmk-config
ports: ports:
- containerPort: 5000 - name: web
containerPort: 5000
- name: agent-receiver
containerPort: 8000
volumeMounts: volumeMounts:
- name: sites - name: sites
mountPath: /omd/sites mountPath: /omd/sites
+21 -3
View File
@@ -7,8 +7,11 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^cmk\.forust\.xyz$`) - match: Host(`cmk.forust.xyz`)
kind: Rule kind: Rule
middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
services: services:
- name: checkmk-service - name: checkmk-service
port: 5000 port: 5000
@@ -16,6 +19,22 @@ spec:
certResolver: letsencrypt certResolver: letsencrypt
--- ---
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: checkmk-agent-receiver
namespace: checkmk
spec:
entryPoints:
- checkmk-agent
routes:
- match: HostSNI(`*`)
services:
- name: checkmk-service
port: 8000
tls:
passthrough: true
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute kind: IngressRoute
metadata: metadata:
name: checkmk-local name: checkmk-local
@@ -24,9 +43,8 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^cmk\.(workstation|gigaforust)\.internal$`) - match: Host(`cmk.workstation.internal`) || Host(`cmk.gigaforust.internal`)
kind: Rule kind: Rule
services: services:
- name: checkmk-service - name: checkmk-service
port: 5000 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:v0.18.0
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@sha256:4eb4ec8f5030faf87c29a73d3d5a2781f28a597cf440c3ab111eb96aee550871
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:
View File
Whitespace-only changes.
+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@sha256:4eb4ec8f5030faf87c29a73d3d5a2781f28a597cf440c3ab111eb96aee550871
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 kind: ConfigMap
metadata: metadata:
name: convertx-config name: convertx-config
namespace: convertx namespace: converters
data: data:
ACCOUNT_REGISTRATION: "false" ACCOUNT_REGISTRATION: "false"
HTTP_ALLOWED: "false" HTTP_ALLOWED: "false"
@@ -2,7 +2,7 @@ apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: convertx-service name: convertx-service
namespace: convertx namespace: converters
spec: spec:
selector: selector:
app: convertx app: convertx
@@ -14,7 +14,7 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: convertx-deployment name: convertx-deployment
namespace: convertx namespace: converters
spec: spec:
replicas: 1 replicas: 1
selector: selector:
@@ -26,7 +26,7 @@ spec:
app: convertx app: convertx
spec: spec:
containers: containers:
- image: ghcr.io/c4illin/convertx:latest - image: ghcr.io/c4illin/convertx:v0.18.0
name: convertx name: convertx
envFrom: envFrom:
- configMapRef: - configMapRef:
@@ -54,7 +54,7 @@ apiVersion: v1
kind: PersistentVolumeClaim kind: PersistentVolumeClaim
metadata: metadata:
name: convertx-pvc name: convertx-pvc
namespace: convertx namespace: converters
spec: spec:
accessModes: accessModes:
- ReadWriteOnce - 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 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: convertx name: converters
@@ -2,6 +2,7 @@ apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: convertx-secrets name: convertx-secrets
namespace: converters
type: Opaque type: Opaque
stringData: stringData:
jwt-secret: "" 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
+14
View File
@@ -0,0 +1,14 @@
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: crowdsec-bouncer
namespace: crowdsec
spec:
plugin:
crowdsec-bouncer:
enabled: true
LogLevel: INFO
CrowdsecMode: live
CrowdsecLapiScheme: http
CrowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080
CrowdsecLapiKeyFile: "/etc/traefik/secrets/traefik-api-key"
+57
View File
@@ -0,0 +1,57 @@
container_runtime: containerd
agent:
env:
- name: COLLECTIONS
value: "crowdsecurity/traefik crowdsecurity/base-http-scenarios"
- name: DISABLE_COLLECTIONS
value: "crowdsecurity/linux crowdsecurity/sshd"
acquisition:
- namespace: traefik
podName: "*traefik*"
program: traefik
poll_without_inotify: true
resources:
requests:
cpu: 50m
memory: 100Mi
limits:
cpu: 200m
memory: 500Mi
lapi:
env:
- name: COLLECTIONS
value: "crowdsecurity/traefik crowdsecurity/base-http-scenarios"
- name: DISABLE_COLLECTIONS
value: "crowdsecurity/linux crowdsecurity/sshd"
service:
type: ClusterIP
persistentVolume:
data:
enabled: true
storageClassName: local-path-retain
size: 1Gi
config:
enabled: true
storageClassName: local-path-retain
size: 100Mi
storeLAPICscliCredentialsInSecret: true
resources:
requests:
cpu: 50m
memory: 150Mi
limits:
cpu: 400m
memory: 500Mi
metrics:
enabled: true
serviceMonitor:
additionalLabels:
release: prometheus-stack
enabled: true
interval: 30s
scrapeTimeout: 10s
namespace: prometheus
+6
View File
@@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: crowdsec
labels:
app.kubernetes.io/part-of: crowdsec
+27
View File
@@ -0,0 +1,27 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: crowdsec-lapi
namespace: crowdsec
spec:
podSelector:
matchLabels:
k8s-app: crowdsec
type: lapi
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik
podSelector:
matchLabels:
app.kubernetes.io/name: traefik
- podSelector:
matchLabels:
k8s-app: crowdsec
type: agent
ports:
- protocol: TCP
port: 8080
+41 -41
View File
@@ -1,46 +1,46 @@
services: services:
dockmon: dockmon:
image: darthnorse/dockmon:latest image: darthnorse/dockmon:2.4.5
container_name: dockmon container_name: dockmon
restart: unless-stopped restart: unless-stopped
# ports: # ports:
# - 8000:443 # - 8000:443
volumes: volumes:
- data:/app/data - data:/app/data
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
healthcheck: healthcheck:
test: [ "CMD", "curl", "-k", "-f", "https://localhost:443/health" ] test: ["CMD", "curl", "-k", "-f", "https://localhost:443/health"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.services.dockmon.loadbalancer.server.port=443" - "traefik.http.services.dockmon.loadbalancer.server.port=443"
- "traefik.http.services.dockmon.loadbalancer.server.scheme=https" - "traefik.http.services.dockmon.loadbalancer.server.scheme=https"
- "traefik.http.services.dockmon.loadbalancer.serverstransport=insecureTransport@file" - "traefik.http.services.dockmon.loadbalancer.serverstransport=insecureTransport@file"
# Prod Router # Prod Router
- "traefik.http.routers.dockmon.rule=Host(`dockmon.forust.xyz`)" - "traefik.http.routers.dockmon.rule=Host(`dockmon.forust.xyz`)"
- "traefik.http.routers.dockmon.entrypoints=websecure" - "traefik.http.routers.dockmon.entrypoints=websecure"
- "traefik.http.routers.dockmon.middlewares=security-headers@file" - "traefik.http.routers.dockmon.middlewares=security-headers@file"
- "traefik.http.routers.dockmon.tls=true" - "traefik.http.routers.dockmon.tls.certresolver=letsencrypt"
# Local Router # Local Router
- "traefik.http.routers.dockmon-local.rule=Host(`dockmon.workstation.internal`)" - "traefik.http.routers.dockmon-local.rule=Host(`dockmon.workstation.internal`)"
- "traefik.http.routers.dockmon-local.entrypoints=websecure" - "traefik.http.routers.dockmon-local.entrypoints=websecure"
- "traefik.http.routers.dockmon-local.tls=true" - "traefik.http.routers.dockmon-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.dockmon-dev.rule=Host(`dockmon.gigaforust.internal`)" - "traefik.http.routers.dockmon-dev.rule=Host(`dockmon.gigaforust.internal`)"
- "traefik.http.routers.dockmon-dev.entrypoints=websecure" - "traefik.http.routers.dockmon-dev.entrypoints=websecure"
- "traefik.http.routers.dockmon-dev.tls=true" - "traefik.http.routers.dockmon-dev.tls=true"
# Glance Metadata # Glance Metadata
- glance.name=dockmon - glance.name=dockmon
- glance.url=https://dockmon.forust.xyz/ - glance.url=https://dockmon.forust.xyz/
- glance.description=Dockmon is a lightweight Docker container monitoring and management tool with a user-friendly web interface. - glance.description=Dockmon is a lightweight Docker container monitoring and management tool with a user-friendly web interface.
networks: networks:
- proxy - proxy
volumes: volumes:
data: data:
networks: networks:
proxy: proxy:
external: true external: true
View File
Whitespace-only changes.
+1 -1
View File
@@ -29,7 +29,7 @@ spec:
spec: spec:
containers: containers:
- name: dockmon - name: dockmon
image: darthnorse/dockmon:latest image: darthnorse/dockmon:2.4.5
ports: ports:
- containerPort: 443 - containerPort: 443
volumeMounts: volumeMounts:
+4 -3
View File
@@ -15,9 +15,11 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^dockmon\.forust\.xyz$`) - match: Host(`dockmon.forust.xyz`)
kind: Rule kind: Rule
middlewares: middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
- name: security-headers@file - name: security-headers@file
services: services:
- name: dockmon-service - name: dockmon-service
@@ -35,10 +37,9 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^dockmon\.(workstation|gigaforust)\.internal$`) - match: Host(`dockmon.workstation.internal`) || Host(`dockmon.gigaforust.internal`)
kind: Rule kind: Rule
services: services:
- name: dockmon-service - name: dockmon-service
port: 443 port: 443
serversTransport: dockmon-transport serversTransport: dockmon-transport
+3 -3
View File
@@ -1,7 +1,7 @@
services: services:
downtify: downtify:
container_name: downtify container_name: downtify
image: ghcr.io/henriquesebastiao/downtify:latest image: ghcr.io/henriquesebastiao/downtify:2.13.0
restart: unless-stopped restart: unless-stopped
# ports: # ports:
# - '7077:8000' # - '7077:8000'
@@ -11,11 +11,11 @@ services:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.services.downtify.loadbalancer.server.port=8000" - "traefik.http.services.downtify.loadbalancer.server.port=8000"
# Prod Router # Prod Router
- "traefik.http.routers.downtify.rule=Host(`downtify.forust.xyz`)" - "traefik.http.routers.downtify.rule=Host(`downtify.forust.xyz`)"
- "traefik.http.routers.downtify.entrypoints=websecure" - "traefik.http.routers.downtify.entrypoints=websecure"
- "traefik.http.routers.downtify.middlewares=security-chain@file" - "traefik.http.routers.downtify.middlewares=security-chain@file"
- "traefik.http.routers.downtify.tls=true" - "traefik.http.routers.downtify.tls.certresolver=letsencrypt"
# Local Router # Local Router
- "traefik.http.routers.downtify-local.rule=Host(`downtify.workstation.internal`)" - "traefik.http.routers.downtify-local.rule=Host(`downtify.workstation.internal`)"
- "traefik.http.routers.downtify-local.entrypoints=websecure" - "traefik.http.routers.downtify-local.entrypoints=websecure"
+1 -1
View File
@@ -27,7 +27,7 @@ spec:
spec: spec:
containers: containers:
- name: downtify - name: downtify
image: ghcr.io/henriquesebastiao/downtify:latest image: ghcr.io/henriquesebastiao/downtify:2.13.0
ports: ports:
- containerPort: 8000 - containerPort: 8000
volumeMounts: volumeMounts:
+4 -3
View File
@@ -7,9 +7,11 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^downtify\.forust\.xyz$`) - match: Host(`downtify.forust.xyz`)
kind: Rule kind: Rule
middlewares: middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
- name: security-chain@file - name: security-chain@file
services: services:
- name: downtify-service - name: downtify-service
@@ -26,9 +28,8 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^downtify\.(workstation|gigaforust)\.internal$`) - match: Host(`downtify.workstation.internal`) || Host(`downtify.gigaforust.internal`)
kind: Rule kind: Rule
services: services:
- name: downtify-service - name: downtify-service
port: 8000 port: 8000
+388 -418
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -9,5 +9,6 @@ WEBINAR_CHECK_INTERVAL=60
REDIS_HOST=redis REDIS_HOST=redis
REDIS_PORT=6379 REDIS_PORT=6379
PLAYWRIGHT_WS=ws://playwright-service:3000/ws PLAYWRIGHT_WS=ws://playwright-service:3000/ws
TZ=Europe/Kyiv
WEBINAR_TELEGRAM_TOKEN=your_telegram_bot_token_here WEBINAR_TELEGRAM_TOKEN=your_telegram_bot_token_here
WEBINAR_ADMIN_ID=123456789 WEBINAR_ADMIN_ID=123456789
+4 -4
View File
@@ -1,17 +1,17 @@
services: services:
redis: redis:
image: redis:alpine image: redis:8.10.1-alpine
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- redis-data:/data - redis-data:/data
healthcheck: healthcheck:
test: [ "CMD", "redis-cli", "ping" ] test: ["CMD", "redis-cli", "ping"]
interval: 5s interval: 5s
timeout: 3s timeout: 3s
retries: 5 retries: 5
playwright-service: playwright-service:
image: mcr.microsoft.com/playwright:v1.56.0-jammy image: mcr.microsoft.com/playwright:v1.63.0-jammy
restart: unless-stopped restart: unless-stopped
command: npx -y playwright@1.56.0 run-server --port 3000 --path /ws command: npx -y playwright@1.56.0 run-server --port 3000 --path /ws
@@ -25,7 +25,7 @@ services:
redis: redis:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
test: [ "CMD-SHELL", "redis-cli -h redis EXISTS EDU_PHPSESSID | grep -q 1" ] test: ["CMD-SHELL", "redis-cli -h redis EXISTS EDU_PHPSESSID | grep -q 1"]
interval: 30s interval: 30s
timeout: 5s timeout: 5s
retries: 10 retries: 10
View File
Whitespace-only changes.
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: edu-master
+57
View File
@@ -0,0 +1,57 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: playwright-service
namespace: edu-master
labels:
app: edu-master-playwright
spec:
replicas: 1
selector:
matchLabels:
app: edu-master-playwright
template:
metadata:
labels:
app: edu-master-playwright
spec:
containers:
- name: playwright
image: mcr.microsoft.com/playwright:v1.63.0-jammy
imagePullPolicy: IfNotPresent
command:
- npx
- -y
- playwright@1.56.0
- run-server
- --port
- "3000"
- --path
- /ws
ports:
- containerPort: 3000
readinessProbe:
tcpSocket:
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
livenessProbe:
tcpSocket:
port: 3000
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 3
---
apiVersion: v1
kind: Service
metadata:
name: playwright-service
namespace: edu-master
spec:
selector:
app: edu-master-playwright
ports:
- name: ws
port: 3000
targetPort: 3000
+75
View File
@@ -0,0 +1,75 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
namespace: edu-master
labels:
app: edu-master-redis
spec:
serviceName: redis
replicas: 1
selector:
matchLabels:
app: edu-master-redis
template:
metadata:
labels:
app: edu-master-redis
spec:
containers:
- name: redis
image: redis:8.10.1-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6379
volumeMounts:
- name: redis-data
mountPath: /data
resources:
requests:
cpu: 25m
memory: 64Mi
limits:
cpu: 250m
memory: 256Mi
readinessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
livenessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 3
volumes:
- name: redis-data
persistentVolumeClaim:
claimName: redis-data-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-data-pvc
namespace: edu-master
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: edu-master
spec:
selector:
app: edu-master-redis
ports:
- name: redis
port: 6379
targetPort: 6379
@@ -0,0 +1,50 @@
# One-time Job to migrate redis state from docker compose to k8s (maintenance window).
# The .example file is not applied by the deploy pipeline (mask *.example.yaml).
#
# Runbook:
# 1. docker compose -f <repo>/edu_master/compose.yaml stop # SIGTERM -> redis will flush dump.rdb
# 2. docker run --rm -v edu_master_redis-data:/data \
# -v /tmp/edu-master-backup:/backup \
# redis:alpine sh -c "cp /data/dump.rdb /backup/ && ls -la /backup"
# 3. kubectl apply -f edu_master/k8s/namespace.yaml
# 4. kubectl apply -f <only the PVC from redis.yaml> # seed must come BEFORE redis pod starts
# 5. kubectl apply -f edu_master/k8s/restore-seed-job.yaml.example
# kubectl wait --for=condition=complete job/redis-restore-seed -n edu-master --timeout=120s
# 6. kubectl delete job redis-restore-seed -n edu-master
# 7. kubectl apply -f edu_master/k8s/ -R # apply remaining manifests
apiVersion: batch/v1
kind: Job
metadata:
name: redis-restore-seed
namespace: edu-master
spec:
backoffLimit: 2
ttlSecondsAfterFinished: 3600
template:
spec:
restartPolicy: Never
containers:
- name: seed
image: redis:alpine
command:
- /bin/sh
- -ec
- |
ls -la /backup
cp /backup/dump.rdb /data/dump.rdb
chmod 644 /data/dump.rdb
ls -la /data
volumeMounts:
- name: redis-data
mountPath: /data
- name: backup
mountPath: /backup
readOnly: true
volumes:
- name: redis-data
persistentVolumeClaim:
claimName: redis-data-pvc
- name: backup
hostPath:
path: /tmp/edu-master-backup
type: DirectoryOrCreate
+27
View File
@@ -0,0 +1,27 @@
apiVersion: v1
kind: Secret
metadata:
name: edu-master-secrets
namespace: edu-master
type: Opaque
stringData:
# Session keeper credentials
KEEPER_LOGIN: ""
KEEPER_PASSWORD: ""
KEEPER_INTERVAL: "10"
# EDU links
EDU_URL_BASE: "https://edu.edu.vn.ua"
EDU_URL_LOGIN: "/user/login"
EDU_URL_COURSES: "/course/userlist"
EDU_URL_WEBINAR: "/webinar/useractive"
# Playwright
USER_AGENT: ""
PLAYWRIGHT_WS: "ws://playwright-service:3000/ws"
# Webinar-checker
WEBINAR_TELEGRAM_TOKEN: ""
WEBINAR_ADMIN_ID: ""
WEBINAR_CHECK_INTERVAL: "60"
# Database
REDIS_HOST: "redis"
REDIS_PORT: "6379"
TZ: "Europe/Kyiv"
+52
View File
@@ -0,0 +1,52 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: session-keeper
namespace: edu-master
labels:
app: edu-master-session-keeper
spec:
replicas: 1
selector:
matchLabels:
app: edu-master-session-keeper
template:
metadata:
labels:
app: edu-master-session-keeper
spec:
initContainers:
- name: wait-redis
image: redis:8.10.1-alpine
command:
- /bin/sh
- -ec
- |
i=0
until redis-cli -h redis ping | grep -q PONG; do
i=$((i+1))
[ "$i" -ge 300 ] && echo "TIMEOUT: redis not ready" && exit 1
sleep 2
done
echo "redis is ready"
containers:
- name: session-keeper
image: gcr.forust.xyz/forust/session-keeper:latest
imagePullPolicy: Always
envFrom:
- secretRef:
name: edu-master-secrets
resources:
requests:
cpu: 25m
memory: 96Mi
limits:
cpu: 250m
memory: 256Mi
readinessProbe:
exec:
command: ["/bin/sh", "-ec", "redis-cli -h redis EXISTS EDU_PHPSESSID | grep -q 1"]
initialDelaySeconds: 15
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 10
+62
View File
@@ -0,0 +1,62 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: webinar-checker
namespace: edu-master
labels:
app: edu-master-webinar-checker
spec:
replicas: 1
selector:
matchLabels:
app: edu-master-webinar-checker
template:
metadata:
labels:
app: edu-master-webinar-checker
spec:
# Enforces dependency order like compose depends_on:
# redis healthy -> session-keeper healthy (EXISTS EDU_PHPSESSID) -> playwright started
initContainers:
- name: wait-deps
image: redis:8.10.1-alpine
command:
- /bin/sh
- -ec
- |
i=0
until redis-cli -h redis ping | grep -q PONG; do
i=$((i+1))
[ "$i" -ge 300 ] && echo "TIMEOUT: redis not ready" && exit 1
sleep 2
done
echo "redis ok"
until [ "$(redis-cli -h redis EXISTS EDU_PHPSESSID)" = "1" ]; do
i=$((i+1))
[ "$i" -ge 300 ] && echo "TIMEOUT: no PHPSESSID (session-keeper down?)" && exit 1
sleep 2
done
echo "PHPSESSID ok"
until nc -z playwright-service 3000; do
i=$((i+1))
[ "$i" -ge 300 ] && echo "TIMEOUT: playwright-service not reachable" && exit 1
sleep 2
done
echo "playwright ok"
containers:
- name: webinar-checker
image: gcr.forust.xyz/forust/webinar-checker:latest
imagePullPolicy: Always
envFrom:
- secretRef:
name: edu-master-secrets
env:
- name: TZ
value: "Europe/Kyiv"
resources:
requests:
cpu: "50m"
memory: "128Mi"
limits:
cpu: "600m"
memory: "512Mi"
+2 -2
View File
@@ -3,10 +3,10 @@ FROM python:3.11-slim
WORKDIR /app WORKDIR /app
# Install system dependencies # 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 # 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 application code
COPY . . COPY . .
+46 -43
View File
@@ -1,17 +1,16 @@
import logging
import os import os
import time import time
import requests
import logging
import redis
from datetime import datetime from datetime import datetime
import redis
import requests
# Configure logging # Configure logging
logging.basicConfig( logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Load configuration (adapted to .env keys) # Load configuration (adapted to .env keys)
def _env(key, default=None): def _env(key, default=None):
v = os.getenv(key, default) v = os.getenv(key, default)
@@ -19,21 +18,26 @@ def _env(key, default=None):
return v[1:-1] return v[1:-1]
return v return v
LOGIN = _env('KEEPER_LOGIN') LOGIN = _env('KEEPER_LOGIN')
PASSWORD = _env('KEEPER_PASSWORD') PASSWORD = _env('KEEPER_PASSWORD')
EDU_BASE = _env('EDU_URL_BASE', 'https://edu.edu.vn.ua') EDU_BASE = _env('EDU_URL_BASE', 'https://edu.edu.vn.ua')
EDU_LOGIN_PATH = _env('EDU_URL_LOGIN', '/user/login') EDU_LOGIN_PATH = _env('EDU_URL_LOGIN', '/user/login')
EDU_COURSES_PATH = _env('EDU_URL_COURSES', '/course/userlist') EDU_COURSES_PATH = _env('EDU_URL_COURSES', '/course/userlist')
URL_LOGIN = f"{EDU_BASE.rstrip('/')}/{EDU_LOGIN_PATH.lstrip('/')}" URL_LOGIN = f'{EDU_BASE.rstrip("/")}/{EDU_LOGIN_PATH.lstrip("/")}'
URL_VERIFY = f"{EDU_BASE.rstrip('/')}/{EDU_COURSES_PATH.lstrip('/')}" URL_VERIFY = f'{EDU_BASE.rstrip("/")}/{EDU_COURSES_PATH.lstrip("/")}'
INTERVAL = int(_env('KEEPER_INTERVAL', 10)) 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_HOST = _env('REDIS_HOST', 'redis')
REDIS_PORT = int(_env('REDIS_PORT', 6379)) REDIS_PORT = int(_env('REDIS_PORT', 6379))
SUCCESS_FILE = '/tmp/last_success' SUCCESS_FILE = '/tmp/last_success' # noqa: S108
def touch_success_file(): def touch_success_file():
"""Updates the timestamp of the success file for healthchecks.""" """Updates the timestamp of the success file for healthchecks."""
@@ -41,22 +45,23 @@ def touch_success_file():
with open(SUCCESS_FILE, 'w') as f: with open(SUCCESS_FILE, 'w') as f:
f.write(str(datetime.now().timestamp())) f.write(str(datetime.now().timestamp()))
except Exception as e: except Exception as e:
logger.error(f"Failed to touch success file: {e}") logger.error(f'Failed to touch success file: {e}')
def main(): def main():
logger.info("Starting Session Keeper Bot") logger.info('Starting Session Keeper Bot')
# Connect to Redis # Connect to Redis
try: try:
redis_client = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, decode_responses=True) redis_client = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, decode_responses=True)
redis_client.ping() 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: except Exception as e:
logger.error(f"Failed to connect to Redis: {e}") logger.error(f'Failed to connect to Redis: {e}')
return return
session = requests.Session() session = requests.Session()
# Set headers # Set headers
headers = { headers = {
'User-Agent': USER_AGENT, 'User-Agent': USER_AGENT,
@@ -72,58 +77,56 @@ def main():
'Sec-Ch-Ua-Mobile': '?0', 'Sec-Ch-Ua-Mobile': '?0',
'Sec-Ch-Ua-Platform': '"Linux"', 'Sec-Ch-Ua-Platform': '"Linux"',
'Accept-Encoding': 'gzip, deflate, br', 'Accept-Encoding': 'gzip, deflate, br',
'Priority': 'u=0, i' 'Priority': 'u=0, i',
} }
session.headers.update(headers) session.headers.update(headers)
while True: while True:
try: try:
logger.info("Attempting login...") logger.info('Attempting login...')
# Login payload # Login payload
payload = { payload = {'login': LOGIN, 'password': PASSWORD}
'login': LOGIN,
'password': PASSWORD
}
# Perform Login # Perform Login
# Note: The user request shows a POST to /user/login with form data # Note: The user request shows a POST to /user/login with form data
# We need to make sure we handle the PHPSESSID correctly. # We need to make sure we handle the PHPSESSID correctly.
# If we already have a PHPSESSID, requests will send it. # If we already have a PHPSESSID, requests will send it.
login_response = session.post(URL_LOGIN, data=payload, allow_redirects=True) login_response = session.post(URL_LOGIN, data=payload, allow_redirects=True)
logger.info(f"Login Response Status: {login_response.status_code}") logger.info(f'Login Response Status: {login_response.status_code}')
logger.info(f"Cookies after login: {session.cookies.get_dict()}") logger.info(f'Cookies after login: {session.cookies.get_dict()}')
# Verify Session # Verify Session
logger.info("Verifying session...") logger.info('Verifying session...')
verify_response = session.get(URL_VERIFY, allow_redirects=False) 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: if verify_response.status_code == 200:
logger.info("Session verification SUCCESS (200 OK).") logger.info('Session verification SUCCESS (200 OK).')
touch_success_file() touch_success_file()
# Save PHPSESSID to Redis # Save PHPSESSID to Redis
phpsessid = session.cookies.get('PHPSESSID') phpsessid = session.cookies.get('PHPSESSID')
if phpsessid: if phpsessid:
try: try:
redis_client.set('EDU_PHPSESSID', phpsessid) 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: 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: 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: 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: 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) time.sleep(INTERVAL * 60)
if __name__ == "__main__":
if __name__ == '__main__':
main() main()
+1 -1
View File
@@ -3,7 +3,7 @@ FROM python:3.11-slim
WORKDIR /app WORKDIR /app
# Install dependencies # 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 . COPY checker.py .
File diff suppressed because it is too large. Load diff
+4 -5
View File
@@ -1,6 +1,6 @@
services: services:
server: server:
image: docker.gitea.com/gitea:1.26 image: docker.gitea.com/gitea:1.27.3
container_name: gitea container_name: gitea
restart: always restart: always
environment: environment:
@@ -12,7 +12,7 @@ services:
- GITEA__database__USER=gitea - GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea - GITEA__database__PASSWD=gitea
- GITEA__database__NAME=gitea - GITEA__database__NAME=gitea
#Server # Server
- GITEA__server__ROOT_URL=https://gitea.forust.xyz - GITEA__server__ROOT_URL=https://gitea.forust.xyz
- GITEA__server__SSH_DOMAIN=gitssh.forust.xyz - GITEA__server__SSH_DOMAIN=gitssh.forust.xyz
- GITEA__server__SSH_PORT=2221 - GITEA__server__SSH_PORT=2221
@@ -36,7 +36,7 @@ services:
# Prod Router # Prod Router
- "traefik.http.routers.gitea.rule=Host(`gitea.forust.xyz`)" - "traefik.http.routers.gitea.rule=Host(`gitea.forust.xyz`)"
- "traefik.http.routers.gitea.entrypoints=websecure" - "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls=true" - "traefik.http.routers.gitea.tls.certresolver"
# Local Router # Local Router
- "traefik.http.routers.gitea-local.rule=Host(`gitea.workstation.internal`)" - "traefik.http.routers.gitea-local.rule=Host(`gitea.workstation.internal`)"
- "traefik.http.routers.gitea-local.entrypoints=websecure" - "traefik.http.routers.gitea-local.entrypoints=websecure"
@@ -53,7 +53,6 @@ services:
- "traefik.http.routers.gitea-registry.rule=Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)" - "traefik.http.routers.gitea-registry.rule=Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)"
- "traefik.http.routers.gitea-registry.entrypoints=websecure" - "traefik.http.routers.gitea-registry.entrypoints=websecure"
- "traefik.http.routers.gitea-registry.tls.certresolver=letsencrypt" - "traefik.http.routers.gitea-registry.tls.certresolver=letsencrypt"
- "traefik.http.routers.gitea-registry.tls=true"
ports: ports:
- "2221:22" - "2221:22"
networks: networks:
@@ -62,7 +61,7 @@ services:
depends_on: depends_on:
- db - db
db: db:
image: docker.io/library/postgres:14 image: docker.io/library/postgres:14.24-alpine
restart: always restart: always
environment: environment:
- POSTGRES_USER=gitea - POSTGRES_USER=gitea
View File
Whitespace-only changes.
+3 -1
View File
@@ -10,11 +10,13 @@ data:
GITEA__server__SSH_PORT: "2221" GITEA__server__SSH_PORT: "2221"
GITEA__database__DB_TYPE: "postgres" GITEA__database__DB_TYPE: "postgres"
GITEA__database__HOST: "gitea-postgres-service:5432" GITEA__database__HOST: "postgres.database.svc.cluster.local:5432"
GITEA__database__NAME: "gitea" GITEA__database__NAME: "gitea"
GITEA__security__REVERSE_PROXY_LIMIT: "1" GITEA__security__REVERSE_PROXY_LIMIT: "1"
GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES: "*" GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES: "*"
GITEA__mailer__ENABLED: "false" GITEA__mailer__ENABLED: "false"
GITEA__log__logger.access.MODE: "console, file"
USER_UID: "1000" USER_UID: "1000"
USER_GID: "1000" USER_GID: "1000"
+1 -1
View File
@@ -31,7 +31,7 @@ spec:
spec: spec:
containers: containers:
- name: gitea - name: gitea
image: docker.gitea.com/gitea:1.26 image: docker.gitea.com/gitea:1.27.3
envFrom: envFrom:
- configMapRef: - configMapRef:
name: gitea-config name: gitea-config
@@ -7,8 +7,19 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^gitea\.forust\.xyz$`) - match: Host(`gitea.forust.xyz`)
kind: Rule kind: Rule
middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
services:
- name: gitea-service
port: 3000
- match: Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)
kind: Rule
middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
services: services:
- name: gitea-service - name: gitea-service
port: 3000 port: 3000
@@ -24,29 +35,16 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^gitea\.(workstation|gigaforust)\.internal$`) - match: Host(`gitea.workstation.internal`) || Host(`gitea.gigaforust.internal`)
kind: Rule kind: Rule
services: services:
- name: gitea-service - name: gitea-service
port: 3000 port: 3000
- match: (Host(`gcr.workstation.internal`) || Host(`gcr.gigaforust.internal`)) && PathPrefix(`/v2`)
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: gitea-registry
namespace: gitea
spec:
entryPoints:
- websecure
routes:
- match: Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)
kind: Rule kind: Rule
services: services:
- name: gitea-service - name: gitea-service
port: 3000 port: 3000
tls:
certResolver: letsencrypt
--- ---
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP kind: IngressRouteTCP
-62
View File
@@ -1,62 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: gitea-postgres-service
namespace: gitea
spec:
clusterIP: None
selector:
app: gitea-postgres
ports:
- port: 5432
targetPort: 5432
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: gitea-postgres-statefulset
namespace: gitea
spec:
selector:
matchLabels:
app: gitea-postgres
serviceName: gitea-postgres-service
replicas: 1
template:
metadata:
labels:
app: gitea-postgres
spec:
containers:
- name: gitea-postgres
image: postgres:14
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: gitea-secrets
key: GITEA__database__USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: gitea-secrets
key: GITEA__database__PASSWD
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: gitea-secrets
key: GITEA__database__USER
ports:
- containerPort: 5432
name: postgres
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
+1
View File
@@ -7,3 +7,4 @@ type: Opaque
stringData: stringData:
GITEA__database__USER: "gitea" GITEA__database__USER: "gitea"
GITEA__database__PASSWD: "gitea" GITEA__database__PASSWD: "gitea"
GITEA__database__NAME: "gitea"
+9 -6
View File
@@ -1,7 +1,7 @@
services: services:
glance: glance:
container_name: glance container_name: glance
image: glanceapp/glance image: glanceapp/glance:v0.8.6
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./config:/app/config:ro - ./config:/app/config:ro
@@ -15,19 +15,22 @@ services:
- "traefik.services.glance.loadbalancer.server.port=8080" - "traefik.services.glance.loadbalancer.server.port=8080"
# Prod Router # 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.entrypoints=websecure"
- "traefik.http.routers.glance.tls=true" - "traefik.http.routers.glance.priority=50"
- "traefik.http.routers.glance.tls.certresolver=letsencrypt"
# Local Router # 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.entrypoints=websecure"
- "traefik.http.routers.glance-local.priority=50"
- "traefik.http.routers.glance-local.tls=true" - "traefik.http.routers.glance-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.glance-dev.rule=Host(`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.entrypoints=websecure"
- "traefik.http.routers.glance-dev.priority=50"
- "traefik.http.routers.glance-dev.tls=true" - "traefik.http.routers.glance-dev.tls=true"
networks: networks:
- proxy - proxy
networks: networks:
proxy: proxy:
external: true external: true
-1
View File
@@ -64,7 +64,6 @@
name: Apple name: Apple
- symbol: MSFT - symbol: MSFT
name: Microsoft name: Microsoft
- type: releases - type: releases
cache: 1d cache: 1d
+11 -13
View File
@@ -1,15 +1,13 @@
- name: Monitoring - name: Monitoring
columns: columns:
- size: small - size: small
widgets: widgets:
- type: dns-stats - type: dns-stats
service: adguard service: adguard
url: http://adguardhome:3000 url: http://adguardhome:3000
username: forust username: forust
password: ${ADGUARD_PASSWORD} password: ${ADGUARD_PASSWORD}
- size: full - size: full
widgets: widgets:
- type: docker-containers - type: docker-containers
hide-by-default: false hide-by-default: false
View File
Whitespace-only changes.
+2
View File
@@ -56,6 +56,8 @@ data:
glance.yml: | glance.yml: |
server: server:
assets-path: /app/assets assets-path: /app/assets
proxied: true
base-url: /glance
theme: theme:
# Перевели #050505 и #e0e0e0 в формат HSL для Glance # Перевели #050505 и #e0e0e0 в формат HSL для Glance
background-color: 0 0 2 # Истинно черный фон background-color: 0 0 2 # Истинно черный фон
+5 -5
View File
@@ -27,7 +27,7 @@ spec:
spec: spec:
containers: containers:
- name: glance - name: glance
image: glanceapp/glance image: glanceapp/glance:v0.8.6
envFrom: envFrom:
- secretRef: - secretRef:
name: glance-secrets name: glance-secrets
@@ -56,11 +56,11 @@ spec:
readOnly: true readOnly: true
resources: resources:
requests: requests:
memory: "10Mi"
cpu: "20m"
limits:
memory: "100Mi"
cpu: "50m" cpu: "50m"
memory: "64Mi"
limits:
cpu: "200m"
memory: "256Mi"
volumes: volumes:
- name: glance-config - name: glance-config
configMap: configMap:
+17 -5
View File
@@ -7,10 +7,11 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^forust\.xyz$`) - match: (Host(`forust.xyz`) || Host(`www.forust.xyz`)) && PathPrefix(`/glance`)
kind: Rule kind: Rule
priority: 50
middlewares: middlewares:
- name: glance-strupprefix - name: glance-stripprefix
services: services:
- name: glance-service - name: glance-service
port: 8080 port: 8080
@@ -26,10 +27,21 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^glance\.(workstation|gigaforust)\.internal$`) - match: (Host(`glance.workstation.internal`) || Host(`glance.gigaforust.internal`)) && PathPrefix(`/glance`)
kind: Rule kind: Rule
middlewares:
- name: glance-stripprefix
priority: 50
services: services:
- name: glance-service - name: glance-service
port: 8080 port: 8080
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: glance-stripprefix
namespace: glance
spec:
stripPrefix:
prefixes:
- /glance
+40 -6
View File
@@ -1,6 +1,6 @@
services: services:
headscale: headscale:
image: headscale/headscale:latest image: headscale/headscale:0.29.3
restart: unless-stopped restart: unless-stopped
container_name: headscale-server container_name: headscale-server
command: serve command: serve
@@ -24,7 +24,7 @@ services:
- "traefik.http.routers.headscale.rule=Host(`hs.forust.xyz`)" - "traefik.http.routers.headscale.rule=Host(`hs.forust.xyz`)"
- "traefik.http.routers.headscale.entrypoints=websecure" - "traefik.http.routers.headscale.entrypoints=websecure"
- "traefik.http.routers.headscale.service=headscale" - "traefik.http.routers.headscale.service=headscale"
- "traefik.http.routers.headscale.tls=true" - "traefik.http.routers.headscale.tls.certresolver=letsencrypt"
# Local Router # Local Router
- "traefik.http.routers.headscale-local.rule=Host(`hs.workstation.internal`)" - "traefik.http.routers.headscale-local.rule=Host(`hs.workstation.internal`)"
- "traefik.http.routers.headscale-local.entrypoints=websecure" - "traefik.http.routers.headscale-local.entrypoints=websecure"
@@ -53,11 +53,11 @@ services:
- "traefik.http.routers.headscale-metrics-dev.service=headscale-metrics" - "traefik.http.routers.headscale-metrics-dev.service=headscale-metrics"
- "traefik.http.routers.headscale-metrics-dev.tls=true" - "traefik.http.routers.headscale-metrics-dev.tls=true"
headplane: headplane:
image: ghcr.io/tale/headplane:latest image: ghcr.io/tale/headplane:0.7.1
container_name: headplane container_name: headplane
restart: unless-stopped restart: unless-stopped
ports: ports:
- '13000:3000' - "13000:3000"
volumes: volumes:
- ./config/headplane.yaml:/etc/headplane/config.yaml - ./config/headplane.yaml:/etc/headplane/config.yaml
- ./config/headscale.yaml:/etc/headscale/config.yaml - ./config/headscale.yaml:/etc/headscale/config.yaml
@@ -65,8 +65,42 @@ services:
- /var/run/docker.sock:/var/run/docker.sock:ro - /var/run/docker.sock:/var/run/docker.sock:ro
networks: networks:
- proxy - 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: web:
image: goodieshq/headscale-admin:latest image: goodieshq/headscale-admin:0.28.0
restart: unless-stopped restart: unless-stopped
ports: ports:
- 10080:80 - 10080:80
@@ -78,7 +112,7 @@ services:
- "traefik.http.routers.headscale-ui.rule=Host(`hs.forust.xyz`) && PathPrefix(`/admin`)" - "traefik.http.routers.headscale-ui.rule=Host(`hs.forust.xyz`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headscale-ui.entrypoints=websecure" - "traefik.http.routers.headscale-ui.entrypoints=websecure"
- "traefik.http.routers.headscale-ui.middlewares=security-chain@file" - "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 # Local Router
- "traefik.http.routers.headscale-ui-local.rule=Host(`hs.workstation.internal`) && PathPrefix(`/admin`)" - "traefik.http.routers.headscale-ui-local.rule=Host(`hs.workstation.internal`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headscale-ui-local.entrypoints=websecure" - "traefik.http.routers.headscale-ui-local.entrypoints=websecure"
+3 -2
View File
@@ -33,7 +33,9 @@ derp:
auto_update_enabled: true auto_update_enabled: true
update_frequency: 24h update_frequency: 24h
disable_check_updates: false disable_check_updates: false
ephemeral_node_inactivity_timeout: 30m node:
ephemeral:
inactivity_timeout: 30m
database: database:
type: sqlite type: sqlite
debug: false debug: false
@@ -76,4 +78,3 @@ unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770" unix_socket_permission: "0770"
logtail: logtail:
enabled: false enabled: false
randomize_client_port: false
+20 -25
View File
@@ -1,26 +1,21 @@
{ {
"groups": { "groups": {
"group:admin": [ "group:admin": ["admin@"],
"admin@" "group:users": []
], },
"group:users": [] "tagOwners": {},
}, "hosts": {},
"tagOwners": {}, "acls": [
"hosts": {}, {
"acls": [ "randomizeClientPort": false,
{ "#ha-meta": {
"#ha-meta": { "name": "users",
"name": "users", "open": true
"open": true },
}, "action": "accept",
"action": "accept", "src": ["autogroup:member"],
"src": [ "dst": ["autogroup:self:*"]
"autogroup:member" }
], ],
"dst": [ "ssh": []
"autogroup:self:*" }
]
}
],
"ssh": []
}
-101
View File
@@ -1,101 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-server-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.forust\.xyz$`)
kind: Rule
services:
- name: headscale-server-external
port: 8080
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-server-local
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`)
kind: Rule
services:
- name: headscale-server-external
port: 8080
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-ui-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.forust\.xyz$`) && PathPrefix(`/admin`)
kind: Rule
middlewares:
- name: security-chain@file
services:
- name: headscale-ui-external
port: 80
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-ui-local
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`) && PathPrefix(`/admin`)
kind: Rule
services:
- name: headscale-ui-external
port: 80
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-metrics-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.forust\.xyz$`) && PathPrefix(`/metrics`)
kind: Rule
services:
- name: headscale-server-external
port: 9090
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-metrics-local
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`) && PathPrefix(`/metrics`)
kind: Rule
services:
- name: headscale-server-external
port: 9090
@@ -57,3 +57,30 @@ ports:
endpoints: endpoints:
- addresses: - addresses:
- "192.168.88.100" - "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"
+112
View File
@@ -0,0 +1,112 @@
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: headplane-prefix
namespace: headscale
spec:
addPrefix:
prefix: "/admin"
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: Host(`hs.forust.xyz`)
kind: Rule
services:
- name: headscale-server-external
port: 8080
- match: Host(`hs.forust.xyz`) && PathPrefix(`/admin`)
kind: Rule
middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
services:
- name: headscale-ui-external
port: 80
- match: Host(`hs.forust.xyz`) && PathPrefix(`/metrics`)
kind: Rule
middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
services:
- name: headscale-server-external
port: 9090
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headplane-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: Host(`hp.forust.xyz`)
kind: Rule
middlewares:
- name: headplane-prefix
- name: crowdsec-bouncer
namespace: crowdsec
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 # Prod Router
- "traefik.http.routers.forust-homepage.rule=Host(`forust.xyz`) || Host(`www.forust.xyz`)" - "traefik.http.routers.forust-homepage.rule=Host(`forust.xyz`) || Host(`www.forust.xyz`)"
- "traefik.http.routers.forust-homepage.entrypoints=websecure" - "traefik.http.routers.forust-homepage.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 # Local Router
- "traefik.http.routers.forust-homepage-local.rule=Host(`landing.workstation.internal`)" - "traefik.http.routers.forust-homepage-local.rule=Host(`landing.workstation.internal`)"
- "traefik.http.routers.forust-homepage-local.entrypoints=websecure" - "traefik.http.routers.forust-homepage-local.entrypoints=websecure"
- "traefik.http.routers.forust-homepage-local.priority=10"
- "traefik.http.routers.forust-homepage-local.tls=true" - "traefik.http.routers.forust-homepage-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.forust-homepage-dev.rule=Host(`landing.gigaforust.internal`)" - "traefik.http.routers.forust-homepage-dev.rule=Host(`landing.gigaforust.internal`)"
- "traefik.http.routers.forust-homepage-dev.entrypoints=websecure" - "traefik.http.routers.forust-homepage-dev.entrypoints=websecure"
- "traefik.http.routers.forust-homepage-dev.priority=10"
- "traefik.http.routers.forust-homepage-dev.tls=true" - "traefik.http.routers.forust-homepage-dev.tls=true"
xdfnx: xdfnx:
build: build:
@@ -47,7 +50,6 @@ services:
- "traefik.http.routers.xdfnx.rule=Host(`xdfnx.cfd`) || Host(`www.xdfnx.cfd`)" - "traefik.http.routers.xdfnx.rule=Host(`xdfnx.cfd`) || Host(`www.xdfnx.cfd`)"
- "traefik.http.routers.xdfnx.entrypoints=websecure" - "traefik.http.routers.xdfnx.entrypoints=websecure"
- "traefik.http.routers.xdfnx.tls.certresolver=letsencrypt" - "traefik.http.routers.xdfnx.tls.certresolver=letsencrypt"
- "traefik.http.routers.xdfnx.tls=true"
# Local Router # Local Router
- "traefik.http.routers.xdfnx-local.rule=Host(`xdfnx.workstation.internal`)" - "traefik.http.routers.xdfnx-local.rule=Host(`xdfnx.workstation.internal`)"
- "traefik.http.routers.xdfnx-local.entrypoints=websecure" - "traefik.http.routers.xdfnx-local.entrypoints=websecure"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 53 KiB

+211 -182
View File
@@ -1,196 +1,225 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head>
<head> <meta charset="UTF-8" />
<meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MrForust // XRock</title> <title>MrForust // XRock</title>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script> <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="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="assets/css/style.css" />
</head> </head>
<body>
<body>
<div class="container"> <div class="container">
<header> <header>
<h1 class="glitch" data-text="MrForust">Mr-Forust</h1> <h1 class="glitch" data-text="MrForust">Mr-Forust</h1>
<p class="subtitle">> CTF Player / XRock_Team / Just Signal.</p> <p class="subtitle">> CTF Player / XRock_Team / Just Signal.</p>
</header> </header>
<hr> <hr />
<section id="socials"> <div class="grid-2">
<h2>./socials</h2> <section id="contacts">
<ul class="link-list"> <h2>./contacts</h2>
<li> <ul class="link-list">
<i class="fab fa-github"></i> <li>
<a href="https://github.com/mr-forust" target="_blank">github/mr-forust</a> <i class="fab fa-github"></i>
</li> <a href="https://github.com/mr-forust" target="_blank">github/mr-forust</a>
<li> </li>
<i class="fas fa-flag"></i> <li>
<a href="https://tryhackme.com/p/MrForust" target="_blank">tryhackme/MrForust</a> <i class="fas fa-flag"></i>
</li> <a href="https://tryhackme.com/p/MrForust" target="_blank">tryhackme/MrForust</a>
<li> </li>
<i class="fab fa-telegram-plane"></i> <li>
<a href="https://t.me/MrForust" target="_blank">telegram/MrForust</a> <i class="fab fa-telegram-plane"></i>
</li> <a href="https://t.me/MrForust" target="_blank">telegram/MrForust</a>
<li> </li>
<i class="fab fa-discord"></i> <li>
<span>discord/mr.forust</span> <i class="fab fa-discord"></i>
</li> <span>discord/mr.forust</span>
<li> </li>
<i class="fas fa-envelope"></i> <li>
<a href="mailto:contact@forust.xyz">mail/contact@forust.xyz</a> <i class="fas fa-envelope"></i>
</li> <a href="mailto:contact@forust.xyz">mail/contact@forust.xyz</a>
<li> </li>
<i class="fa fa-pie-chart"></i> <li>
<a href="https://forust.xyz/glance">forust/dashboard</a> <i class="fa-solid fa-key"></i>
</li> <a href=".well-known/pgp-key.asc">security/PGP Key</a>
<li> </li>
<i class="fa fa-refresh"></i> <li>
<a href="https://forust.xyz/convert">forust/converter</a> <p class="comment"># PGP Key Fingerprint: A777 7CB7 D9C4 0A97 443D CCF0 7A3D A455 F820 5B82</p>
</li> </li>
<li> </ul>
<i class="fa-solid fa-key"></i>
<a href=".well-known/pgp-key.asc">security/PGP Key</a>
</li>
<li>
<p class="comment"># PGP Key Fingerprint: A777 7CB7 D9C4 0A97 443D CCF0 7A3D A455 F820 5B82</p>
</li>
</ul>
</section> </section>
<section id="stack"> <section id="tools">
<h2>./skills_and_tools</h2> <h2>./tools</h2>
<div class="grid-2"> <ul class="link-list">
<div> <li>
<div class="skill-item"> <i class="fa fa-pie-chart"></i>
<span>ArchLinux # btw</span> <a href="https://forust.xyz/glance" target="_blank">forust/dashboard</a>
<span class="level">[#######...]</span> <p class="comment"># Glance dashboard</p>
</div> </li>
<div class="skill-item"> <li>
<span>Kubernetes</span> <span class="level">[###.......]</span> <i class="fa fa-refresh"></i>
</div> <a href="https://forust.xyz/convert" target="_blank">forust/converter</a>
<div class="skill-item"> <p class="comment"># ConvertX instance</p>
<span>Docker</span> <span class="level">[####......]</span> </li>
</div> <li>
<div class="skill-item"> <i class="fa-solid fa-file-pdf"></i>
<span>Docker Compose</span> <span class="level">[#####.....]</span> <a href="https://pdf.forust.xyz" target="_blank">pdf.forust.xyz</a>
</div> <p class="comment"># BentoPDF instance</p>
<div class="skill-item"> </li>
<span>Web Pentest</span> <span class="level">[#####.....]</span> </ul>
</div> </section>
<div class="skill-item"> </div>
<span>Burpsuite</span> <span class="level">[#####.....]</span>
</div> <section id="stack">
<div class="skill-item"> <h2>./skills</h2>
<span>Steganography</span> <span class="level">[####......]</span> <div class="grid-2">
</div> <div>
</div> <div class="skill-item">
<div> <span>ArchLinux # btw</span>
<div class="skill-item"> <span class="level">[#######...]</span>
<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> </div>
</section> <div class="skill-item"><span>Kubernetes</span> <span class="level">[###.......]</span></div>
<div class="skill-item"><span>Docker</span> <span class="level">[####......]</span></div>
<section id="team"> <div class="skill-item">
<h2>./xrock_team</h2> <span>Docker Compose</span>
<p class="comment"># It's a select caste. Cybershamans. Cryptoanarchists. Shadows on the net..</p> <span class="level">[#####.....]</span>
<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>
<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>
<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>
<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>
<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>
<a href="https://xdfnx.cfd" target="_blank">xdfnx</a>
</div>
</div> </div>
</section> <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>
</div>
</section>
<section id="repos"> <section id="team">
<h2>./favorite_repos</h2> <h2>./xrock_team</h2>
<ul class="repo-list"> <p class="comment"># It's a select caste. Cybershamans. Cryptoanarchists. Shadows on the net..</p>
<li>
<a href="https://github.com/TDesktop-x64/tdesktop" target="_blank">TDesktop-x64/tdesktop</a>
<span class="comment">// unofficial telegram client with some additions</span>
</li>
<li>
<a href="https://github.com/traefik/traefik" target="_blank">traefik/traefik</a>
<span class="comment">// beloved reverse-proxy</span>
</li>
<li>
<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/mountain-loop/yaak" target="_blank">mountain-loop/yaak</a>
<span class="comment">// modern, fancy api client</span>
</li>
<li>
<a href="https://github.com/pear-devs/pear-desktop" target="_blank">pear-devs/pear-desktop</a>
<span class="comment">// music client with a lot of features</span>
</li>
<li>
<a href="https://github.com/epi052/feroxbuster" target="_blank">epi052/feroxbuster</a>
<span class="comment">// directory discovery</span>
</li>
</ul>
</section>
<footer> <div class="team-grid">
<p>root@xrock:~$ cat <a href="miku.html">./miku</a></p> <div class="member">
<p>miku?</p> <div
<p>root@xrock:~$ shutdown -h now</p> class="avatar"
<p>&copy; XRock - Just Signal.</p> style="
</footer> 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(&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(&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(&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(&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">
<li>
<a href="https://github.com/TDesktop-x64/tdesktop" target="_blank">TDesktop-x64/tdesktop</a>
<span class="comment">// unofficial telegram client with some additions</span>
</li>
<li>
<a href="https://github.com/traefik/traefik" target="_blank">traefik/traefik</a>
<span class="comment">// beloved reverse-proxy</span>
</li>
<li>
<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>
</li>
<li>
<a href="https://github.com/pear-devs/pear-desktop" target="_blank">pear-devs/pear-desktop</a>
<span class="comment">// music client with a lot of features</span>
</li>
<li>
<a href="https://github.com/epi052/feroxbuster" target="_blank">epi052/feroxbuster</a>
<span class="comment">// directory discovery</span>
</li>
</ul>
</section>
<footer>
<p>root@xrock:~$ cat <a href="miku.html">./miku</a></p>
<p>miku?</p>
<p>root@xrock:~$ shutdown -h now</p>
<p>&copy; XRock - Just Signal.</p>
</footer>
</div> </div>
</body>
</body> </html>
</html>
View File
Whitespace-only changes.
+2
View File
@@ -28,6 +28,7 @@ spec:
containers: containers:
- name: forust-homepage - name: forust-homepage
image: gcr.forust.xyz/forust/forust-homepage:latest image: gcr.forust.xyz/forust/forust-homepage:latest
imagePullPolicy: Always
ports: ports:
- containerPort: 80 - containerPort: 80
resources: resources:
@@ -68,6 +69,7 @@ spec:
containers: containers:
- name: xdfnx-homepage - name: xdfnx-homepage
image: gcr.forust.xyz/forust/xdfnx-homepage:latest image: gcr.forust.xyz/forust/xdfnx-homepage:latest
imagePullPolicy: Always
ports: ports:
- containerPort: 80 - containerPort: 80
resources: resources:
+12 -5
View File
@@ -7,8 +7,12 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^(forust\.xyz|www\.forust\.xyz)$`) - match: Host(`forust.xyz`) || Host(`www.forust.xyz`)
kind: Rule kind: Rule
middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
priority: 10
services: services:
- name: forust-homepage-service - name: forust-homepage-service
port: 80 port: 80
@@ -24,8 +28,9 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^landing\.(workstation|gigaforust)\.internal$`) - match: Host(`landing.workstation.internal`) || Host(`landing.gigaforust.internal`)
kind: Rule kind: Rule
priority: 10
services: services:
- name: forust-homepage-service - name: forust-homepage-service
port: 80 port: 80
@@ -39,8 +44,11 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^(xdfnx\.cfd|www\.xdfnx\.cfd)$`) - match: Host(`xdfnx.cfd`)
kind: Rule kind: Rule
middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
services: services:
- name: xdfnx-homepage-service - name: xdfnx-homepage-service
port: 80 port: 80
@@ -56,9 +64,8 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^xdfnx\.(workstation|gigaforust)\.internal$`) - match: Host(`xdfnx.workstation.internal`) || Host(`xdfnx.gigaforust.internal`)
kind: Rule kind: Rule
services: services:
- name: xdfnx-homepage-service - name: xdfnx-homepage-service
port: 80 port: 80
File diff suppressed because it is too large. Load diff
+4 -4
View File
@@ -1,6 +1,6 @@
services: services:
kener: kener:
image: rajnandan1/kener:4.0.23 image: rajnandan1/kener:4.1.5
container_name: kener container_name: kener
restart: unless-stopped restart: unless-stopped
# ports: # ports:
@@ -23,7 +23,7 @@ services:
# Prod Router # Prod Router
- "traefik.http.routers.kener.rule=Host(`status.forust.xyz`)" - "traefik.http.routers.kener.rule=Host(`status.forust.xyz`)"
- "traefik.http.routers.kener.entrypoints=websecure" - "traefik.http.routers.kener.entrypoints=websecure"
- "traefik.http.routers.kener.tls=true" - "traefik.http.routers.kener.tls.certresolver=letsencrypt"
# Local Router # Local Router
- "traefik.http.routers.kener-local.rule=Host(`status.workstation.internal`)" - "traefik.http.routers.kener-local.rule=Host(`status.workstation.internal`)"
- "traefik.http.routers.kener-local.entrypoints=websecure" - "traefik.http.routers.kener-local.entrypoints=websecure"
@@ -36,13 +36,13 @@ services:
- proxy - proxy
- kener - kener
redis: redis:
image: redis:7-alpine image: redis:8.10.1-alpine
container_name: kener-redis container_name: kener-redis
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- redis:/data - redis:/data
healthcheck: healthcheck:
test: [ "CMD", "redis-cli", "ping" ] test: ["CMD", "redis-cli", "ping"]
interval: 6s interval: 6s
timeout: 5s timeout: 5s
retries: 5 retries: 5
+5 -3
View File
@@ -7,8 +7,11 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^status\.forust\.xyz$`) - match: Host(`status.forust.xyz`)
kind: Rule kind: Rule
middlewares:
- name: crowdsec-bouncer
namespace: crowdsec
services: services:
- name: kener-service - name: kener-service
port: 3000 port: 3000
@@ -24,9 +27,8 @@ spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- match: HostRegexp(`^status\.(workstation|gigaforust)\.internal$`) - match: Host(`status.workstation.internal`) || Host(`status.gigaforust.internal`)
kind: Rule kind: Rule
services: services:
- name: kener-service - name: kener-service
port: 3000 port: 3000
+1 -1
View File
@@ -27,7 +27,7 @@ spec:
spec: spec:
containers: containers:
- name: kener - name: kener
image: rajnandan1/kener:4.0.23 image: rajnandan1/kener:4.1.5
envFrom: envFrom:
- configMapRef: - configMapRef:
name: kener-config name: kener-config
Loaded 100 of 336 files, more files were not shown because too many files have changed in this diff. Show more