Compare commits

...

55 Commits

Author SHA1 Message Date
forust 0c5cf29f83 feat: add userbot k8s deployment method
Deploy to Server / deploy (push) Has been cancelled
- Kustomize: base + overlays/dev + overlays/prod
2026-06-07 19:41:28 +02:00
forust 43c38767a1 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 a68c01a68f chore: add gitea container registry compose support for localy builded apps
Deploy to Server / deploy (push) Has been cancelled
2026-06-07 14:37:57 +02:00
forust bdcdb1cb3d feat: router for gitea container registry (unproxied) 2026-06-07 14:37:53 +02:00
forust fe2b80b51f fix: errorpages intercepted gitea container registry endpoint
gitea registry introduced
2026-06-07 13:39:54 +02:00
forust b8d5bc747d hack: commented out local certs until i figure out how to route certs for local routers 2026-06-07 13:38:14 +02:00
forust 6f77b7d845 switch to embedded dockmon login page
Deploy to Server / deploy (push) Has been cancelled
2026-05-27 20:11:48 +02:00
forust ea286e117d feat: add diary (/diary) command with calendar parsing via Playwright
Deploy to Server / deploy (push) Has been cancelled
- Parse school diary calendar HTML table for daily/weekly/monthly views
- Cache diary data with 5-minute TTL
- Inline keyboard for today/tomorrow/week/month selection
- Ukrainian month/weekday names and formatting
2026-05-27 19:39:45 +02:00
forust 6a050669e8 chore: ignore all generated searxng core-config files 2026-05-27 19:39:41 +02:00
forust b9c11b8eab Merge branch 'main' into optimize/userbot
Deploy to Server / deploy (push) Has been cancelled
2026-05-25 01:48:31 +02:00
forust 6dac841b2c updated traefik to v3.7,
Deploy to Server / deploy (push) Has been cancelled
resolved maxResponseBodySize not set
2026-05-25 01:47:59 +02:00
forust 526a2b617a refactor: update .dockerignore
pull_policy never to use local images
2026-05-25 01:43:46 +02:00
forust 1e08391e0e refactor: improved error handling, timeouts and use temp files 2026-05-21 22:14:29 +02:00
forust 0a31601b77 refactor: imporved layer caching for dockerfile
using existing built image for account 2
2026-05-21 22:12:33 +02:00
forust 25eb89c902 feat: add searxng service (metasearch engine) 2026-05-21 21:34:40 +02:00
forust d988b0f7db refactor: change Cloudlfare DDNS config to env-based
Deploy to Server / deploy (push) Failing after 14m7s
2026-05-08 17:38:41 +02:00
forust e873f37159 refactor: nextcloud now requires mounting /dev/dri inside the container.
Deploy to Server / deploy (push) Failing after 0s
Changed network name for nextcloud
2026-05-08 16:39:09 +02:00
forust 8362f45bdc upd: updated image tags for services:
- gitea 1.25.1 --> 1.26
- portainer-ce latest --> 2.41.0
- traefik latest --> 3.6.15
2026-05-08 16:37:26 +02:00
forust fd5ea6cadd upd: kener v4.0.23
Deploy to Server / deploy (push) Failing after 0s
2026-04-10 02:29:02 +02:00
forust aa3598ee3d Merge pull request 'upd: updated kener to v4' (#14) from upd/kener-v4 into main
Deploy to Server / deploy (push) Failing after 1s
Reviewed-on: #14
2026-02-27 13:06:36 +01:00
forust c0205fa49b upd: updated kener to v4 2026-02-27 13:05:56 +01:00
forust a22707770f feat: update certificates logic:
Deploy to Server / deploy (push) Failing after 1s
- Switched xdfnx's homepage certificates to traefik-managed mode
- Renamed local fallback certs
2026-02-25 21:12:44 +01:00
forust 646f988a86 chore: Pinned stable kener version
Deploy to Server / deploy (push) Failing after 5s
2026-02-24 12:09:06 +01:00
forust 414d17d839 deleted test gitea workflow
Deploy to Server / deploy (push) Successful in 1s
2026-02-22 03:53:51 +01:00
forust 812e4eb87a ci: add copy of the gitea workflow for the github
Deploy to Server / deploy (push) Successful in 1s
2026-02-22 03:37:45 +01:00
forust 70b3b203fb fix: update email address
Deploy to Server / deploy (push) Has been cancelled
2026-02-22 00:28:19 +01:00
forust d857f3838d revert testing message
Deploy to Server / deploy (push) Successful in 1s
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2026-02-20 20:41:01 +01:00
forust f8620349a9 fix deploy pipeline to prevent logspam
Deploy to Server / deploy (push) Successful in 16s
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2026-02-20 20:38:39 +01:00
forust b1acff5c85 ci: add run-name to deployment workflow
Deploy to Server / deploy (push) Successful in 19s
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2026-02-20 20:25:17 +01:00
forust beb6dca6a2 CI test change 2026-02-20 20:23:11 +01:00
forust aed6ff31f7 fix: add .runner (act runner settings) to .gitignore 2026-02-20 20:22:10 +01:00
forust 73684af21b ci: deploy workflow with local act_runner
Deploy to Server / deploy (push) Successful in 1s
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2026-02-20 20:09:26 +01:00
forust cd5c90adcc Merge branch 'main' into ci/gitea-actions 2026-02-20 20:08:48 +01:00
forust 578a1ca544 revert: naio needs insecure transport
2593b54402 chore: add backquotes for downtify traefik labels removed insecureTransport
2026-02-20 01:25:23 +01:00
forust 12ed20a306 fix: support for external dynamic traefik configs 2026-02-20 01:16:54 +01:00
forust 400e7b6595 Starting learning cicd from scratch
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
Demo gitea action
2026-02-19 00:36:02 +01:00
forust f58e96a25d add support for external dynamic traefik configs 2026-02-07 01:56:10 +01:00
forust a3e5f5a78b fix: let traefik handle https to portainer 2026-02-05 02:42:39 +01:00
forust 1a09a62a4c chore: deploy and lint workflows 2026-02-05 02:17:47 +01:00
forust 2593b54402 chore: add backquotes for downtify traefik labels
removed insecureTransport
2026-02-05 01:33:04 +01:00
forust 42826a037c refactor: store n8n data in named volumes 2026-02-04 22:26:43 +01:00
forust d7a68237e5 chore: remove redundant or unnececary traefik labels
- traefik.docker.network= (defined by traefik cli)
- traefik.http.routers.<routername>.middlewares=security-headers@file" (applied globally by traefik cli)
2026-02-04 22:26:27 +01:00
forust bbb8bdf0a7 feat: traefik routers for netronome, exported netronome env to .env 2026-02-04 11:00:44 +01:00
forust f4d3bd9c6d feat: basic netronome service 2026-02-03 14:25:53 +01:00
forust 6b919df7c6 chore: restart downtify service unless stopped 2026-02-01 17:24:50 +01:00
forust 3ee0b96ed5 feat: add acl policies to the headscale 2026-02-01 01:14:58 +01:00
forust d25d213d9b feat: add headscale admin web admin (along with headplane accessible via port) 2026-01-31 13:38:33 +01:00
forust a3b7c4c889 commit team avatars (and love) 2026-01-29 21:19:34 +01:00
forust 3dbb50c924 json logging 2026-01-29 17:30:09 +01:00
forust 54da82432b fix: remove headplane healtcheck (always false negative) 2026-01-29 17:22:47 +01:00
forust e5eb234c41 chore: gitignore for adguard 2026-01-29 17:22:40 +01:00
forust 721348e67f refactor: switch adguard data to named volume 2026-01-29 17:22:33 +01:00
forust d58ae2a5e7 chore: new statuspage for errorpages 2026-01-25 23:41:42 +01:00
forust aa516c3445 Merge pull request 'fix: errorpage styles fixes #11' (#12) from fix/errorpage-styles into main
Reviewed-on: #12
2026-01-25 23:39:10 +01:00
forust b5cc7d9a0d fix: errorpage styles fixes #11 2026-01-25 23:38:34 +01:00
71 changed files with 2033 additions and 394 deletions
+39
View File
@@ -0,0 +1,39 @@
name: Deploy to Server
run-name: Deploying to ${{ runner.os}} server on ${{ gitea.ref }}
on:
push:
branches:
- main
- ci/gitea-actions
jobs:
deploy:
runs-on: prod
steps:
- name: Fetch and Diff Analysis
id: diff
run: |
cd ${{ secrets.PROD_DIR }}
git fetch origin main
CHANGES=$(git diff --name-only HEAD origin/main | cut -d/ -f1 | sort -u | tr '\n' ' ')
echo "dirs=$CHANGES" >> $GITHUB_OUTPUT
echo "Changed dirs: $CHANGES"
- name: Sync Server Files
run: |
cd ${{ secrets.PROD_DIR }}
git reset --hard origin/main
echo "Server files synced with origin/main"
- name: Deploy Services
run: |
cd ${{ secrets.PROD_DIR }}
for dir in ${{ steps.diff.outputs.dirs }}; do
if [ -d "$dir" ] && ([ -f "$dir/compose.yaml" ] || [ -f "$dir/docker-compose.yaml" ]); then
echo ">>> Deploying $dir"
cd "$dir"
DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=plain docker compose up -d --build --no-color
cd ..
else
echo ">>> Skipping $dir: no compose file found"
fi
done
+41
View File
@@ -0,0 +1,41 @@
## 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
+9 -3
View File
@@ -5,12 +5,12 @@ sync.ffs_lock
# Copyparty # Copyparty
*.hist/ *.hist/
# Volumes and data directories # Volumes, configs and data directories
gitea/gitea-db/ gitea/gitea-db/
gitea/gitea-data/* gitea/gitea-data/*
n8n/n8n-data/* n8n/n8n-data/*
n8n/n8n-node-data/* n8n/n8n-node-data/*
adguardhome/data/* adguardhome/conf/*
dockmon/data/* dockmon/data/*
portainer/portainer_data/* portainer/portainer_data/*
metube/MeTube_downloads metube/MeTube_downloads
@@ -21,6 +21,7 @@ checkmk/checkmk/*
downtify/Downtify_downloads downtify/Downtify_downloads
headscale/config/* headscale/config/*
headscale/data/* headscale/data/*
searxng/core-config/*
# Steaming services files # Steaming services files
streaming/jellyfin/* streaming/jellyfin/*
@@ -32,12 +33,15 @@ streaming/qbittorrent/*
streaming/prowlarr/* streaming/prowlarr/*
# Homepage # Homepage
homepages/forust_files/assets/images/team/*
homepages/forust_files/.well-known/* homepages/forust_files/.well-known/*
# Traefik files # Traefik files
traefik/letsencrypt/acme.json traefik/letsencrypt/acme.json
traefik/dynamic/fileservers.yml traefik/dynamic/fileservers.yml
traefik/dynamic/*.local.y*ml.*
traefik/dynamic/*.external.y*ml
traefik/logs/* traefik/logs/*
# SSL Certificates # SSL Certificates
@@ -77,6 +81,8 @@ replacements.txt
# Git # Git
.gitattributes .gitattributes
# Gitea/github Runners
.runner
# Misc # Misc
.DS_Store .DS_Store
+4 -6
View File
@@ -11,28 +11,24 @@ services:
# - "68:68/tcp" # DHCP # - "68:68/tcp" # DHCP
# - "3000:3000/tcp" # - "3000:3000/tcp"
volumes: volumes:
- ./data/work:/opt/adguardhome/work - data:/opt/adguardhome/work
- ./data/conf:/opt/adguardhome/conf - ./conf:/opt/adguardhome/conf
- ./certs:/certs:ro - ./certs:/certs:ro
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.adguard.loadbalancer.server.port=3000" - "traefik.http.services.adguard.loadbalancer.server.port=3000"
# Prod Router # Prod Router
- "traefik.http.routers.adguard.rule=Host(`dns.forust.xyz`) || Host(`adguard.forust.xyz`)" - "traefik.http.routers.adguard.rule=Host(`dns.forust.xyz`) || Host(`adguard.forust.xyz`)"
- "traefik.http.routers.adguard.entrypoints=websecure" - "traefik.http.routers.adguard.entrypoints=websecure"
- "traefik.http.routers.adguard.middlewares=security-headers@file"
- "traefik.http.routers.adguard.tls=true" - "traefik.http.routers.adguard.tls=true"
# Local Router # Local Router
- "traefik.http.routers.adguard-local.rule=Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`)" - "traefik.http.routers.adguard-local.rule=Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`)"
- "traefik.http.routers.adguard-local.entrypoints=websecure" - "traefik.http.routers.adguard-local.entrypoints=websecure"
- "traefik.http.routers.adguard-local.middlewares=security-headers@file"
- "traefik.http.routers.adguard-local.tls=true" - "traefik.http.routers.adguard-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.adguard-dev.rule=Host(`adguard.gigaforust.internal`) || Host(`dns.gigaforust.internal`)" - "traefik.http.routers.adguard-dev.rule=Host(`adguard.gigaforust.internal`) || Host(`dns.gigaforust.internal`)"
- "traefik.http.routers.adguard-dev.entrypoints=websecure" - "traefik.http.routers.adguard-dev.entrypoints=websecure"
- "traefik.http.routers.adguard-dev.middlewares=security-headers@file"
- "traefik.http.routers.adguard-dev.tls=true" - "traefik.http.routers.adguard-dev.tls=true"
# DoH Router # DoH Router
- "traefik.http.routers.dns.rule=(Host(`dns.forust.xyz`) && PathPrefix(`/dns-query`))" - "traefik.http.routers.dns.rule=(Host(`dns.forust.xyz`) && PathPrefix(`/dns-query`))"
@@ -45,6 +41,8 @@ services:
- glance.description=AdGuard Home is a network-wide software for blocking ads. - glance.description=AdGuard Home is a network-wide software for blocking ads.
networks: networks:
- proxy - proxy
volumes:
data:
networks: networks:
proxy: proxy:
external: true external: true
+1 -7
View File
@@ -42,26 +42,20 @@ services:
- ./custom-templates:/templates - ./custom-templates:/templates
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.authentik-server.loadbalancer.server.port=9000" - "traefik.http.services.authentik-server.loadbalancer.server.port=9000"
# Prod Router # Prod Router
- "traefik.http.routers.authentik-server.rule=Host(`auth.forust.xyz`)" - "traefik.http.routers.authentik-server.rule=Host(`auth.forust.xyz`)"
- "traefik.http.routers.authentik-server.entrypoints=websecure" - "traefik.http.routers.authentik-server.entrypoints=websecure"
- "traefik.http.routers.authentik-server.middlewares=security-headers@file"
- "traefik.http.routers.authentik-server.service=authentik-server"
- "traefik.http.routers.authentik-server.tls=true" - "traefik.http.routers.authentik-server.tls=true"
# Local Router # Local Router
- "traefik.http.routers.authentik-server-local.rule=Host(`auth.workstation.internal`) || Host(`auth-dashboard.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"
- "traefik.http.routers.authentik-server-local.middlewares=security-headers@file"
- "traefik.http.routers.authentik-server-local.service=authentik-server"
- "traefik.http.routers.authentik-server-local.tls=true" - "traefik.http.routers.authentik-server-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.authentik-server-dev.rule=Host(`auth.gigaforust.internal`)" - "traefik.http.routers.authentik-server-dev.rule=Host(`auth.gigaforust.internal`)"
- "traefik.http.routers.authentik-server-dev.entrypoints=websecure" - "traefik.http.routers.authentik-server-dev.entrypoints=websecure"
- "traefik.http.routers.authentik-server-dev.middlewares=security-headers@file" - "traefik.http.routers.authentik-server-dev.middlewares=security-headers@file"
- "traefik.http.routers.authentik-server-dev.service=authentik-server"
- "traefik.http.routers.authentik-server-dev.tls=true" - "traefik.http.routers.authentik-server-dev.tls=true"
networks: networks:
- proxy - proxy
+15
View File
@@ -0,0 +1,15 @@
CLOUDFLARE_API_TOKEN=YOUR_CLOUDFLARE_API_TOKEN
DOMAINS=example.com,dns.example.com,mc.example.com,auth.example.com,ssh.example.com
IP4_DOMAINS=
IP6_DOMAINS=
IP4_PROVIDER=cloudflare.trace
IP6_PROVIDER=none # change if you want to update AAAA
UPDATE_CRON=@every 5m
UPDATE_ON_START=true
DELETE_ON_STOP=false
DELETE_ON_FAILURE=true
TTL=1
PROXIED=!is(dns.example.com) && !is(mc.example.com) && !is(ssh.example.com)
EMOJI=true
UPTIMEKUMA=https://uptime-kuma.example.com/api/push/AsaSDFGFkfklaFALSKffkfFKfkfkfkFK?status=up&msg=OK&ping=
REJECT_CLOUDFLARE_IPS=true
+21 -4
View File
@@ -6,8 +6,25 @@ services:
security_opt: security_opt:
- no-new-privileges:true - no-new-privileges:true
network_mode: 'host' network_mode: 'host'
# https://github.com/timothymiller/cloudflare-ddns#-quick-start
environment: environment:
- PUID=1000 - CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN:?Cloudflare API token is required}
- PGID=1000 - DOMAINS=${DOMAINS:-}
volumes: - IP4_DOMAINS=${IP4_DOMAINS:-}
- ./config.json:/config.json - IP6_DOMAINS=${IP6_DOMAINS:-}
- IP4_PROVIDER=${IP4_PROVIDER:-cloudflare.trace}
- IP6_PROVIDER=${IP6_PROVIDER:-none}
- UPDATE_CRON=${UPDATE_CRON:-@every 5m}
- UPDATE_ON_START=${UPDATE_ON_START:-true}
- DELETE_ON_STOP=${DELETE_ON_STOP:-false}
- DELETE_ON_FAILURE=${DELETE_ON_FAILURE:-true}
- TTL=${TTL:-1} # 1=auto
# to proxy only "dns.example.com" and "wfs.example.com" use "!is(dns.domain.com) && !is (wfs.domain.com)"
- PROXIED=${PROXIED:-true}
- EMOJI=${EMOJI:-true}
- UPTIMEKUMA=${UPTIMEKUMA:-}
- HEALTHCHECKS=${HEALTHCHECKS:-}
- REJECT_CLOUDFLARE_IPS=${REJECT_CLOUDFLARE_IPS:-true}
# volumes:
# Prefer using environment variables for configuration, config.json legacy support
# - ./config.json:/config.json
-4
View File
@@ -16,22 +16,18 @@ services:
- TZ=${TZ:-Etc/UTC} - TZ=${TZ:-Etc/UTC}
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.checkmk.loadbalancer.server.port=5000" - "traefik.http.services.checkmk.loadbalancer.server.port=5000"
# Prod Router # Prod Router
- "traefik.http.routers.checkmk.rule=Host(`cmk.forust.xyz`)" - "traefik.http.routers.checkmk.rule=Host(`cmk.forust.xyz`)"
- "traefik.http.routers.checkmk.entrypoints=websecure" - "traefik.http.routers.checkmk.entrypoints=websecure"
- "traefik.http.routers.checkmk.middlewares=security-headers@file"
- "traefik.http.routers.checkmk.tls=true" - "traefik.http.routers.checkmk.tls=true"
# Local Router # Local Router
- "traefik.http.routers.checkmk-local.rule=Host(`cmk.workstation.internal`)" - "traefik.http.routers.checkmk-local.rule=Host(`cmk.workstation.internal`)"
- "traefik.http.routers.checkmk-local.entrypoints=websecure" - "traefik.http.routers.checkmk-local.entrypoints=websecure"
- "traefik.http.routers.checkmk-local.middlewares=security-headers@file"
- "traefik.http.routers.checkmk-local.tls=true" - "traefik.http.routers.checkmk-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.checkmk-dev.rule=Host(`cmk.gigaforust.internal`)" - "traefik.http.routers.checkmk-dev.rule=Host(`cmk.gigaforust.internal`)"
- "traefik.http.routers.checkmk-dev.middlewares=security-headers@file"
- "traefik.http.routers.checkmk-dev.entrypoints=websecure" - "traefik.http.routers.checkmk-dev.entrypoints=websecure"
- "traefik.http.routers.checkmk-dev.tls=true" - "traefik.http.routers.checkmk-dev.tls=true"
networks: networks:
+1 -5
View File
@@ -15,7 +15,6 @@ services:
retries: 3 retries: 3
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.dockmon.loadbalancer.server.port=443" - "traefik.http.services.dockmon.loadbalancer.server.port=443"
- "traefik.http.services.dockmon.loadbalancer.server.scheme=https" - "traefik.http.services.dockmon.loadbalancer.server.scheme=https"
- "traefik.http.services.dockmon.loadbalancer.serverstransport=insecureTransport@file" - "traefik.http.services.dockmon.loadbalancer.serverstransport=insecureTransport@file"
@@ -23,18 +22,15 @@ services:
# Prod Router # Prod Router
- "traefik.http.routers.dockmon.rule=Host(`dockmon.forust.xyz`)" - "traefik.http.routers.dockmon.rule=Host(`dockmon.forust.xyz`)"
- "traefik.http.routers.dockmon.entrypoints=websecure" - "traefik.http.routers.dockmon.entrypoints=websecure"
- "traefik.http.routers.dockmon.middlewares=security-chain@file" - "traefik.http.routers.dockmon.middlewares=security-headers@file"
- "traefik.http.routers.dockmon.service=dockmon"
- "traefik.http.routers.dockmon.tls=true" - "traefik.http.routers.dockmon.tls=true"
# Local Router # Local Router
- "traefik.http.routers.dockmon-local.rule=Host(`dockmon.workstation.internal`)" - "traefik.http.routers.dockmon-local.rule=Host(`dockmon.workstation.internal`)"
- "traefik.http.routers.dockmon-local.entrypoints=websecure" - "traefik.http.routers.dockmon-local.entrypoints=websecure"
- "traefik.http.routers.dockmon-local.middlewares=security-headers@file"
- "traefik.http.routers.dockmon-local.tls=true" - "traefik.http.routers.dockmon-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.dockmon-dev.rule=Host(`dockmon.gigaforust.internal`)" - "traefik.http.routers.dockmon-dev.rule=Host(`dockmon.gigaforust.internal`)"
- "traefik.http.routers.dockmon-dev.entrypoints=websecure" - "traefik.http.routers.dockmon-dev.entrypoints=websecure"
- "traefik.http.routers.dockmon-dev.middlewares=security-chain@file"
- "traefik.http.routers.dockmon-dev.tls=true" - "traefik.http.routers.dockmon-dev.tls=true"
# Glance Metadata # Glance Metadata
+13 -15
View File
@@ -2,30 +2,28 @@ services:
downtify: downtify:
container_name: downtify container_name: downtify
image: ghcr.io/henriquesebastiao/downtify:latest image: ghcr.io/henriquesebastiao/downtify:latest
restart: unless-stopped
# ports: # ports:
# - '7077:8000' # - '7077:8000'
volumes: volumes:
- ./Downtify_downloads:/downloads - ./Downtify_downloads:/downloads
labels: labels:
- traefik.enable=true - "traefik.enable=true"
- traefik.docker.network=proxy - "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=true"
# Local Router # Local Router
- traefik.http.routers.downtify-local.rule=Host(`downtify.workstation.internal`) || Host(`downtify.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"
- traefik.http.routers.downtify-local.middlewares=security-headers@file - "traefik.http.routers.downtify-local.tls=true"
- traefik.http.routers.downtify-local.tls=true
# Dev Router # Dev Router
- traefik.http.routers.downtify-dev.rule=Host(`downtify.gigaforust.internal`) - "traefik.http.routers.downtify-dev.rule=Host(`downtify.gigaforust.internal`)"
- traefik.http.routers.downtify-dev.entrypoints=websecure - "traefik.http.routers.downtify-dev.entrypoints=websecure"
- traefik.http.routers.downtify-dev.middlewares=security-chain@file - "traefik.http.routers.downtify-dev.tls=true"
- traefik.http.routers.downtify-dev.tls=true
networks: networks:
- proxy - proxy
networks: networks:
+2 -1
View File
@@ -3,10 +3,11 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
image: gcr.forust.xyz/forust/dtek-notif:latest
pull_policy: build
restart: unless-stopped restart: unless-stopped
environment: environment:
- TZ=Europe/Kyiv - TZ=Europe/Kyiv
dns: dns:
- 1.1.1.1 - 1.1.1.1
- 8.8.8.8 - 8.8.8.8
+4
View File
@@ -17,6 +17,8 @@ services:
session-keeper: session-keeper:
build: ./phpsessid-bot build: ./phpsessid-bot
image: gcr.forust.xyz/forust/session-keeper:latest
pull_policy: build
env_file: .env env_file: .env
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
@@ -31,6 +33,8 @@ services:
webinar-checker: webinar-checker:
build: ./webinar-checker build: ./webinar-checker
image: gcr.forust.xyz/forust/webinar-checker:latest
pull_policy: build
env_file: .env env_file: .env
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
+274 -1
View File
@@ -1,7 +1,10 @@
import os import os
import re
import logging import logging
import redis import redis
import json import json
import time
from datetime import datetime, timedelta
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, ChatMember from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, ChatMember
from telegram.constants import ChatType from telegram.constants import ChatType
@@ -30,6 +33,7 @@ def _env(key, default=None):
EDU_BASE = _env('EDU_URL_BASE', 'https://edu.edu.vn.ua') EDU_BASE = _env('EDU_URL_BASE', 'https://edu.edu.vn.ua')
EDU_WEBINAR_PATH = _env('EDU_URL_WEBINAR', '/webinar/useractive') EDU_WEBINAR_PATH = _env('EDU_URL_WEBINAR', '/webinar/useractive')
WEBINAR_URL = f"{EDU_BASE.rstrip('/')}/{EDU_WEBINAR_PATH.lstrip('/')}" WEBINAR_URL = f"{EDU_BASE.rstrip('/')}/{EDU_WEBINAR_PATH.lstrip('/')}"
DIARY_URL = f"{EDU_BASE.rstrip('/')}/user/diary"
WEBINAR_CHECK_INTERVAL = int(_env('WEBINAR_CHECK_INTERVAL', 60)) WEBINAR_CHECK_INTERVAL = int(_env('WEBINAR_CHECK_INTERVAL', 60))
REDIS_HOST = _env('REDIS_HOST', 'redis') REDIS_HOST = _env('REDIS_HOST', 'redis')
@@ -252,6 +256,205 @@ def get_admin_keyboard(user_id: int):
] ]
return InlineKeyboardMarkup(keyboard) return InlineKeyboardMarkup(keyboard)
# --- Diary Functions ---
DIARY_MONTH_NAMES = ['', 'Січня', 'Лютого', 'Березня', 'Квітня', 'Травня', 'Червня',
'Липня', 'Серпня', 'Вересня', 'Жовтня', 'Листопада', 'Грудня']
DIARY_WEEKDAYS_SHORT = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Нд']
def get_diary_keyboard():
today = datetime.now()
keyboard = [
[
InlineKeyboardButton(f"📌 Сьогодні ({today.day}.{today.month:02d})", callback_data="diary_today"),
InlineKeyboardButton("📌 Завтра", callback_data="diary_tomorrow"),
],
[
InlineKeyboardButton("📅 Цей тиждень", callback_data="diary_week"),
InlineKeyboardButton("📅 Весь місяць", callback_data="diary_month"),
],
]
return InlineKeyboardMarkup(keyboard)
def _parse_calendar_html(table_html: str) -> tuple:
"""Parse calendar HTML table into (month_text, {day_num: {weekday, events}})."""
days = {}
weekdays = []
rows = re.findall(r'<tr[^>]*>(.*?)</tr>', table_html, re.DOTALL)
month_text = ''
for r_idx, row in enumerate(rows):
cells = re.findall(r'<t[dh][^>]*>(.*?)</t[dh]>', row, re.DOTALL)
if r_idx == 0:
# Month navigation row: extract "Травень 2026" from nav text
raw = re.sub(r'<[^>]+>', ' ', row).strip()
raw = re.sub(r'\s+', ' ', raw)
m = re.search(r'([А-Яа-яіїєґ\']+\s*:?\s*\d{4})', raw)
if m:
month_text = m.group(1).replace(' : ', ' ').strip()
else:
month_text = raw
elif r_idx == 1:
# Day names row
for cell in cells:
name = re.sub(r'<[^>]+>', '', cell).strip()
if name:
weekdays.append(name)
else:
# Data rows: each cell = a day
for col_idx, cell in enumerate(cells):
# Extract day number — first number in the cell text
text = re.sub(r'<[^>]+>', ' ', cell).strip()
text = re.sub(r'\s+', ' ', text)
dm = re.match(r'(\d+)', text)
if not dm:
continue
day_num = dm.group(1)
# Extract events: title attribute (full name) of ALL <a> tags inside the cell
events = []
for a_match in re.finditer(r'<a[^>]*>(.*?)</a>', cell, re.DOTALL):
a_tag = a_match.group(0)
# Prefer the title attribute (contains full name, not truncated)
title_m = re.search(r'title\s*=\s*"([^"]*)"', a_tag)
if title_m:
et = title_m.group(1).strip()
else:
et = re.sub(r'<[^>]+>', '', a_match.group(1)).strip()
if et:
events.append(et)
weekday = weekdays[col_idx] if col_idx < len(weekdays) else ''
days[day_num] = {'weekday': weekday, 'events': events}
return month_text, days
async def fetch_diary_data(phpsessid: str) -> dict | None:
logger.info("Fetching diary data via Playwright...")
try:
async with async_playwright() as p:
browser = await p.chromium.connect(PLAYWRIGHT_WS)
try:
context_browser = await browser.new_context(user_agent=USER_AGENT)
await context_browser.add_cookies([{
'name': 'PHPSESSID',
'value': phpsessid,
'domain': 'edu.edu.vn.ua',
'path': '/'
}])
page = await context_browser.new_page()
try:
await page.goto(DIARY_URL, wait_until='domcontentloaded')
await page.wait_for_selector('table.calendar', timeout=10000)
await page.wait_for_timeout(1500)
table_html = await page.evaluate("""
() => {
const t = document.querySelector('table.calendar');
return t ? t.outerHTML : null;
}
""")
if not table_html:
logger.error("table.calendar not found in DOM")
return None
# Debug: save HTML for troubleshooting
try:
with open('/tmp/diary_debug.html', 'w', encoding='utf-8') as f:
f.write(table_html)
except Exception:
pass
month_text, days = _parse_calendar_html(table_html)
logger.info(f"Diary parsed: month={month_text!r}, days_with_events={sum(1 for d in days.values() if d['events'])}/{len(days)}")
return {'monthFullText': month_text, 'days': days}
except Exception as e:
logger.error(f"Error parsing diary: {e}")
return None
finally:
await page.close()
await context_browser.close()
finally:
await browser.close()
except Exception as e:
logger.error(f"Playwright error in diary fetch: {e}")
return None
def _parse_diary_month(text: str) -> str:
match = re.search(r'([А-Яа-яіїєґ\']+\s*:\s*\d{4})', text)
if match:
return match.group(1).replace(' : ', ' ').strip()
return text.strip()
def format_diary_day(data: dict, day_num: int) -> str:
days = data.get('days', {})
month_str = _parse_diary_month(data.get('monthFullText', ''))
day_data = days.get(str(day_num))
lines = [f"📅 <b>{day_num} {month_str}</b>", "" * 18]
if not day_data or not day_data.get('events'):
lines.append("Немає подій")
else:
for e in day_data['events']:
lines.append(f"📌 {e}")
lines.append(f"\n🔗 {DIARY_URL}")
return "\n".join(lines)
def format_diary_week(data: dict, today: datetime) -> str:
days = data.get('days', {})
month_str = _parse_diary_month(data.get('monthFullText', ''))
monday = today - timedelta(days=today.weekday())
sunday = monday + timedelta(days=6)
lines = [f"📅 <b>Тиждень {monday.day}.{monday.month} {sunday.day}.{sunday.month}</b>\n"]
for i in range(7):
d = monday + timedelta(days=i)
day_data = days.get(str(d.day))
lines.append(f"─ <b>{DIARY_WEEKDAYS_SHORT[i]} {d.day}.{d.month}</b> ─")
if not day_data or not day_data.get('events'):
lines.append("Немає подій\n")
else:
for e in day_data['events']:
lines.append(f"📌 {e}")
lines.append("")
lines.append(f"🔗 {DIARY_URL}")
return "\n".join(lines)
def format_diary_month(data: dict) -> str:
days = data.get('days', {})
month_str = _parse_diary_month(data.get('monthFullText', ''))
lines = [f"📅 <b>{month_str}</b>\n"]
for day_num in sorted(days.keys(), key=int):
day_data = days[day_num]
events = day_data.get('events', [])
weekday = day_data.get('weekday', '')
lines.append(f"─ <b>{weekday} {day_num}</b> ─")
if not events:
lines.append("Немає подій\n")
else:
for e in events:
lines.append(f"📌 {e}")
lines.append("")
lines.append(f"🔗 {DIARY_URL}")
return "\n".join(lines)
async def _get_diary_data(context: ContextTypes.DEFAULT_TYPE) -> dict | None:
cached = context.user_data.get('diary_cache')
now_ts = time.time()
if cached and (now_ts - cached.get('timestamp', 0)) < 300:
return cached['data']
phpsessid = redis_client.get(KEY_PHPSESSID)
if not phpsessid:
return None
data = await fetch_diary_data(phpsessid)
if data:
context.user_data['diary_cache'] = {'data': data, 'timestamp': now_ts}
return data
# --- Command Handlers --- # --- Command Handlers ---
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
@@ -376,6 +579,74 @@ async def clear_history(update: Update, context: ContextTypes.DEFAULT_TYPE):
logger.error(f"Failed to clear history: {e}") logger.error(f"Failed to clear history: {e}")
await update.message.reply_text(t(admin_id, 'history_clear_failed')) await update.message.reply_text(t(admin_id, 'history_clear_failed'))
async def diary_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
user = update.effective_user
chat = update.effective_chat
if not is_whitelisted(user.id):
await update.message.reply_text(t(user.id, 'access_denied'))
return
await update.message.reply_text(
"📅 <b>Щоденник</b> — виберіть період:",
parse_mode='HTML',
reply_markup=get_diary_keyboard()
)
async def diary_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
user_id = query.from_user.id
await query.answer()
if user_id != ADMIN_ID:
if not is_whitelisted(user_id):
await query.edit_message_text("⛔ Доступ заборонено.")
return
data = query.data
if data == "diary_refresh":
context.user_data.pop('diary_cache', None)
await query.edit_message_text("🔄 Завантажую щоденник...")
diary_data = await _get_diary_data(context)
if not diary_data:
await query.edit_message_text("❌ Не вдалося завантажити щоденник. Немає сесії або помилка.")
return
await query.edit_message_text(
"📅 <b>Щоденник</b> — виберіть період:",
parse_mode='HTML',
reply_markup=get_diary_keyboard()
)
return
await query.edit_message_text("🔄 Завантажую щоденник...")
diary_data = await _get_diary_data(context)
if not diary_data:
await query.edit_message_text("❌ Не вдалося завантажити щоденник.")
return
today = datetime.now()
if data == "diary_today":
text = format_diary_day(diary_data, today.day)
elif data == "diary_tomorrow":
tomorrow = today + timedelta(days=1)
if tomorrow.day < today.day:
text = "❌ Дані за наступний місяць недоступні. Перейдіть на сайт."
else:
text = format_diary_day(diary_data, tomorrow.day)
elif data == "diary_week":
text = format_diary_week(diary_data, today)
elif data == "diary_month":
text = format_diary_month(diary_data)
else:
return
if len(text) > 4096:
text = text[:4090] + "\n\n✂️ ...(обрізано)"
await query.edit_message_text(
text,
parse_mode='HTML',
reply_markup=get_diary_keyboard()
)
# --- Admin Callbacks --- # --- Admin Callbacks ---
async def admin_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): async def admin_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
@@ -649,8 +920,10 @@ def main():
app.add_handler(CommandHandler("adduser", add_user)) app.add_handler(CommandHandler("adduser", add_user))
app.add_handler(CommandHandler("removeuser", remove_user)) app.add_handler(CommandHandler("removeuser", remove_user))
app.add_handler(CommandHandler("clearhistory", clear_history)) app.add_handler(CommandHandler("clearhistory", clear_history))
app.add_handler(CommandHandler("diary", diary_command))
# Callback handlers - language selection first, then admin panel # Callback handlers - diary first, then language selection, then admin panel
app.add_handler(CallbackQueryHandler(diary_callback, pattern="^diary_"))
app.add_handler(CallbackQueryHandler(language_callback, pattern="^lang_")) app.add_handler(CallbackQueryHandler(language_callback, pattern="^lang_"))
app.add_handler(CallbackQueryHandler(admin_callback)) app.add_handler(CallbackQueryHandler(admin_callback))
+5 -4
View File
@@ -1,6 +1,8 @@
services: services:
errorpage: errorpage:
build: . build: .
image: gcr.forust.xyz/forust/error-pages:latest
pull_policy: build
container_name: error-pages container_name: error-pages
restart: unless-stopped restart: unless-stopped
# ports: # ports:
@@ -9,11 +11,10 @@ services:
- proxy - proxy
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy" - "traefik.http.services.error-pages.loadbalancer.server.port=80"
- "traefik.http.services.errorpage.loadbalancer.server.port=80"
# Error handler middleware # Error handler middleware
- "traefik.http.middlewares.error-pages.errors.status=400-599" - "traefik.http.middlewares.error-pages.errors.status=400,402-599"
- "traefik.http.middlewares.error-pages.errors.service=errorpage" - "traefik.http.middlewares.error-pages.errors.service=error-pages"
- "traefik.http.middlewares.error-pages.errors.query=/{status}.html" - "traefik.http.middlewares.error-pages.errors.query=/{status}.html"
networks: networks:
proxy: proxy:
+170 -2
View File
@@ -7,7 +7,175 @@
<title>403 // Forbidden</title> <title>403 // Forbidden</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="style.css"> <style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head> </head>
<body> <body>
@@ -24,7 +192,7 @@
<h2>./error_message</h2> <h2>./error_message</h2>
<p>You do not have permission to access this resource.</p> <p>You do not have permission to access this resource.</p>
<br> <br>
<p>Check the <a href="https://uptime.forust.xyz/status/forust">System Status</a> if you believe this is an <p>Check the <a href="https://status.forust.xyz">System Status</a> if you believe this is an
error.</p> error.</p>
</section> </section>
+170 -2
View File
@@ -7,7 +7,175 @@
<title>404 // Not Found</title> <title>404 // Not Found</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="style.css"> <style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head> </head>
<body> <body>
@@ -24,7 +192,7 @@
<h2>./error_message</h2> <h2>./error_message</h2>
<p>The page you are looking for does not exist or has been moved.</p> <p>The page you are looking for does not exist or has been moved.</p>
<br> <br>
<p>Check the <a href="https://uptime.forust.xyz/status/forust">System Status</a> if you believe this is an error.</p> <p>Check the <a href="https://status.forust.xyz">System Status</a> if you believe this is an error.</p>
</section> </section>
<footer> <footer>
+170 -2
View File
@@ -7,7 +7,175 @@
<title>500 // Server Error</title> <title>500 // Server Error</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="style.css"> <style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head> </head>
<body> <body>
@@ -24,7 +192,7 @@
<h2>./error_message</h2> <h2>./error_message</h2>
<p>Something went wrong on our end. We are working to fix it.</p> <p>Something went wrong on our end. We are working to fix it.</p>
<br> <br>
<p>Check the <a href="https://uptime.forust.xyz/status/forust">System Status</a> for more information.</p> <p>Check the <a href="https://status.forust.xyz">System Status</a> for more information.</p>
</section> </section>
<footer> <footer>
+170 -2
View File
@@ -7,7 +7,175 @@
<title>502 // Bad Gateway</title> <title>502 // Bad Gateway</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="style.css"> <style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head> </head>
<body> <body>
@@ -24,7 +192,7 @@
<h2>./error_message</h2> <h2>./error_message</h2>
<p>The server received an invalid response from the upstream server.</p> <p>The server received an invalid response from the upstream server.</p>
<br> <br>
<p>Check the <a href="https://uptime.forust.xyz/status/forust">System Status</a> for more information.</p> <p>Check the <a href="https://status.forust.xyz">System Status</a> for more information.</p>
</section> </section>
<footer> <footer>
+170 -2
View File
@@ -7,7 +7,175 @@
<title>503 // Service Unavailable</title> <title>503 // Service Unavailable</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="style.css"> <style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head> </head>
<body> <body>
@@ -24,7 +192,7 @@
<h2>./error_message</h2> <h2>./error_message</h2>
<p>The server is currently unable to handle the request due to maintenance or overload.</p> <p>The server is currently unable to handle the request due to maintenance or overload.</p>
<br> <br>
<p>Check the <a href="https://uptime.forust.xyz/status/forust">System Status</a> for more information.</p> <p>Check the <a href="https://status.forust.xyz">System Status</a> for more information.</p>
</section> </section>
<footer> <footer>
+170 -2
View File
@@ -7,7 +7,175 @@
<title>504 // Gateway Timeout</title> <title>504 // Gateway Timeout</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="style.css"> <style>
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
</style>
</head> </head>
<body> <body>
@@ -24,7 +192,7 @@
<h2>./error_message</h2> <h2>./error_message</h2>
<p>The server did not receive a timely response from the upstream server.</p> <p>The server did not receive a timely response from the upstream server.</p>
<br> <br>
<p>Check the <a href="https://uptime.forust.xyz/status/forust">System Status</a> for more information.</p> <p>Check the <a href="https://status.forust.xyz">System Status</a> for more information.</p>
</section> </section>
<footer> <footer>
-167
View File
@@ -1,167 +0,0 @@
/* hidden in a plain sight? */
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--accent: #ffffff;
--dim: #666666;
--font-mono: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-mono);
line-height: 1.6;
font-size: 16px;
padding: 2rem;
}
a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px solid var(--dim);
transition: all 0.2s;
}
a:hover {
background-color: var(--text-color);
color: var(--bg-color);
border-color: var(--text-color);
}
.container {
max-width: 800px;
margin: 0 auto;
}
/* TEXT */
h1 {
font-size: 2.5rem;
text-transform: uppercase;
letter-spacing: -2px;
margin-bottom: 0.5rem;
}
h2 {
font-size: 1.2rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--dim);
display: inline-block;
padding-right: 20px;
}
.subtitle {
color: var(--dim);
margin-bottom: 2rem;
}
hr {
border: 0;
border-top: 1px dashed var(--dim);
margin: 2rem 0;
}
.comment {
color: var(--dim);
font-size: 0.9rem;
margin-left: 10px;
}
/* SECTIONS */
section {
margin-bottom: 3rem;
}
/* LISTS */
ul {
list-style: none;
}
.link-list li {
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 15px;
}
/* STACK GRID */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.level {
font-weight: bold;
}
.special .level {
color: var(--text-color);
text-shadow: 1px 0 0 red, -1px 0 0 blue;
}
/* my dudes */
.team-grid {
display: flex;
gap: 2rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.member {
text-align: center;
width: 100px;
}
.avatar {
width: 80px;
height: 80px;
background-color: #222;
border: 2px solid var(--text-color);
margin: 0 auto 10px auto;
background-size: cover;
}
/* if no avatar added: */
.placeholder::before {
content: "?";
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 2rem;
color: var(--dim);
}
/* REPOS */
.repo-list li {
margin-bottom: 1rem;
}
/* FOOTER */
footer {
text-align: center;
color: var(--dim);
font-size: 0.8rem;
/* flag{why-are-you-here?} */
margin-top: 4rem;
}
/* SMTH RESPONSIVE */
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
gap: 0;
}
}
+6 -5
View File
@@ -1,6 +1,6 @@
services: services:
server: server:
image: docker.gitea.com/gitea:1.25.1 image: docker.gitea.com/gitea:1.26
container_name: gitea container_name: gitea
restart: always restart: always
environment: environment:
@@ -31,28 +31,29 @@ services:
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.gitea.loadbalancer.server.port=3000" - "traefik.http.services.gitea.loadbalancer.server.port=3000"
# Prod Router # Prod Router
- "traefik.http.routers.gitea.rule=Host(`gitea.forust.xyz`)" - "traefik.http.routers.gitea.rule=Host(`gitea.forust.xyz`)"
- "traefik.http.routers.gitea.entrypoints=websecure" - "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.middlewares=security-headers@file"
- "traefik.http.routers.gitea.tls=true" - "traefik.http.routers.gitea.tls=true"
# Local Router # Local Router
- "traefik.http.routers.gitea-local.rule=Host(`gitea.workstation.internal`)" - "traefik.http.routers.gitea-local.rule=Host(`gitea.workstation.internal`)"
- "traefik.http.routers.gitea-local.entrypoints=websecure" - "traefik.http.routers.gitea-local.entrypoints=websecure"
- "traefik.http.routers.gitea-local.middlewares=security-headers@file"
- "traefik.http.routers.gitea-local.tls=true" - "traefik.http.routers.gitea-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.gitea-dev.rule=Host(`gitea.gigaforust.internal`)" - "traefik.http.routers.gitea-dev.rule=Host(`gitea.gigaforust.internal`)"
- "traefik.http.routers.gitea-dev.entrypoints=websecure" - "traefik.http.routers.gitea-dev.entrypoints=websecure"
- "traefik.http.routers.gitea-dev.middlewares=security-headers@file"
- "traefik.http.routers.gitea-dev.tls=true" - "traefik.http.routers.gitea-dev.tls=true"
# SSH Router # SSH Router
- "traefik.tcp.services.gitea.loadbalancer.server.port=22" - "traefik.tcp.services.gitea.loadbalancer.server.port=22"
- "traefik.tcp.routers.gitea.entrypoints=ssh" - "traefik.tcp.routers.gitea.entrypoints=ssh"
- "traefik.tcp.routers.gitea.rule=HostSNI(`*`)" - "traefik.tcp.routers.gitea.rule=HostSNI(`*`)"
# Gitea container registry Router
- "traefik.http.routers.gitea-registry.rule=Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)"
- "traefik.http.routers.gitea-registry.entrypoints=websecure"
- "traefik.http.routers.gitea-registry.tls.certresolver=letsencrypt"
- "traefik.http.routers.gitea-registry.tls=true"
ports: ports:
- "2221:22" - "2221:22"
networks: networks:
+1 -4
View File
@@ -12,22 +12,19 @@ services:
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy" - "traefik.docker.network=proxy"
# FIXME: traefik.services.glance.loadbalancer.server.port ?? - "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(`glance.forust.xyz`)"
- "traefik.http.routers.glance.entrypoints=websecure" - "traefik.http.routers.glance.entrypoints=websecure"
- "traefik.http.routers.glance.middlewares=security-headers@file"
- "traefik.http.routers.glance.tls=true" - "traefik.http.routers.glance.tls=true"
# Local Router # Local Router
- "traefik.http.routers.glance-local.rule=Host(`glance.workstation.internal`)" - "traefik.http.routers.glance-local.rule=Host(`glance.workstation.internal`)"
- "traefik.http.routers.glance-local.entrypoints=websecure" - "traefik.http.routers.glance-local.entrypoints=websecure"
- "traefik.http.routers.glance-local.middlewares=security-headers@file"
- "traefik.http.routers.glance-local.tls=true" - "traefik.http.routers.glance-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.glance-dev.rule=Host(`glance.gigaforust.internal`)" - "traefik.http.routers.glance-dev.rule=Host(`glance.gigaforust.internal`)"
- "traefik.http.routers.glance-dev.entrypoints=websecure" - "traefik.http.routers.glance-dev.entrypoints=websecure"
- "traefik.http.routers.glance-dev.middlewares=security-headers@file"
- "traefik.http.routers.glance-dev.tls=true" - "traefik.http.routers.glance-dev.tls=true"
networks: networks:
- proxy - proxy
+23 -7
View File
@@ -9,10 +9,10 @@ services:
volumes: volumes:
- ./config/headscale.yaml:/etc/headscale/config.yaml - ./config/headscale.yaml:/etc/headscale/config.yaml
- data:/var/lib/headscale - data:/var/lib/headscale
- ./config/policy.json:/var/lib/headscale/policy.json
labels: labels:
- "me.tale.headplane.target: headscale" - "me.tale.headplane.target: headscale"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.headscale.loadbalancer.server.port=8080" - "traefik.http.services.headscale.loadbalancer.server.port=8080"
- "traefik.http.services.headscale-metrics.loadbalancer.server.port=9090" - "traefik.http.services.headscale-metrics.loadbalancer.server.port=9090"
@@ -62,12 +62,28 @@ services:
- /var/run/docker.sock:/var/run/docker.sock:ro - /var/run/docker.sock:/var/run/docker.sock:ro
networks: networks:
- proxy - proxy
healthcheck: web:
test: [ "CMD", "/bin/hp_healthcheck" ] image: goodieshq/headscale-admin:latest
interval: 30s restart: unless-stopped
timeout: 5s labels:
start_period: 5s - "traefik.enable=true"
retries: 3 - "traefik.http.services.headscale-ui.loadbalancer.server.port=80"
# Prod Router
- "traefik.http.routers.headscale-ui.rule=Host(`hs.forust.xyz`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headscale-ui.entrypoints=websecure"
- "traefik.http.routers.headscale-ui.middlewares=security-chain@file"
- "traefik.http.routers.headscale-ui.tls=true"
# Local Router
- "traefik.http.routers.headscale-ui-local.rule=Host(`hs.workstation.internal`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headscale-ui-local.entrypoints=websecure"
- "traefik.http.routers.headscale-ui-local.tls=true"
# Dev Router
- "traefik.http.routers.headscale-ui-dev.rule=Host(`hs.gigaforust.internal`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headscale-ui-dev.entrypoints=websecure"
- "traefik.http.routers.headscale-ui-dev.tls=true"
networks:
- proxy
volumes: volumes:
data: data:
headplane-data: headplane-data:
+26
View File
@@ -0,0 +1,26 @@
{
"groups": {
"group:admin": [
"admin@"
],
"group:users": []
},
"tagOwners": {},
"hosts": {},
"acls": [
{
"#ha-meta": {
"name": "users",
"open": true
},
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"autogroup:self:*"
]
}
],
"ssh": []
}
+5 -8
View File
@@ -3,6 +3,8 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile.forust dockerfile: Dockerfile.forust
image: gcr.forust.xyz/forust/forust-homepage:latest
pull_policy: build
# ports: # ports:
# - "8085:80" # - "8085:80"
restart: unless-stopped restart: unless-stopped
@@ -12,28 +14,26 @@ services:
- proxy - proxy
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.forust-homepage.loadbalancer.server.port=80" - "traefik.http.services.forust-homepage.loadbalancer.server.port=80"
# Prod Router # Prod Router
- "traefik.http.routers.forust-homepage.rule=Host(`forust.xyz`)" - "traefik.http.routers.forust-homepage.rule=Host(`forust.xyz`)"
- "traefik.http.routers.forust-homepage.entrypoints=websecure" - "traefik.http.routers.forust-homepage.entrypoints=websecure"
- "traefik.http.routers.forust-homepage.middlewares=security-headers@file"
- "traefik.http.routers.forust-homepage.tls=true" - "traefik.http.routers.forust-homepage.tls=true"
# Local Router # Local Router
- "traefik.http.routers.forust-homepage-local.rule=Host(`landing.workstation.internal`)" - "traefik.http.routers.forust-homepage-local.rule=Host(`landing.workstation.internal`)"
- "traefik.http.routers.forust-homepage-local.entrypoints=websecure" - "traefik.http.routers.forust-homepage-local.entrypoints=websecure"
- "traefik.http.routers.forust-homepage-local.middlewares=security-headers@file"
- "traefik.http.routers.forust-homepage-local.tls=true" - "traefik.http.routers.forust-homepage-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.forust-homepage-dev.rule=Host(`landing.gigaforust.internal`)" - "traefik.http.routers.forust-homepage-dev.rule=Host(`landing.gigaforust.internal`)"
- "traefik.http.routers.forust-homepage-dev.entrypoints=websecure" - "traefik.http.routers.forust-homepage-dev.entrypoints=websecure"
- "traefik.http.routers.forust-homepage-dev.middlewares=security-headers@file"
- "traefik.http.routers.forust-homepage-dev.tls=true" - "traefik.http.routers.forust-homepage-dev.tls=true"
xdfnx: xdfnx:
build: build:
context: . context: .
dockerfile: Dockerfile.xdfnx dockerfile: Dockerfile.xdfnx
image: gcr.forust.xyz/forust/xdfnx-homepage:latest
pull_policy: build
restart: unless-stopped restart: unless-stopped
# ports: # ports:
# - "8086:80" # - "8086:80"
@@ -41,23 +41,20 @@ services:
- ./xdfnx_files:/usr/share/nginx/html - ./xdfnx_files:/usr/share/nginx/html
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.xdfnx-homepage.loadbalancer.server.port=80" - "traefik.http.services.xdfnx-homepage.loadbalancer.server.port=80"
# Prod Router # Prod Router
- "traefik.http.routers.xdfnx.rule=Host(`xdfnx.cfd`)" - "traefik.http.routers.xdfnx.rule=Host(`xdfnx.cfd`)"
- "traefik.http.routers.xdfnx.entrypoints=websecure" - "traefik.http.routers.xdfnx.entrypoints=websecure"
- "traefik.http.routers.xdfnx.middlewares=security-headers@file" - "traefik.http.routers.xdfnx.tls.certresolver=letsencrypt"
- "traefik.http.routers.xdfnx.tls=true" - "traefik.http.routers.xdfnx.tls=true"
# Local Router # Local Router
- "traefik.http.routers.xdfnx-local.rule=Host(`xdfnx.workstation.internal`)" - "traefik.http.routers.xdfnx-local.rule=Host(`xdfnx.workstation.internal`)"
- "traefik.http.routers.xdfnx-local.entrypoints=websecure" - "traefik.http.routers.xdfnx-local.entrypoints=websecure"
- "traefik.http.routers.xdfnx-local.middlewares=security-headers@file"
- "traefik.http.routers.xdfnx-local.tls=true" - "traefik.http.routers.xdfnx-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.xdfnx-dev.rule=Host(`xdfnx.gigaforust.internal`)" - "traefik.http.routers.xdfnx-dev.rule=Host(`xdfnx.gigaforust.internal`)"
- "traefik.http.routers.xdfnx-dev.entrypoints=websecure" - "traefik.http.routers.xdfnx-dev.entrypoints=websecure"
- "traefik.http.routers.xdfnx-dev.middlewares=security-headers@file"
- "traefik.http.routers.xdfnx-dev.tls=true" - "traefik.http.routers.xdfnx-dev.tls=true"
networks: networks:
- proxy - proxy
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

+2 -2
View File
@@ -41,7 +41,7 @@
</li> </li>
<li> <li>
<i class="fas fa-envelope"></i> <i class="fas fa-envelope"></i>
<a href="mailto:forust@forust.xyz">mail/contact@forust.xyz</a> <a href="mailto:contact@forust.xyz">mail/contact@forust.xyz</a>
</li> </li>
<li> <li>
<i class="fa-solid fa-key"></i> <i class="fa-solid fa-key"></i>
@@ -116,7 +116,7 @@
<div class="avatar" <div class="avatar"
style="background-image: url('assets/images/team/anna.jpg'); background-size: cover; background-position: center;"> style="background-image: url('assets/images/team/anna.jpg'); background-size: cover; background-position: center;">
</div> </div>
<a href="" target="_blank">Anna~</a> <a href="./assets/images/love.png" target="_blank">Anna~</a>
</div> </div>
<div class="member"> <div class="member">
+22 -2
View File
@@ -1,6 +1,6 @@
services: services:
kener: kener:
image: rajnandan1/kener:latest image: rajnandan1/kener:4.0.23
container_name: kener container_name: kener
restart: unless-stopped restart: unless-stopped
# ports: # ports:
@@ -8,13 +8,16 @@ services:
environment: environment:
- KENER_SECRET_KEY=${KENER_SECRET_KEY?Kener requires a secret key} - KENER_SECRET_KEY=${KENER_SECRET_KEY?Kener requires a secret key}
- ORIGIN=${ORIGIN:-http://localhost:3000} - ORIGIN=${ORIGIN:-http://localhost:3000}
- REDIS_URL=redis://redis:6379
- TZ:${TZ:-Etc/UTC} - TZ:${TZ:-Etc/UTC}
depends_on:
redis:
condition: service_healthy
volumes: volumes:
- db:/app/database - db:/app/database
- uploads:/app/uploads - uploads:/app/uploads
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.kener.loadbalancer.server.port=3000" - "traefik.http.services.kener.loadbalancer.server.port=3000"
# Prod Router # Prod Router
@@ -31,9 +34,26 @@ services:
- "traefik.http.routers.kener-dev.tls=true" - "traefik.http.routers.kener-dev.tls=true"
networks: networks:
- proxy - proxy
- kener
redis:
image: redis:7-alpine
container_name: kener-redis
restart: unless-stopped
volumes:
- redis:/data
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
interval: 6s
timeout: 5s
retries: 5
networks:
- kener
volumes: volumes:
db: db:
uploads: uploads:
redis:
networks: networks:
proxy: proxy:
external: true external: true
kener:
external: false
-3
View File
@@ -14,7 +14,6 @@ services:
- ./MeTube_downloads:/downloads - ./MeTube_downloads:/downloads
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.metube.loadbalancer.server.port=8081" - "traefik.http.services.metube.loadbalancer.server.port=8081"
# Prod Router # Prod Router
@@ -25,12 +24,10 @@ services:
# Local Router # Local Router
- "traefik.http.routers.metube-local.rule=Host(`metube.workstation.internal`)" - "traefik.http.routers.metube-local.rule=Host(`metube.workstation.internal`)"
- "traefik.http.routers.metube-local.entrypoints=websecure" - "traefik.http.routers.metube-local.entrypoints=websecure"
- "traefik.http.routers.metube-local.middlewares=security-headers@file"
- "traefik.http.routers.metube-local.tls=true" - "traefik.http.routers.metube-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.metube-dev.rule=Host(`metube.gigaforust.internal`)" - "traefik.http.routers.metube-dev.rule=Host(`metube.gigaforust.internal`)"
- "traefik.http.routers.metube-dev.entrypoints=websecure" - "traefik.http.routers.metube-dev.entrypoints=websecure"
- "traefik.http.routers.metube-dev.middlewares=security-chain@file"
- "traefik.http.routers.metube-dev.tls=true" - "traefik.http.routers.metube-dev.tls=true"
networks: networks:
- proxy - proxy
+8 -13
View File
@@ -13,8 +13,8 @@ services:
- N8N_SECURE_COOKIE=false - N8N_SECURE_COOKIE=false
- N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true - N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true
volumes: volumes:
- ./n8n-node-data:/home/node/.n8n - node-data:/home/node/.n8n
- ./n8n-files:/files - files:/files
extra_hosts: extra_hosts:
- "enterprise.n8n.io:104.26.13.187" - "enterprise.n8n.io:104.26.13.187"
- "enterprise.n8n.io:104.26.12.187" - "enterprise.n8n.io:104.26.12.187"
@@ -27,28 +27,19 @@ services:
- n8n - n8n
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy" - "traefik.http.services.n8n.loadbalancer.server.port=5678"
# Prod Router # Prod Router
- "traefik.http.routers.n8n.rule=Host(`n8n.forust.xyz`)" - "traefik.http.routers.n8n.rule=Host(`n8n.forust.xyz`)"
- "traefik.http.routers.n8n.entrypoints=websecure" - "traefik.http.routers.n8n.entrypoints=websecure"
- "traefik.http.routers.n8n.middlewares=security-headers@file"
- "traefik.http.routers.n8n.service=n8n"
- "traefik.http.routers.n8n.tls=true" - "traefik.http.routers.n8n.tls=true"
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
# Local Router # Local Router
- "traefik.http.routers.n8n-local.rule=Host(`n8n.workstation.internal`) || Host(`n8n.internal`)" - "traefik.http.routers.n8n-local.rule=Host(`n8n.workstation.internal`)"
- "traefik.http.routers.n8n-local.entrypoints=websecure" - "traefik.http.routers.n8n-local.entrypoints=websecure"
- "traefik.http.routers.n8n-local.middlewares=security-headers@file"
- "traefik.http.routers.n8n-local.service=n8n"
- "traefik.http.routers.n8n-local.tls=true" - "traefik.http.routers.n8n-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.n8n-dev.rule=Host(`n8n.gigaforust.internal`)" - "traefik.http.routers.n8n-dev.rule=Host(`n8n.gigaforust.internal`)"
- "traefik.http.routers.n8n-dev.entrypoints=websecure" - "traefik.http.routers.n8n-dev.entrypoints=websecure"
- "traefik.http.routers.n8n-dev.middlewares=security-headers@file"
- "traefik.http.routers.n8n-dev.service=n8n"
- "traefik.http.routers.n8n-dev.tls=true" - "traefik.http.routers.n8n-dev.tls=true"
- glance.name=n8n - glance.name=n8n
@@ -60,3 +51,7 @@ networks:
external: false external: false
proxy: proxy:
external: true external: true
volumes:
node-data:
files:
+29
View File
@@ -0,0 +1,29 @@
## https://github.com/autobrr/netronome?tab=readme-ov-file#environment-variables
# Server settings
NETRONOME__HOST=0.0.0.0 # Listen address
NETRONOME__PORT=7575 # Web UI port
NETRONOME__BASE_URL=/netronome # Base URL for reverse proxy
# Database (SQLite by default)
NETRONOME__DB_TYPE=postgres # sqlite or postgres
NETRONOME__DB_PATH=netronome.db # SQLite database path
# PostgreSQL (when DB_TYPE=postgres)
NETRONOME__DB_TYPE=postgres
NETRONOME__DB_HOST=postgres
NETRONOME__DB_PORT=5432
NETRONOME__DB_USER=netronome
NETRONOME__DB_PASSWORD=netronome
NETRONOME__DB_NAME=netronome
NETRONOME__DB_SSLMODE=disable
# Authentication
NETRONOME__AUTH_WHITELIST=127.0.0.1/32,192.168.1.0/24 # IP whitelist (comma-separated)
NETRONOME__SESSION_SECRET= # Session secret (auto-generated if empty)
# OIDC (optional)
NETRONOME__OIDC_ISSUER=https://accounts.google.com
NETRONOME__OIDC_CLIENT_ID=your-client-id
NETRONOME__OIDC_CLIENT_SECRET=your-secret
NETRONOME__OIDC_REDIRECT_URL=https://example.com/api/auth/oidc/callback
+59
View File
@@ -0,0 +1,59 @@
services:
netronome:
image: ghcr.io/autobrr/netronome:latest
restart: unless-stopped
container_name: netronome
ports:
- "7575:7575"
cap_add:
- NET_RAW
env_file:
- .env
labels:
- "traefik.enable=true"
- "traefik.http.services.netronome.loadbalancer.server.port=7575"
# Prod Router
- "traefik.http.routers.netronome.rule=Host(`nm.forust.xyz`)"
- "traefik.http.routers.netronome.entrypoints=websecure"
- "traefik.http.routers.netronome.tls=true"
# Local Router
- "traefik.http.routers.netronome-local.rule=Host(`nm.workstation.internal`)"
- "traefik.http.routers.netronome-local.entrypoints=websecure"
- "traefik.http.routers.netronome-local.tls=true"
# Dev Router
- "traefik.http.routers.netronome-dev.rule=Host(`nm.gigaforust.internal`)"
- "traefik.http.routers.netronome-dev.entrypoints=websecure"
- "traefik.http.routers.netronome-dev.tls=true"
networks:
- proxy
- netronome
depends_on:
postgres:
condition: service_healthy
postgres:
container_name: netronome-postgres
image: postgres:17-alpine
environment:
- POSTGRES_USER=netronome
- POSTGRES_PASSWORD=netronome
- POSTGRES_DB=netronome
volumes:
- data:/var/lib/postgresql/data
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U netronome" ]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- netronome
volumes:
data:
networks:
proxy:
external: true
netronome:
external: false
+3 -5
View File
@@ -7,6 +7,7 @@ services:
volumes: volumes:
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config # Do not change (backup) - nextcloud_aio_mastercontainer:/mnt/docker-aio-config # Do not change (backup)
- /var/run/docker.sock:/var/run/docker.sock:ro - /var/run/docker.sock:/var/run/docker.sock:ro
- /dev/dri:/dev/dri
networks: networks:
- nextcloud-aio - nextcloud-aio
- proxy # Optional: Connects the mastercontainer to the proxy network in order to make the built-in reverse proxy detection work. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md - proxy # Optional: Connects the mastercontainer to the proxy network in order to make the built-in reverse proxy detection work. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
@@ -17,7 +18,6 @@ services:
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
# AIO Services configuration # AIO Services configuration
- "traefik.http.services.nextcloud-aio.loadbalancer.server.port=8080" - "traefik.http.services.nextcloud-aio.loadbalancer.server.port=8080"
- "traefik.http.services.nextcloud-aio.loadbalancer.server.scheme=https" - "traefik.http.services.nextcloud-aio.loadbalancer.server.scheme=https"
@@ -27,17 +27,14 @@ services:
# - "traefik.http.routers.nextcloud-aio.rule=Host(`naio.forust.xyz`)" # - "traefik.http.routers.nextcloud-aio.rule=Host(`naio.forust.xyz`)"
# - "traefik.http.routers.nextcloud-aio.entrypoints=websecure" # - "traefik.http.routers.nextcloud-aio.entrypoints=websecure"
# - "traefik.http.routers.nextcloud-aio.middlewares=security-chain@file" # - "traefik.http.routers.nextcloud-aio.middlewares=security-chain@file"
# - "traefik.http.routers.nextcloud-aio.service=nextcloud-aio"
# - "traefik.http.routers.nextcloud-aio.tls=true" # - "traefik.http.routers.nextcloud-aio.tls=true"
# Local Router # Local Router
- "traefik.http.routers.nextcloud-aio-local.rule=Host(`naio.workstation.internal`)" - "traefik.http.routers.nextcloud-aio-local.rule=Host(`naio.workstation.internal`)"
- "traefik.http.routers.nextcloud-aio-local.entrypoints=websecure" - "traefik.http.routers.nextcloud-aio-local.entrypoints=websecure"
- "traefik.http.routers.nextcloud-aio-local.middlewares=security-headers@file"
- "traefik.http.routers.nextcloud-aio-local.tls=true" - "traefik.http.routers.nextcloud-aio-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.nextcloud-aio-dev.rule=Host(`naio.gigaforust.internal`)" - "traefik.http.routers.nextcloud-aio-dev.rule=Host(`naio.gigaforust.internal`)"
- "traefik.http.routers.nextcloud-aio-dev.entrypoints=websecure" - "traefik.http.routers.nextcloud-aio-dev.entrypoints=websecure"
- "traefik.http.routers.nextcloud-aio-dev.middlewares=security-headers@file"
- "traefik.http.routers.nextcloud-aio-dev.tls=true" - "traefik.http.routers.nextcloud-aio-dev.tls=true"
# Glance Metadata # Glance Metadata
@@ -61,7 +58,7 @@ services:
NEXTCLOUD_STARTUP_APPS: deck twofactor_totp tasks calendar contacts notes # Allows to modify the Nextcloud apps that are installed on starting AIO the first time. See https://github.com/nextcloud/all-in-one#how-to-change-the-nextcloud-apps-that-are-installed-on-the-first-startup NEXTCLOUD_STARTUP_APPS: deck twofactor_totp tasks calendar contacts notes # Allows to modify the Nextcloud apps that are installed on starting AIO the first time. See https://github.com/nextcloud/all-in-one#how-to-change-the-nextcloud-apps-that-are-installed-on-the-first-startup
NEXTCLOUD_ADDITIONAL_APKS: imagemagick # This allows to add additional packages to the Nextcloud container permanently. Default is imagemagick but can be overwritten by modifying this value. See https://github.com/nextcloud/all-in-one#how-to-add-os-packages-permanently-to-the-nextcloud-container NEXTCLOUD_ADDITIONAL_APKS: imagemagick # This allows to add additional packages to the Nextcloud container permanently. Default is imagemagick but can be overwritten by modifying this value. See https://github.com/nextcloud/all-in-one#how-to-add-os-packages-permanently-to-the-nextcloud-container
NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS: imagick # dditional php extensions to the Nextcloud container permanently. Default is imagick but can be overwritten by modifying this value. See https://github.com/nextcloud/all-in-one#how-to-add-php-extensions-permanently-to-the-nextcloud-container NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS: imagick # dditional php extensions to the Nextcloud container permanently. Default is imagick but can be overwritten by modifying this value. See https://github.com/nextcloud/all-in-one#how-to-add-php-extensions-permanently-to-the-nextcloud-container
NEXTCLOUD_ENABLE_DRI_DEVICE: true # This allows to enable the /dev/dri device for containers that profit from it. ⚠️⚠️⚠️ Warning: this only works if the '/dev/dri' device is present on the host! If it should not exist on your host, don't set this to true as otherwise the Nextcloud container will fail to start! See https://github.com/nextcloud/all-in-one#how-to-enable-hardware-acceleration-for-nextcloud # NEXTCLOUD_ENABLE_DRI_DEVICE: true # This allows to enable the /dev/dri device for containers that profit from it. ⚠️⚠️⚠️ Warning: this only works if the '/dev/dri' device is present on the host! If it should not exist on your host, don't set this to true as otherwise the Nextcloud container will fail to start! See https://github.com/nextcloud/all-in-one#how-to-enable-hardware-acceleration-for-nextcloud
# NEXTCLOUD_KEEP_DISABLED_APPS: false # Setting this to true will keep Nextcloud apps that are disabled in the AIO interface and not uninstall them if they should be installed. See https://github.com/nextcloud/all-in-one#how-to-keep-disabled-apps # NEXTCLOUD_KEEP_DISABLED_APPS: false # Setting this to true will keep Nextcloud apps that are disabled in the AIO interface and not uninstall them if they should be installed. See https://github.com/nextcloud/all-in-one#how-to-keep-disabled-apps
SKIP_DOMAIN_VALIDATION: true # This should only be set to true if things are correctly configured. See https://github.com/nextcloud/all-in-one?tab=readme-ov-file#how-to-skip-the-domain-validation SKIP_DOMAIN_VALIDATION: true # This should only be set to true if things are correctly configured. See https://github.com/nextcloud/all-in-one?tab=readme-ov-file#how-to-skip-the-domain-validation
# TALK_PORT: 3478 # This a-llows to adjust the port that the talk container is using which is exposed on the host. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-talk-port # TALK_PORT: 3478 # This a-llows to adjust the port that the talk container is using which is exposed on the host. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-talk-port
@@ -71,6 +68,7 @@ networks:
proxy: proxy:
external: true external: true
nextcloud-aio: nextcloud-aio:
name: nextcloud-aio
driver: bridge driver: bridge
external: false external: false
volumes: volumes:
-4
View File
@@ -102,23 +102,19 @@ services:
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.penpot.loadbalancer.server.port=8080" - "traefik.http.services.penpot.loadbalancer.server.port=8080"
# Prod Router # Prod Router
- "traefik.http.routers.penpot.rule=Host(`penpot.forust.xyz`)" - "traefik.http.routers.penpot.rule=Host(`penpot.forust.xyz`)"
- "traefik.http.routers.penpot.entrypoints=websecure" - "traefik.http.routers.penpot.entrypoints=websecure"
- "traefik.http.routers.penpot.middlewares=security-headers@file"
- "traefik.http.routers.penpot.tls=true" - "traefik.http.routers.penpot.tls=true"
# Local Router # Local Router
- "traefik.http.routers.penpot-local.rule=Host(`penpot.workstation.internal`)" - "traefik.http.routers.penpot-local.rule=Host(`penpot.workstation.internal`)"
- "traefik.http.routers.penpot-local.entrypoints=websecure" - "traefik.http.routers.penpot-local.entrypoints=websecure"
- "traefik.http.routers.penpot-local.middlewares=security-headers@file"
- "traefik.http.routers.penpot-local.tls=true" - "traefik.http.routers.penpot-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.penpot-dev.rule=Host(`penpot.gigaforust.internal`)" - "traefik.http.routers.penpot-dev.rule=Host(`penpot.gigaforust.internal`)"
- "traefik.http.routers.penpot-dev.entrypoints=websecure" - "traefik.http.routers.penpot-dev.entrypoints=websecure"
- "traefik.http.routers.penpot-dev.middlewares=security-headers@file"
- "traefik.http.routers.penpot-dev.tls=true" - "traefik.http.routers.penpot-dev.tls=true"
environment: environment:
<<: [ *penpot-flags, *penpot-http-body-size ] <<: [ *penpot-flags, *penpot-http-body-size ]
+3 -9
View File
@@ -1,35 +1,29 @@
services: services:
portainer: portainer:
image: portainer/portainer-ce:latest image: portainer/portainer-ce:2.41.0
container_name: portainer container_name: portainer
restart: always restart: always
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
- data:/data - data:/data
ports: ports:
- 9443:9443 - 9000:9000
# - 8000:8000 # Remove if you do not intend to use Edge Agents # - 8000:8000 # Remove if you do not intend to use Edge Agents
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy" - "traefik.http.services.portainer.loadbalancer.server.port=9000"
- "traefik.http.services.portainer.loadbalancer.server.port=9443"
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
- "traefik.http.services.portainer.loadbalancer.serverstransport=insecureTransport@file"
# Prod Router # Prod Router
- "traefik.http.routers.portainer.rule=Host(`portainer.forust.xyz`)" - "traefik.http.routers.portainer.rule=Host(`portainer.forust.xyz`)"
- "traefik.http.routers.portainer.entrypoints=websecure" - "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.middlewares=security-headers@file"
- "traefik.http.routers.portainer.tls=true" - "traefik.http.routers.portainer.tls=true"
# Local Router # Local Router
- "traefik.http.routers.portainer-local.rule=Host(`portainer.workstation.internal`)" - "traefik.http.routers.portainer-local.rule=Host(`portainer.workstation.internal`)"
- "traefik.http.routers.portainer-local.entrypoints=websecure" - "traefik.http.routers.portainer-local.entrypoints=websecure"
- "traefik.http.routers.portainer-local.middlewares=security-headers@file"
- "traefik.http.routers.portainer-local.tls=true" - "traefik.http.routers.portainer-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.portainer-dev.rule=Host(`portainer.gigaforust.internal`)" - "traefik.http.routers.portainer-dev.rule=Host(`portainer.gigaforust.internal`)"
- "traefik.http.routers.portainer-dev.entrypoints=websecure" - "traefik.http.routers.portainer-dev.entrypoints=websecure"
- "traefik.http.routers.portainer-dev.middlewares=security-headers@file"
- "traefik.http.routers.portainer-dev.tls=true" - "traefik.http.routers.portainer-dev.tls=true"
# Glance Metadata # Glance Metadata
+15
View File
@@ -0,0 +1,15 @@
# Read the documentation before using the `docker-compose.yml` file:
# https://docs.searxng.org/admin/installation-docker.html
#
# Additional ENVs:
# https://docs.searxng.org/admin/settings/settings_general.html#settings-general
# https://docs.searxng.org/admin/settings/settings_server.html#settings-server
# Use a specific version tag. E.g. "latest" or "2026.3.25-541c6c3cb".
#SEARXNG_VERSION=latest
# Listen to a specific address.
#SEARXNG_HOST=[::]
# Listen to a specific port.
SEARXNG_PORT=8080
+45
View File
@@ -0,0 +1,45 @@
# Read the documentation before using the `docker-compose.yml` file:
# https://docs.searxng.org/admin/installation-docker.html
services:
core:
container_name: searxng-core
image: docker.io/searxng/searxng:${SEARXNG_VERSION:-latest}
restart: unless-stopped
# ports:
# - ${SEARXNG_PORT:-8080}
env_file: .env
labels:
- "traefik.enable=true"
- "traefik.http.services.searxng.loadbalancer.server.port=8080"
# Prod Router
- "traefik.http.routers.searxng.rule=Host(`s.forust.xyz` || `searxng.forust.xyz`)"
- "traefik.http.routers.searxng.entrypoints=websecure"
- "traefik.http.routers.searxng.tls=true"
# Local Router
- "traefik.http.routers.searxng-local.rule=Host(`s.workstation.internal` || `searxng.workstation.internal`)"
- "traefik.http.routers.searxng-local.entrypoints=websecure"
- "traefik.http.routers.searxng-local.tls=true"
# Dev Router
- "traefik.http.routers.searxng-dev.rule=Host(`searxng.gigaforust.internal`)"
- "traefik.http.routers.searxng-dev.entrypoints=websecure"
- "traefik.http.routers.searxng-dev.tls=true"
networks:
- proxy
volumes:
- ./core-config/:/etc/searxng/:Z
- core-data:/var/cache/searxng/
valkey:
container_name: searxng-valkey
image: docker.io/valkey/valkey:9-alpine
command: valkey-server --save 30 1 --loglevel warning
restart: unless-stopped
volumes:
- valkey-data:/data/
volumes:
core-data:
valkey-data:
networks:
proxy:
external: true
-4
View File
@@ -11,23 +11,19 @@ services:
PORT: "8080" PORT: "8080"
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.termix.loadbalancer.server.port=8080" - "traefik.http.services.termix.loadbalancer.server.port=8080"
# Prod Router # Prod Router
- "traefik.http.routers.termix.rule=Host(`termix.forust.xyz`)" - "traefik.http.routers.termix.rule=Host(`termix.forust.xyz`)"
- "traefik.http.routers.termix.entrypoints=websecure" - "traefik.http.routers.termix.entrypoints=websecure"
- "traefik.http.routers.termix.middlewares=security-headers@file"
- "traefik.http.routers.termix.tls=true" - "traefik.http.routers.termix.tls=true"
# Local Router # Local Router
- "traefik.http.routers.termix-local.rule=Host(`termix.workstation.internal`)" - "traefik.http.routers.termix-local.rule=Host(`termix.workstation.internal`)"
- "traefik.http.routers.termix-local.entrypoints=websecure" - "traefik.http.routers.termix-local.entrypoints=websecure"
- "traefik.http.routers.termix-local.middlewares=security-headers@file"
- "traefik.http.routers.termix-local.tls=true" - "traefik.http.routers.termix-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.termix-dev.rule=Host(`termix.gigaforust.internal`)" - "traefik.http.routers.termix-dev.rule=Host(`termix.gigaforust.internal`)"
- "traefik.http.routers.termix-dev.entrypoints=websecure" - "traefik.http.routers.termix-dev.entrypoints=websecure"
- "traefik.http.routers.termix-dev.middlewares=security-headers@file"
- "traefik.http.routers.termix-dev.tls=true" - "traefik.http.routers.termix-dev.tls=true"
networks: networks:
- proxy - proxy
+8 -10
View File
@@ -1,6 +1,6 @@
services: services:
traefik: traefik:
image: traefik:latest image: traefik:v3.7
container_name: traefik container_name: traefik
restart: unless-stopped restart: unless-stopped
command: command:
@@ -17,8 +17,8 @@ services:
# EntryPoints # EntryPoints
- "--entryPoints.web.address=:80" - "--entryPoints.web.address=:80"
# - "--entryPoints.web.http.middlewares=error-pages@docker"
- "--entryPoints.web.http.redirections.entryPoint.scheme=https" - "--entryPoints.web.http.redirections.entryPoint.scheme=https"
- "--entryPoints.web.http.redirections.entryPoint.to=websecure"
- "--entryPoints.websecure.address=:443" - "--entryPoints.websecure.address=:443"
- "--entryPoints.websecure.http.middlewares=error-pages@docker" - "--entryPoints.websecure.http.middlewares=error-pages@docker"
- "--entryPoints.websecure.http.tls=true" - "--entryPoints.websecure.http.tls=true"
@@ -35,14 +35,14 @@ services:
# Cloudflare # Cloudflare
- "--entryPoints.web.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22" - "--entryPoints.web.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22"
- "--entryPoints.websecure.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22" - "--entryPoints.websecure.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22"
# # Logging # Logging
# - "--log.level=INFO" - "--log.level=INFO"
# - "--log.filePath=/var/log/traefik/traefik.log" - "--log.filePath=/var/log/traefik/traefik.log"
# - "--accesslog=true" - "--log.format=json"
# - "--accesslog.filepath=/var/log/traefik/access.log" - "--accesslog=true"
- "--accesslog.filepath=/var/log/traefik/access.log"
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
# Prod Router (Dash) # Prod Router (Dash)
- "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.forust.xyz`)" - "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.forust.xyz`)"
@@ -53,13 +53,11 @@ services:
# Local Router # Local Router
- "traefik.http.routers.traefik-dashboard-local.rule=Host(`traefik.workstation.internal`)" - "traefik.http.routers.traefik-dashboard-local.rule=Host(`traefik.workstation.internal`)"
- "traefik.http.routers.traefik-dashboard-local.entrypoints=websecure" - "traefik.http.routers.traefik-dashboard-local.entrypoints=websecure"
- "traefik.http.routers.traefik-dashboard-local.middlewares=security-headers@file"
- "traefik.http.routers.traefik-dashboard-local.service=api@internal" - "traefik.http.routers.traefik-dashboard-local.service=api@internal"
- "traefik.http.routers.traefik-dashboard-local.tls=true" - "traefik.http.routers.traefik-dashboard-local.tls=true"
# Dev Router # Dev Router
- "traefik.http.routers.traefik-dashboard-dev.rule=Host(`traefik.gigaforust.internal`)" - "traefik.http.routers.traefik-dashboard-dev.rule=Host(`traefik.gigaforust.internal`)"
- "traefik.http.routers.traefik-dashboard-dev.entrypoints=websecure" - "traefik.http.routers.traefik-dashboard-dev.entrypoints=websecure"
- "traefik.http.routers.traefik-dashboard-dev.middlewares=security-headers@file"
- "traefik.http.routers.traefik-dashboard-dev.service=api@internal" - "traefik.http.routers.traefik-dashboard-dev.service=api@internal"
- "traefik.http.routers.traefik-dashboard-dev.tls=true" - "traefik.http.routers.traefik-dashboard-dev.tls=true"
+1
View File
@@ -35,6 +35,7 @@ http:
forwardAuth: forwardAuth:
address: "http://authentik-server:9000/outpost.goauthentik.io/auth/traefik" address: "http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
trustForwardHeader: true trustForwardHeader: true
maxResponseBodySize: 1048576
authResponseHeaders: authResponseHeaders:
- X-authentik-username - X-authentik-username
- X-authentik-groups - X-authentik-groups
-2
View File
@@ -15,7 +15,6 @@ http:
rule: "Host(`nextcloud.workstation.internal`)" rule: "Host(`nextcloud.workstation.internal`)"
entrypoints: entrypoints:
- websecure - websecure
- web
service: nextcloud service: nextcloud
middlewares: middlewares:
- nextcloud-chain - nextcloud-chain
@@ -26,7 +25,6 @@ http:
rule: "Host(`nextcloud.gigaforust.internal`)" rule: "Host(`nextcloud.gigaforust.internal`)"
entrypoints: entrypoints:
- websecure - websecure
- web
service: nextcloud service: nextcloud
middlewares: middlewares:
- nextcloud-chain - nextcloud-chain
+6 -8
View File
@@ -4,14 +4,12 @@ tls:
# Cloudflare Origin CA *.forust.xyz # Cloudflare Origin CA *.forust.xyz
# - certFile: /certs/cloudflare.pem # - certFile: /certs/cloudflare.pem
# keyFile: /certs/cloudflare.key # keyFile: /certs/cloudflare.key
- certFile: /certs/xdfnx.pem # stores:
keyFile: /certs/xdfnx.key # default:
stores: # defaultCertificate:
default: # # Fallback local certificate
defaultCertificate: # certFile: /certs/local.pem
# Fallback local certificate # keyFile: /certs/local-key.pem
certFile: /certs/gigaforust.internal+1.pem
keyFile: /certs/gigaforust.internal+1-key.pem
options: options:
default: default:
-1
View File
@@ -9,7 +9,6 @@ services:
# - "3001:3001" # - "3001:3001"
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001" - "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001"
# Prod Router # Prod Router
+11
View File
@@ -1 +1,12 @@
.unused .unused
Downloads
.venv
volumes
.env
.env.*
my_account.session
.gitignore
README.md
.git
uv.lock
.deepsource.toml
+3
View File
@@ -0,0 +1,3 @@
API_ID=""
API_HASH=""
STRINGSESSION=""
+14
View File
@@ -0,0 +1,14 @@
# apiflash api key only for webshot plugin
APIFLASH_KEY=""
# gemini api key only for gemini plugin
GEMINI_KEY=""
# VT api key only for VirusTotal plugin
VT_KEY=""
# rmbg api key only for removebg plugin
RMBG_KEY=""
# cohere api key only for cohere plugin
COHERE_KEY=""
# sqlite/sqlite3 or mongo/mongodb
DATABASE_TYPE=""
# file name for sqlite3, database name for mongodb
DATABASE_NAME=""
+3
View File
@@ -14,3 +14,6 @@ __pycache__/
/downloads/ /downloads/
/Downloads/ /Downloads/
config.ini config.ini
k8s/*/*secret*.yaml
!k8s/account-secrets.yaml.example
+16 -8
View File
@@ -1,10 +1,18 @@
FROM python:3.11 FROM python:3.11-slim
WORKDIR /app WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
git wget ffmpeg mediainfo && \
rm -rf /var/lib/apt/lists/*
COPY requirements.txt /app/
RUN python -m pip install --no-cache-dir --upgrade pip && \
python -m pip install --no-cache-dir -r /app/requirements.txt
COPY . /app COPY . /app
RUN apt-get -qq update && apt-get -qq install -y git wget ffmpeg mediainfo\
&& apt-get clean \ ENV PYTHONUNBUFFERED=1
&& rm -rf /var/lib/apt/lists/*
RUN python -m venv --copies /opt/venv CMD ["python", "-u", "main.py"]
ENV PATH="/opt/venv/bin:$PATH"
RUN pip install --no-cache-dir -r requirements.txt
CMD ["python", "main.py"]
+7 -4
View File
@@ -3,6 +3,8 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
image: gcr.forust.xyz/forust/userbot:latest
pull_policy: build
restart: unless-stopped restart: unless-stopped
env_file: env_file:
- .env - .env
@@ -10,15 +12,16 @@ services:
volumes: volumes:
- ./volumes/data_forust:/app/data - ./volumes/data_forust:/app/data
- ./Downloads:/app/downloads - ./Downloads:/app/downloads
- ./volumes/logs_forust-:/app/logs - ./volumes/logs_forust:/app/logs
dns: dns:
- 8.8.8.8 - 8.8.8.8
- 1.1.1.1 - 1.1.1.1
anna: anna:
build: image: gcr.forust.xyz/forust/userbot:latest
context: . pull_policy: build
dockerfile: Dockerfile depends_on:
- forust
restart: unless-stopped restart: unless-stopped
env_file: env_file:
- .env - .env
+7
View File
@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: userbot-common-config
data:
DATABASE_TYPE: ""
DATABASE_NAME: ""
+9
View File
@@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- userbots.yaml
- common-secret.yaml
- common-config.yaml
- forust-secrets.yaml
- anna-secrets.yaml
+114
View File
@@ -0,0 +1,114 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: forust-userbot-deployment
labels:
app: forust-userbot
spec:
replicas: 1
selector:
matchLabels:
app: forust-userbot
template:
metadata:
labels:
app: forust-userbot
spec:
containers:
- name: forust-userbot
image: gcr.forust.xyz/forust/userbot:latest
imagePullPolicy: Always
resources:
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "256Mi"
cpu: "100m"
envFrom:
- secretRef:
name: userbot-common-secrets
- configMapRef:
name: userbot-common-config
- secretRef:
name: userbot-forust-secrets
volumeMounts:
- name: forust-storage
mountPath: /app/data
subPath: data
- name: forust-storage
mountPath: /app/logs
subPath: logs
volumes:
- name: forust-storage
persistentVolumeClaim:
claimName: forust-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: forust-pvc
spec:
resources:
requests:
storage: 1Gi
accessModes:
- ReadWriteOnce
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: anna-userbot-deployment
labels:
app: anna-userbot
spec:
replicas: 1
selector:
matchLabels:
app: anna-userbot
template:
metadata:
labels:
app: anna-userbot
spec:
containers:
- name: anna-userbot
image: gcr.forust.xyz/forust/userbot:latest
imagePullPolicy: Always
resources:
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "256Mi"
cpu: "100m"
envFrom:
- secretRef:
name: userbot-common-secrets
- configMapRef:
name: userbot-common-config
- secretRef:
name: userbot-anna-secrets
volumeMounts:
- name: anna-storage
mountPath: /app/data
subPath: data
- name: anna-storage
mountPath: /app/logs
subPath: logs
volumes:
- name: anna-storage
persistentVolumeClaim:
claimName: anna-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: anna-pvc
spec:
resources:
requests:
storage: 1Gi
accessModes:
- ReadWriteOnce
@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: patch-downloads.yaml
@@ -0,0 +1,35 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: forust-userbot-deployment
spec:
template:
spec:
containers:
- name: forust-userbot
volumeMounts:
- name: downloads
mountPath: /app/downloads
volumes:
- name: downloads
hostPath:
path: /home/user/projects/homelab/userbot/Downloads
type: DirectoryOrCreate
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: anna-userbot-deployment
spec:
template:
spec:
containers:
- name: anna-userbot
volumeMounts:
- name: downloads
mountPath: /app/downloads
volumes:
- name: downloads
hostPath:
path: /home/user/projects/homelab/userbot/Downloads
type: DirectoryOrCreate
@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: patch-downloads.yaml
@@ -0,0 +1,35 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: forust-userbot-deployment
spec:
template:
spec:
containers:
- name: forust-userbot
volumeMounts:
- name: downloads
mountPath: /app/downloads
volumes:
- name: downloads
hostPath:
path: /srv/homelab/userbot/Downloads
type: DirectoryOrCreate
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: anna-userbot-deployment
spec:
template:
spec:
containers:
- name: anna-userbot
volumeMounts:
- name: downloads
mountPath: /app/downloads
volumes:
- name: downloads
hostPath:
path: /srv/homelab/userbot/Downloads
type: DirectoryOrCreate
+13 -5
View File
@@ -90,11 +90,19 @@ def load_missing_modules():
os.makedirs(custom_modules_path, exist_ok=True) os.makedirs(custom_modules_path, exist_ok=True)
try: try:
f = requests.get( resp = requests.get(
"https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt" "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt",
).text timeout=10,
except Exception: )
logging.error("Failed to fetch custom modules list") if not resp.ok:
logging.error(
"Failed to fetch custom modules list: HTTP %s",
resp.status_code,
)
return
f = resp.text
except Exception as e:
logging.error("Failed to fetch custom modules list: %s", e)
return return
modules_dict = { modules_dict = {
line.split("/")[-1].split()[0]: line.strip() for line in f.splitlines() line.split("/")[-1].split()[0]: line.strip() for line in f.splitlines()
+8 -8
View File
@@ -59,26 +59,26 @@ async def version(client: Client, message: Message):
await message.delete() await message.delete()
if gitrepo is not None:
remote_url = list(gitrepo.remote().urls)[0] remote_url = list(gitrepo.remote().urls)[0]
commit_time = ( commit_time = (
datetime.datetime.fromtimestamp(gitrepo.head.commit.committed_date) datetime.datetime.fromtimestamp(gitrepo.head.commit.committed_date)
.astimezone(datetime.timezone.utc) .astimezone(datetime.timezone.utc)
.strftime("%Y-%m-%d %H:%M:%S %Z") .strftime("%Y-%m-%d %H:%M:%S %Z")
) )
git_info = (
f"\n<b>Branch: <a href={remote_url}/tree/{gitrepo.active_branch}>{gitrepo.active_branch}</a>\n"
if gitrepo.active_branch != "master" else "\n"
) + f"Commit: <a href={remote_url}/commit/{gitrepo.head.commit.hexsha}>" f"{gitrepo.head.commit.hexsha[:7]}</a> by {gitrepo.head.commit.author.name}\n" f"Commit time: {commit_time}</b>"
else:
git_info = ""
await message.reply( await message.reply(
f"<b>Moon Userbot version: {userbot_version}\n" f"<b>Moon Userbot version: {userbot_version}\n"
f"Changelog </b><i><a href=https://t.me/moonuserbot/{changelog}>in channel</a></i>.<b>\n" f"Changelog </b><i><a href=https://t.me/moonuserbot/{changelog}>in channel</a></i>.<b>\n"
f"Changelog written by </b><i>" f"Changelog written by </b><i>"
f"<a href=https://t.me/Qbtaumai>Abhi</a></i>\n\n" f"<a href=https://t.me/Qbtaumai>Abhi</a></i>\n\n"
+ ( f"{git_info}",
f"<b>Branch: <a href={remote_url}/tree/{gitrepo.active_branch}>{gitrepo.active_branch}</a>\n"
if gitrepo.active_branch != "master"
else ""
)
+ f"Commit: <a href={remote_url}/commit/{gitrepo.head.commit.hexsha}>"
f"{gitrepo.head.commit.hexsha[:7]}</a> by {gitrepo.head.commit.author.name}\n"
f"Commit time: {commit_time}</b>",
) )
+1 -1
View File
@@ -3,7 +3,7 @@ name = "userbot"
version = "0.1.0" version = "0.1.0"
description = "Add your description here" description = "Add your description here"
readme = "README.md" readme = "README.md"
requires-python = ">=3.13" requires-python = ">=3.11"
dependencies = [ dependencies = [
"aiofiles>=25.1.0", "aiofiles>=25.1.0",
"aiohttp>=3.13.2", "aiohttp>=3.13.2",
+2
View File
@@ -18,3 +18,5 @@ aiohttp
aiofiles aiofiles
pySmartDL pySmartDL
qrcode qrcode
bottle
dulwich
+1 -1
View File
@@ -1,8 +1,8 @@
import os import os
import environs import environs
env = environs.Env()
try: try:
env = environs.Env()
env.read_env("./.env") env.read_env("./.env")
except FileNotFoundError: except FileNotFoundError:
print("No .env file found, using os.environ.") print("No .env file found, using os.environ.")
+5 -29
View File
@@ -1,19 +1,3 @@
# Moon-Userbot - telegram userbot
# Copyright (C) 2020-present Moon Userbot Organization
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from sys import version_info from sys import version_info
from .db import db from .db import db
import git import git
@@ -37,19 +21,11 @@ prefix = db.get("core.main", "prefix", ".")
try: try:
gitrepo = git.Repo(".") gitrepo = git.Repo(".")
except git.exc.InvalidGitRepositoryError: except (git.exc.InvalidGitRepositoryError, git.exc.NoSuchPathError):
repo = git.Repo.init() gitrepo = None
origin = repo.create_remote(
"origin", "https://github.com/The-MoonTg-project/Moon-Userbot"
)
origin.fetch()
repo.create_head("main", origin.refs.main)
repo.heads.main.set_tracking_branch(origin.refs.main)
repo.heads.main.checkout(True)
gitrepo = git.Repo(".")
if len(gitrepo.tags) > 0: if gitrepo is not None and len(gitrepo.tags) > 0:
commits_since_tag = list(gitrepo.iter_commits(f"{gitrepo.tags[-1].name}..HEAD")) commits_since_tag = list(gitrepo.iter_commits(f"{gitrepo.tags[-1].name}..HEAD"))
userbot_version = f"2.5.{len(commits_since_tag)}"
else: else:
commits_since_tag = [] userbot_version = "2.5.0"
userbot_version = f"2.5.{len(commits_since_tag)}"
+11 -11
View File
@@ -22,6 +22,7 @@ import re
import shlex import shlex
import subprocess import subprocess
import sys import sys
import tempfile
import time import time
import traceback import traceback
from PIL import Image from PIL import Image
@@ -85,13 +86,17 @@ async def edit_or_send_as_file(
return return
if len(tex) > 1024: if len(tex) > 1024:
await message.edit("<code>OutPut is Too Large, Sending As File!</code>") await message.edit("<code>OutPut is Too Large, Sending As File!</code>")
file_names = f"{file_name}.txt" with tempfile.NamedTemporaryFile(
with open(file_names, "w") as fn: "w", delete=False, suffix=".txt", prefix=f"{file_name}_"
) as fn:
fn.write(tex) fn.write(tex)
await client.send_document(message.chat.id, file_names, caption=caption) temp_path = fn.name
try:
await client.send_document(message.chat.id, temp_path, caption=caption)
await message.delete() await message.delete()
if os.path.exists(file_names): finally:
os.remove(file_names) if os.path.exists(temp_path):
os.remove(temp_path)
return return
return await message.edit(tex) return await message.edit(tex)
@@ -249,12 +254,7 @@ def is_admin(func):
chat_member = await client.get_chat_member( chat_member = await client.get_chat_member(
message.chat.id, message.from_user.id message.chat.id, message.from_user.id
) )
chat_admins = [] if chat_member.status in ("administrator", "creator"):
async for member in client.get_chat_members(
message.chat.id, filter=ChatMembersFilter.ADMINISTRATORS
):
chat_admins.append(member)
if chat_member in chat_admins:
return await func(client, message) return await func(client, message)
await message.edit("You need to be an admin to perform this action.") await message.edit("You need to be an admin to perform this action.")
except UserNotParticipant: except UserNotParticipant: