updated wger to 2.5

This commit is contained in:
2026-04-17 19:23:04 +02:00
parent c8a3974333
commit a7f0dfc341
+153 -45
View File
@@ -1,20 +1,28 @@
# wger - Workout Manager # wger - Workout Manager
# https://github.com/wger-project/wger # https://github.com/wger-project/wger
# Version: 2.3 # Version: 2.5 (official image, no custom fork)
# Domain: workout.dooplex.hu # Domain: workout.dooplex.hu
# Auth: Authentik Forward Auth (Proxy) with Remote-User header # Auth: Authentik Forward Auth (domain mode) + native wger AUTH_PROXY middleware
# #
# wger supports authentication via headers (X-Remote-User) # ============================================================================
# when WGER_USE_PROXY_AUTH is enabled # MIGRATION NOTES (from 2.3 + custom OIDC fork):
# - Image switched from ghcr.io/kisfenyo/wger-oidc:latest -> wger/server:2.5
# - All OIDC_* / ENABLE_OIDC env vars removed
# - Native AUTH_PROXY_* env vars added (wger 2.4+ feature, PR #1859)
# - Ingress split into two resources:
# * wger -> path / -> protected by Authentik forward-auth
# * wger-api -> path /api/ -> unprotected (JWT auth for mobile app)
# - nginx sidecar: strips client-supplied X-Authentik-* on /api/ (defense in depth)
# - Authentik: create a new Proxy Provider (Forward auth, single application)
# External Host: https://workout.dooplex.hu
# Attach to existing outpost. The old OIDC provider can be deleted.
# #
# Authentik Setup: # POST-UPGRADE COMMANDS (run once after rollout stabilises):
# 1. Create Proxy Provider: # kubectl exec -n workout-system deploy/wger -c wger -- \
# - Name: wger # python manage.py recalculate_statistics --all --active-only
# - External Host: https://workout.dooplex.hu # kubectl exec -n workout-system deploy/wger -c wger -- \
# - Mode: Forward auth (single application) # python manage.py evaluate_trophies --all
# 2. Configure to send X-Remote-User header # ============================================================================
# 3. Create Application linked to this provider
# 4. Create Outpost (or add to existing) with this provider
--- ---
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
@@ -65,6 +73,10 @@ metadata:
labels: labels:
app.kubernetes.io/instance: wger app.kubernetes.io/instance: wger
app.kubernetes.io/name: wger app.kubernetes.io/name: wger
annotations:
# Track upstream wger releases
extensions.v1alpha1.version-checker.io/wger: "true"
extensions.v1alpha1.version-checker.io/wger.match-regex: "^\\d+\\.\\d+$"
spec: spec:
replicas: 1 replicas: 1
selector: selector:
@@ -98,8 +110,8 @@ spec:
mountPath: /etc/nginx/conf.d/default.conf mountPath: /etc/nginx/conf.d/default.conf
subPath: nginx.conf subPath: nginx.conf
- name: wger - name: wger
image: ghcr.io/kisfenyo/wger-oidc:latest image: wger/server:2.5
imagePullPolicy: Always imagePullPolicy: IfNotPresent
env: env:
# Django settings # Django settings
- name: SECRET_KEY - name: SECRET_KEY
@@ -122,7 +134,9 @@ spec:
value: "config.settings.production" value: "config.settings.production"
- name: DJANGO_CACHE_TIMEOUT - name: DJANGO_CACHE_TIMEOUT
value: "120" value: "120"
# Database - name: CSRF_TRUSTED_ORIGINS
value: "https://workout.dooplex.hu"
# Database (shared CNPG)
- name: DJANGO_DB_ENGINE - name: DJANGO_DB_ENGINE
value: "django.db.backends.postgresql" value: "django.db.backends.postgresql"
- name: DJANGO_DB_HOST - name: DJANGO_DB_HOST
@@ -153,31 +167,26 @@ spec:
value: "redis://wger-redis:6379/2" value: "redis://wger-redis:6379/2"
- name: CELERY_BACKEND - name: CELERY_BACKEND
value: "redis://wger-redis:6379/2" value: "redis://wger-redis:6379/2"
- name: ENABLE_OIDC # ----------------------------------------------------------------
# Native Authentication Proxy (wger 2.4+) - replaces OIDC fork
# ----------------------------------------------------------------
- name: AUTH_PROXY_ENABLED
value: "True" value: "True"
- name: OIDC_RP_CLIENT_ID # Django META key format: HTTP_ + uppercase header with - replaced by _
value: "AXr6k4P1JcgKKMcvGeXOLwd69MJ1UVjz3fW80mEg" # So X-Authentik-Username => HTTP_X_AUTHENTIK_USERNAME
- name: OIDC_RP_CLIENT_SECRET - name: AUTH_PROXY_HEADER
value: "oaj4yWum0skWoAJVf4VvXSSnc4pdaWQbKtyPaMaG6prBN0av1b1w7bna6nUALoIXwSQWu9seFZl66XsYxaFWXVXcWyI6B63rl5saIFCifVg9hqkl6RlhxHL4X4u42pqd" value: "HTTP_X_AUTHENTIK_USERNAME"
- name: OIDC_RP_SIGN_ALGO - name: AUTH_PROXY_CREATE_UNKNOWN_USER
value: "RS256" value: "True"
- name: CSRF_TRUSTED_ORIGINS - name: AUTH_PROXY_EMAIL_HEADER
value: "https://workout.dooplex.hu" value: "HTTP_X_AUTHENTIK_EMAIL"
# Authentik Endpoints (Replace 'authentik.dooplex.hu' with your actual Authentik domain) - name: AUTH_PROXY_NAME_HEADER
- name: OIDC_OP_LOGOUT_ENDPOINT value: "HTTP_X_AUTHENTIK_NAME"
value: "https://authentik.dooplex.hu/application/o/workout/end-session/" # Only trust the auth header when coming from the nginx sidecar
- name: OIDC_LOGIN_BUTTON_TEXT # (same pod, proxies from 127.0.0.1 to Django on :8000).
value: "Login with Authentik" # This prevents header-spoofing attacks from anywhere else.
- name: OIDC_ALLOW_CREATE_USER - name: AUTH_PROXY_TRUSTED_IPS
value: "true" value: "127.0.0.1/32"
- name: OIDC_OP_AUTHORIZATION_ENDPOINT
value: "https://authentik.dooplex.hu/application/o/authorize/"
- name: OIDC_OP_TOKEN_ENDPOINT
value: "https://authentik.dooplex.hu/application/o/token/"
- name: OIDC_OP_USER_ENDPOINT
value: "https://authentik.dooplex.hu/application/o/userinfo/"
- name: OIDC_OP_JWKS_ENDPOINT
value: "https://authentik.dooplex.hu/application/o/workout/jwks/"
# Email (disabled - no email sending) # Email (disabled - no email sending)
- name: ENABLE_EMAIL - name: ENABLE_EMAIL
value: "False" value: "False"
@@ -260,8 +269,8 @@ spec:
fsGroup: 1000 fsGroup: 1000
containers: containers:
- name: celery-worker - name: celery-worker
image: ghcr.io/kisfenyo/wger-oidc:latest image: wger/server:2.5
imagePullPolicy: Always imagePullPolicy: IfNotPresent
command: ["/start-worker"] command: ["/start-worker"]
env: env:
- name: SECRET_KEY - name: SECRET_KEY
@@ -274,6 +283,10 @@ spec:
secretKeyRef: secretKeyRef:
name: wger-app name: wger-app
key: signing-key key: signing-key
- name: DJANGO_SETTINGS_MODULE
value: "config.settings.production"
- name: TIME_ZONE
value: "Europe/Budapest"
- name: DJANGO_DB_ENGINE - name: DJANGO_DB_ENGINE
value: "django.db.backends.postgresql" value: "django.db.backends.postgresql"
- name: DJANGO_DB_HOST - name: DJANGO_DB_HOST
@@ -337,8 +350,8 @@ spec:
fsGroup: 1000 fsGroup: 1000
containers: containers:
- name: celery-beat - name: celery-beat
image: ghcr.io/kisfenyo/wger-oidc:latest image: wger/server:2.5
imagePullPolicy: Always imagePullPolicy: IfNotPresent
command: ["/start-beat"] command: ["/start-beat"]
env: env:
- name: SECRET_KEY - name: SECRET_KEY
@@ -351,6 +364,10 @@ spec:
secretKeyRef: secretKeyRef:
name: wger-app name: wger-app
key: signing-key key: signing-key
- name: DJANGO_SETTINGS_MODULE
value: "config.settings.production"
- name: TIME_ZONE
value: "Europe/Budapest"
- name: DJANGO_CACHE_TIMEOUT - name: DJANGO_CACHE_TIMEOUT
value: "120" value: "120"
- name: DJANGO_CACHE_CLIENT_CLASS - name: DJANGO_CACHE_CLIENT_CLASS
@@ -421,7 +438,9 @@ spec:
app.kubernetes.io/instance: wger app.kubernetes.io/instance: wger
app.kubernetes.io/name: wger app.kubernetes.io/name: wger
--- ---
# Ingress with Authentik forward auth # ============================================================================
# Ingress #1: web UI paths (/) - Authentik forward-auth protected
# ============================================================================
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress
metadata: metadata:
@@ -435,6 +454,13 @@ metadata:
external-dns.alpha.kubernetes.io/hostname: workout.dooplex.hu,workout.home external-dns.alpha.kubernetes.io/hostname: workout.dooplex.hu,workout.home
nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "100m" nginx.ingress.kubernetes.io/proxy-body-size: "100m"
# Authentik Forward Auth (domain mode) - same pattern as your other SSO apps
# If you use an internal outpost service URL elsewhere, swap auth-url for it.
nginx.ingress.kubernetes.io/auth-url: "http://ak-outpost-workout-outpost.auth-system.svc.cluster.local:9000/outpost.goauthentik.io/auth/nginx"
nginx.ingress.kubernetes.io/auth-signin: "https://workout.dooplex.hu/outpost.goauthentik.io/start?rd=$escaped_request_uri"
nginx.ingress.kubernetes.io/auth-response-headers: "Set-Cookie,X-Authentik-Username,X-Authentik-Email,X-Authentik-Name,X-Authentik-Groups,X-Authentik-Uid"
nginx.ingress.kubernetes.io/auth-snippet: |
proxy_set_header X-Forwarded-Host $http_host;
nginx.ingress.kubernetes.io/configuration-snippet: | nginx.ingress.kubernetes.io/configuration-snippet: |
set $geo_allowed 0; set $geo_allowed 0;
if ($remote_addr ~ "^192\.168\.") { set $geo_allowed 1; } if ($remote_addr ~ "^192\.168\.") { set $geo_allowed 1; }
@@ -471,6 +497,60 @@ spec:
- workout.dooplex.hu - workout.dooplex.hu
secretName: wger-tls secretName: wger-tls
--- ---
# ============================================================================
# Ingress #2: API paths (/api/) - NO forward-auth, JWT token auth only
# Required so the wger Flutter mobile app can hit /api/v2/token for login.
# More-specific path match means /api/* hits this Ingress, not the / one.
# ============================================================================
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wger-api
namespace: workout-system
labels:
app.kubernetes.io/instance: wger
app.kubernetes.io/name: wger-api
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
nginx.ingress.kubernetes.io/configuration-snippet: |
# Same geo-block as the web UI ingress
set $geo_allowed 0;
if ($remote_addr ~ "^192\.168\.") { set $geo_allowed 1; }
if ($remote_addr ~ "^10\.") { set $geo_allowed 1; }
if ($geoip2_country_code = "HU") { set $geo_allowed 1; }
if ($geo_allowed = 0) {
return 403 "Access restricted to Hungary";
}
spec:
ingressClassName: nginx-internal
rules:
- host: workout.dooplex.hu
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: wger
port:
number: 80
- host: workout.home
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: wger
port:
number: 80
tls:
- hosts:
- workout.dooplex.hu
secretName: wger-tls
---
apiVersion: v1 apiVersion: v1
kind: PersistentVolumeClaim kind: PersistentVolumeClaim
metadata: metadata:
@@ -532,12 +612,40 @@ data:
access_log off; access_log off;
} }
# API path: strip any client-supplied auth headers before proxying.
# Mobile app + API clients authenticate via JWT (/api/v2/token), not
# proxy auth. This is a defense-in-depth measure so that even if traffic
# somehow reaches this sidecar without going through the forward-auth
# ingress, it cannot forge an AUTH_PROXY login via a spoofed header.
# Nginx treats "" as "do not forward this header."
location /api/ {
proxy_pass http://localhost:8000;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Authentik-Username "";
proxy_set_header X-Authentik-Email "";
proxy_set_header X-Authentik-Name "";
proxy_set_header X-Authentik-Groups "";
proxy_set_header X-Authentik-Uid "";
}
# Everything else: pass through the auth headers set by the
# forward-auth ingress so wger's AUTH_PROXY middleware can log the
# user in. $http_x_authentik_username expands to empty if the header
# isn't present (e.g. Tailscale admin access bypassing the ingress).
location / { location / {
proxy_pass http://localhost:8000; proxy_pass http://localhost:8000;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Authentik-Username $http_x_authentik_username;
proxy_set_header X-Authentik-Email $http_x_authentik_email;
proxy_set_header X-Authentik-Name $http_x_authentik_name;
proxy_set_header X-Authentik-Groups $http_x_authentik_groups;
proxy_set_header X-Authentik-Uid $http_x_authentik_uid;
} }
} }
--- ---