# =============================================================================
# txadmin-vhost.conf -- Apache 2.4 Reverse Proxy fuer das txAdmin-Panel
#
# Ablegen unter: /etc/apache2/sites-available/tx.example.de.conf
# Aktivieren: a2ensite tx.example.de.conf && apachectl -t && systemctl reload apache2
#
# Vorher noetig: a2enmod ssl proxy proxy_http proxy_wstunnel headers rewrite
#
# Ersetzen: tx.example.de, info@example.de und die beiden Zertifikatspfade.
# Voraussetzung: txAdmin hoert auf 127.0.0.1:40120, siehe
# https://www.musiker15.de/de/docs/fivem/installation
#
# Doku: https://www.musiker15.de/de/docs/fivem/txadmin-reverse-proxy
# =============================================================================
ServerName tx.example.de
Redirect permanent / https://tx.example.de/
ServerName tx.example.de
ServerAdmin info@example.de
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/example.de/fullchain.cer
SSLCertificateKeyFile /etc/apache2/ssl/example.de/example.de.key
# --- Security-Header -----------------------------------------------------
# Bewusst OHNE Content-Security-Policy. txAdmin liefert eigene
# Security-Header aus, und zwei Policies fuer dasselbe Dokument werden
# nicht zusammengefuehrt, sondern beide durchgesetzt.
# Pruefen mit:
# curl -sI https://tx.example.de/ | grep -i -E 'content-security|x-frame'
#
# X-XSS-Protection fehlt hier absichtlich. Der Header ist in allen
# aktuellen Browsern wirkungslos und wurde von der CSP abgeloest.
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Cross-Origin-Opener-Policy "same-origin"
Header always set Cross-Origin-Resource-Policy "same-origin"
# --- Reverse Proxy -------------------------------------------------------
ProxyPreserveHost On
# Standard waere der globale Timeout von 60 Sekunden. Eine Live-Konsole,
# auf der eine Minute lang nichts passiert, gilt damit als tote Verbindung
# und wird gekappt. Sichtbar als Panel, das sich staendig neu verbindet.
ProxyTimeout 600
# upgrade=websocket braucht Apache 2.4.47 oder neuer. Damit laeuft die
# Live-Konsole ueber eine echte WebSocket-Verbindung statt ueber
# HTTP-Polling. Pruefen mit: apache2 -v
#
# Das ist die Standardantwort und sie reicht nicht immer. Bleibt es trotzdem
# bei Status 400, vergleiche die ANTWORTGROESSE. Kommt vom Backend eine
# kleine Antwort (rund 34 Bytes) und durch den Proxy eine grosse (rund 1400),
# stammt der 400 von Apache, nicht von txAdmin:
# curl -s -o /dev/null -w '%{size_download}\n' \
# "http://127.0.0.1:40120/socket.io/?EIO=4&transport=websocket"
# Weitersuchen dann mit LogLevel alert proxy:trace3
#
# Testen NICHT mit einem selbstgebauten curl-Handshake, den lehnt engine.io
# auch direkt am Backend mit 400 ab. Richtig ist der Browser:
# DevTools, Netzwerk, Filter WS, Status 101.
#
# Geht der Upgrade nicht durch, ist das kein Beinbruch: socket.io bleibt
# still beim HTTP-Longpolling, das Panel funktioniert weiter, nur traeger.
ProxyPass / http://127.0.0.1:40120/ upgrade=websocket
ProxyPassReverse / http://127.0.0.1:40120/
# --- Fuer Apache aelter als 2.4.47 ---------------------------------------
# Dann kennt ProxyPass die Option nicht und quittiert mit
# "Unknown parameter". Stattdessen die drei Zeilen unten einkommentieren,
# das "upgrade=websocket" oben entfernen, und mod_rewrite uebernimmt die
# Weiche. Sie muss VOR dem ProxyPass stehen.
#
# Wichtig: die Unterscheidung laeuft ueber den Upgrade-Header, nicht ueber
# den Pfad. /socket.io/ pauschal auf ws:// zu legen bricht den
# HTTP-Handshake, mit dem socket.io jede Sitzung beginnt.
#
#RewriteEngine On
#RewriteCond %{HTTP:Upgrade} =websocket [NC]
#RewriteRule ^/?(.*) ws://127.0.0.1:40120/$1 [P,L]
# X-Forwarded-For, X-Forwarded-Host und X-Forwarded-Server setzt
# mod_proxy_http von allein. Wer sie zusaetzlich per RequestHeader setzt,
# bekommt die Client-IP doppelt ("1.2.3.4, 1.2.3.4") und damit unbrauchbare
# Adressen in den txAdmin-Logs und in der Ban-Ansicht.
# X-Forwarded-Proto setzt das Modul dagegen nicht, diese Zeile bleibt.
RequestHeader set X-Forwarded-Proto "https"