# ============================================================ # omny-test.psi.ch — behind an SSL-terminating reverse proxy # # The proxy terminates HTTPS and forwards requests to this # Apache as plain HTTP on port 80. Therefore: # * everything (auth-gate rewrites, deny rules) lives in the # *:80 vhost — there is no *:443 vhost on this host # * the HTTP->HTTPS redirect fires ONLY when the proxy # explicitly reports "X-Forwarded-Proto: http". If the # header is absent, no redirect happens (loop-proof). # # Requirements (for the administrators): # * mod_rewrite enabled. The vhost will intentionally FAIL # to load without it, rather than silently serving # everything unauthenticated. # * PHP execution active for .php files in /var/www/omny. # * IMPORTANT: mod_remoteip configured with the proxy's IP # (RemoteIPHeader X-Forwarded-For + # RemoteIPInternalProxy ), so REMOTE_ADDR shows # the real client. Several endpoints authorize by client # IP; without mod_remoteip they see only the proxy address. # ============================================================ ServerName omny-test.psi.ch DocumentRoot /var/www/omny ErrorLog ${APACHE_LOG_DIR}/omny-test_error.log CustomLog ${APACHE_LOG_DIR}/omny-test_access.log combined Options +ExecCGI -Indexes AllowOverride None Require all granted # Bare "/" is normally caught by the catch-all rewrite # below; DirectoryIndex kept as fallback. DirectoryIndex login.php index.html index.php # -------------------------------------------------------- # Block direct filesystem access to sensitive / junk files. # (Apache's default "^\.ht" rule does NOT cover # users.htpasswd / session.htpasswd — they don't start # with ".ht".) # -------------------------------------------------------- Require all denied RewriteEngine On # -------------------------------------------------------- # 0. HTTPS enforcement, loop-proof behind the proxy: # redirect ONLY if the proxy explicitly reports that the # original request was plain HTTP. If the proxy does not # send X-Forwarded-Proto, this never matches -> no loop. # -------------------------------------------------------- RewriteCond %{HTTP:X-Forwarded-Proto} =http RewriteRule ^ https://omny-test.psi.ch%{REQUEST_URI} [R=301,L] # 1. URL-level deny before any rewriting. RewriteRule \.(htpasswd|gen)$ - [F,L] # 2. Guard: forbid direct client requests that pass the # internal _file parameter to the gate scripts (would # otherwise let a logged-in user stream PHP source incl. # TOKEN_SECRET). Internal rewrites are unaffected: the # gate rewrites below use [END], which skips rule # re-processing. RewriteCond %{QUERY_STRING} (^|&)_file= RewriteRule ^/(samples/)?auth_gate\.php$ - [F,L] # 3. Pass-throughs (no cookie check) — first match wins. RewriteRule ^/login\.php$ - [L] RewriteRule ^/upload\.php$ - [L] RewriteRule ^/session_query\.php$ - [L] RewriteRule ^/set_password\.php$ - [L] RewriteRule ^/info\.php$ - [L] RewriteRule ^/auth_gate\.php$ - [L] RewriteRule ^/samples/auth_gate\.php$ - [L] RewriteRule ^/\.well-known/acme-challenge/ - [L] RewriteRule ^/samples/upload\.php$ - [L] RewriteRule ^/samples/newmeasurement\.php$ - [L] # 4. Normalize /samples -> /samples/ so it hits the samples # gate instead of falling through to the main gate. RewriteRule ^/samples$ /samples/ [R=301,L] # 5. Samples area: fixed users only. # [END] (not [L]) is essential: Apache re-runs the rule # set after internal redirects; without END this rule # would match its own output and loop. # [QSA] appends the original query string, e.g. # /samples/x.json?t=1 -> _file=x.json&t=1 # (auth_gate.php handles this form via strtok). RewriteRule ^/samples/(.*)$ /samples/auth_gate.php?_file=$1 [END,QSA] # 6. Everything else: main auth gate. RewriteRule ^/(.*)$ /auth_gate.php?_file=$1 [END,QSA]