From 0d767d7edfbe1183be6092e5e673dac004b4271a Mon Sep 17 00:00:00 2001 From: Felix Kemmler Date: Mon, 10 Aug 2026 18:37:06 +0200 Subject: [PATCH] Fix infinite redirect loop on omsorgWeb behind the TLS-terminating proxy The root .htaccess forces HTTPS via `RewriteCond %{HTTPS} !=on`. Behind a reverse proxy that terminates TLS and forwards to Apache over plain HTTP, %{HTTPS} is always "off" - verified via mod_rewrite trace logging that this is NOT spoofable via SetEnvIf or a RewriteRule E-flag, despite that being commonly recommended; %{HTTPS} reflects only the actual TLS connection to Apache. Every request was therefore redirected to https://, which the proxy forwarded back over HTTP, looping forever (browser: "the page isn't redirecting properly"). Fix: .htaccess's redirect condition also accepts a trusted X-Forwarded-Proto: https header as evidence the request is already HTTPS. omsorgWeb/docker/000-default.conf additionally sets HTTPS=on in the request environment when that header is present, so mod_headers' `env=HTTPS` condition (HSTS header) still fires correctly - this part doesn't affect mod_rewrite's %{HTTPS} but is unrelated to the redirect fix. Co-Authored-By: Claude Sonnet 5 --- .htaccess | 11 ++++++++++- omsorgWeb/Dockerfile | 6 ++++++ omsorgWeb/docker/000-default.conf | 22 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 omsorgWeb/docker/000-default.conf diff --git a/.htaccess b/.htaccess index d509442..282bf94 100644 --- a/.htaccess +++ b/.htaccess @@ -1,6 +1,15 @@ -# HTTPS erzwingen +# HTTPS erzwingen - %{HTTPS} spiegelt nur die tatsächliche TLS-Verbindung zu Apache wider und lässt +# sich über keine Env-Var vortäuschen (auch nicht per SetEnvIf/RewriteRule-E-Flag, siehe +# omsorgWeb/docker/000-default.conf). Hinter einem TLS-terminierenden Reverse-Proxy (z.B. der +# Docker-Deployment, siehe docker-compose.yml) ist %{HTTPS} deshalb IMMER "off", auch bei einer +# echten HTTPS-Anfrage - ohne die zweite Bedingung würde das einen endlosen Redirect-Loop erzeugen +# (Proxy leitet HTTPS-Request per HTTP weiter -> Apache hält es für HTTP -> redirected auf https:// +# -> Proxy nimmt HTTPS-Request an, leitet wieder per HTTP weiter -> ...). Die zweite Bedingung lässt +# den Request durch, wenn der (vertrauenswürdige) Proxy per X-Forwarded-Proto bestätigt, dass die +# ursprüngliche Anfrage bereits HTTPS war. RewriteEngine On RewriteCond %{HTTPS} !=on +RewriteCond %{HTTP:X-Forwarded-Proto} !=https RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] # Verzeichnis-Listing verbieten diff --git a/omsorgWeb/Dockerfile b/omsorgWeb/Dockerfile index 356be74..278b68d 100644 --- a/omsorgWeb/Dockerfile +++ b/omsorgWeb/Dockerfile @@ -14,6 +14,12 @@ RUN apt-get update \ COPY omsorgWeb/docker/allow-htaccess.conf /etc/apache2/conf-available/allow-htaccess.conf RUN a2enconf allow-htaccess +# Ersetzt die mitgelieferte Default-vhost (identisch, nur mit einer zusätzlichen Rewrite-Regel, +# die den TLS-terminierenden Host-nginx davor erkennt - sonst redirected die root-.htaccess +# endlos, siehe Datei-Kommentar. Muss im -Block selbst stehen, ein conf-enabled-Drop-in +# außerhalb davon wird nicht mit der .htaccess desselben Pfads zusammengeführt.) +COPY omsorgWeb/docker/000-default.conf /etc/apache2/sites-enabled/000-default.conf + COPY omsorgWeb/ /var/www/html/ COPY .htaccess /var/www/html/.htaccess diff --git a/omsorgWeb/docker/000-default.conf b/omsorgWeb/docker/000-default.conf new file mode 100644 index 0000000..94dcdbe --- /dev/null +++ b/omsorgWeb/docker/000-default.conf @@ -0,0 +1,22 @@ + + ServerName omsorgweb + ServerAdmin webmaster@localhost + DocumentRoot /var/www/html + + # Der Host-nginx terminiert TLS und proxied per HTTP an diesen Container (siehe + # docker-compose.yml) - ohne diese Regel weiß die root-.htaccess + # (`RewriteCond %{HTTPS} !=on` -> Redirect auf https://) nie, dass die ursprüngliche Anfrage + # HTTPS war, und redirected endlos (führt zu "Firefox kann nicht verbinden - Seite leitet + # falsch weiter" bzw. ERR_TOO_MANY_REDIRECTS). Per mod_rewrite-Trace verifiziert: das MUSS + # innerhalb dieses -Blocks stehen - weder eine Regel in conf-enabled/*.conf + # außerhalb jedes VirtualHost, noch eine in einem -Block wird mit dem + # per-Directory-Regelsatz der .htaccess desselben Pfads zusammengeführt (beides per Trace + # ausprobiert, keins hat gewirkt - Apache vererbt Rewrite-Regeln standardmäßig nicht über + # Kontextgrenzen hinweg, siehe RewriteOptions Inherit in der mod_rewrite-Doku). + RewriteEngine On + RewriteCond "%{HTTP:X-Forwarded-Proto}" "=https" + RewriteRule ^ - [E=HTTPS:on] + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined +