Zum Hauptinhalt springen

HAProxy als Webproxy auf Securepoint UTM betreiben

Wim Bonis
Securepoint Security Tools
Autor
Stylite AG
Spezialisten in ZFS storage solutions, security. Docker containerization for enterprise environments.
Inhaltsverzeichnis

Securepoint-UTMs bringen einen eingebauten nginx mit. Für simple HTTP/HTTPS-Weiterleitungen reicht das. Bei NTLM-Backends wie Skype for Business oder Exchange nicht mehr. Der Grund steht direkt in der nginx-Doku: die ntlm-Direktive ist ausschließlich Teil der kommerziellen nginx-Plus-Subscription. Im freien nginx, den die UTM ausliefert, gibt es kein NTLM-Connection-Binding.

Und Securepoint sagt das selbst so. Das offizielle Wiki zur Exchange-Integration schreibt wörtlich:

„Da der Reverse Proxy keine NTLM-Authentifiezierung weiterleitet, darf in den IIS Einstellungen des Exchange Servers nur Basic/Standardauth aktiv sein"

Für Outlook-Client-Zugriffe wird dort konsequenterweise VPN statt Reverse Proxy empfohlen. Auch im Support-Forum taucht das Thema auf: nach dem Engine-Wechsel von Squid auf nginx konnten Outlook-Clients den Exchange nicht mehr sauber erreichen. Wer also onPrem Exchange, SfB Edge oder OOS über die UTM veröffentlichen will, stößt mit dem eingebauten nginx schnell an funktionale Grenzen.

Header kommen nicht durch. ACLs, SNI-Routing oder mehrere Backends pro Hostname? In der GUI schlicht nicht abbildbar.

Bei Stylite lösen wir das so wie hier beschrieben. Ein statisch gelinktes HAProxy-Binary läuft direkt auf der UTM. Persistent gestartet über eine kleine Hintertür: den Template-Editor für /etc/cronjobs/digest.

Warum HAProxy und nicht der eingebaute nginx?
#

  • Flexible ACLs: Host-Routing, Source-IP-Filter, Path-Redirects, SNI-Auswertung. Alles in einer Datei.
  • TLS-Kontrolle: TLS-Versionen und Cipher-Suites pro Frontend. Bei Altclients wie Lync/SfB oft der einzige Hebel, der eine Verbindung überhaupt aufbaut.
  • Footprint: Ein statisches Binary, ca. 10 MB. Kein Paketmanager, keine Abhängigkeiten.

Die Herausforderung: Persistenz auf einer UTM
#

Securepoint-UTMs sind keine klassischen Linux-Server. Das Root-Dateisystem wird bei jedem Reboot aus Templates neu aufgebaut. Änderungen an /etc außerhalb des Template-Mechanismus sind danach weg. Ein simples echo >> /etc/crontab überlebt keinen Neustart.

Unter Extras → Templates gibt es einen Editor für systemweite Templates. Was dort gespeichert wird, landet im persistenten Konfigurations-Store und wird bei jedem Reboot ausgerollt. Genau dort platzieren wir einen Cron-Job. Der überwacht den HAProxy-Prozess und startet oder reloaded ihn bei Bedarf.

Securepoint UTM WebUI: Template-Editor für /etc/cronjobs/digest mit zusätzlicher Zeile für den HAProxy-Cron-Wrapper

Abbildung 1: Template-Editor in der Securepoint-WebUI – die zweite Zeile ist der Persistenz-Trick

Wichtig: Die Zeile muss über die GUI rein. Direkt auf der CLI editiert hält sie bis zum nächsten Template-Rollout. Reboot oder Updates schreiben sie neu, außer das Template hat den Eintrag.

Installation Schritt für Schritt
#

1. Arbeitsverzeichnis unter /data anlegen
#

/data ist auf Securepoint-UTMs der einzige dauerhafte Ort für eigene Dateien. Überlebt Reboots. Überlebt Firmware-Updates. Alles außerhalb wird bei einem Update aus den Werks-Templates neu aufgebaut.

# install.sh
MYDIR=/data/stylite-haproxy
mkdir -p $MYDIR
cd $MYDIR
wget -O haproxy https://github.com/styliteag/haproxy-static-build/raw/main/dist/linux_amd64/haproxy-latest
chmod +x haproxy

Das Binary kommt aus styliteag/haproxy-static-build . Dort wird HAProxy reproduzierbar und statisch gelinkt gebaut. Keine glibc-Abhängigkeit zur UTM. Das Repo liefert linux_amd64-Binaries und hält immer eine haproxy-latest-Variante bereit.

2. HAProxy-Konfiguration ablegen
#

Die haproxy.cfg kommt in dasselbe Verzeichnis. Ein exemplarischer Ausschnitt für ein Skype-for-Business-Szenario mit mehreren Hostnames:

global
    log stdout format raw daemon
    maxconn 10000
    uid 0
    tune.ssl.default-dh-param 2048

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    option  forwardfor
    timeout connect 10s
    timeout client  60s
    timeout server  60s
    retries 3

frontend fe_sfb_http
    bind 192.168.178.100:80
    capture request header Host len 64
    capture request header User-Agent len 200
    capture request header Authorization len 64
    capture response header WWW-Authenticate len 128
    log-format "%ci:%cp [%tr] %ft %b/%s %ST %B ts:%tsc Tq:%Tq Tw:%Tw Tc:%Tc Tr:%Tr Ta:%Ta ssl:%sslv/%sslc sni:%[ssl_fc_sni] host:%[capture.req.hdr(0)] meth:%HM uri:%HP ua:%[capture.req.hdr(1)] auth:%[capture.req.hdr(2)] www-auth:%[capture.res.hdr(0)]"

    acl host_sfb hdr_dom(host) -i meet.example.de dialin.example.de lyncdiscover.example.de skypeweb.example.de s4bweb.example.de sfbwebext.example.de webconf.example.de oos.example.de

    # Usually safe for public URLs
    http-request redirect scheme https code 301 if host_sfb

    http-request deny


frontend fe_sfb_https
    bind 192.168.178.100:443 ssl crt fullchain.pem ssl-min-ver TLSv1.2 ssl-max-ver TLSv1.2 alpn http/1.1

    capture request header Host len 64
    capture request header User-Agent len 200
    capture request header Authorization len 64
    capture response header WWW-Authenticate len 128

    log-format "%ci:%cp [%tr] %ft %b/%s %ST %B host:%[capture.req.hdr(0)] meth:%HM uri:%HP auth:%[capture.req.hdr(2)] www-auth:%[capture.res.hdr(0)]"

    http-request set-header X-Forwarded-Proto https
    http-request set-header X-Forwarded-Port 443

    acl host_sfb hdr_dom(host) -i meet.example.de dialin.example.de lyncdiscover.example.de skypeweb.example.de s4bweb.example.de sfbwebext.example.de webconf.example.de
    # acl host_oos hdr_dom(host) -i oos.example.de

    use_backend be_sfb_web 
    # use_backend be_oos if host_oos
    
backend be_sfb_web
    mode http
    http-request set-header Host %[req.hdr(host)]
    server fe1 192.168.0.11:4443 check ssl verify none sni req.hdr(host)
    server fe2 192.168.0.12:4443 check ssl verify none sni req.hdr(host) backup

3. Cron-Wrapper-Script
#

Start, Monitoring und Reload übernimmt cron.sh. Alle fünf Minuten aufgerufen. Prüft die Config. Startet HAProxy, wenn der Prozess nicht läuft. Reloaded bei Config-Änderung (MD5-Hash-Vergleich):

#!/bin/sh
BASE_DIR="/data/stylite-haproxy"
HAPROXY_BIN="$BASE_DIR/haproxy"
HAPROXY_CFG="$BASE_DIR/haproxy.cfg"
HAPROXY_PID="$BASE_DIR/haproxy.pid"
CFG_HASH_FILE="$BASE_DIR/.cfg.hash"
LOG_FILE="$BASE_DIR/cron.log"

cd "$BASE_DIR" || exit 1

[ -x "$BASE_DIR/rotate_log.sh" ] && "$BASE_DIR/rotate_log.sh"

[ -x "$HAPROXY_BIN" ] || exit 0
[ -f "$HAPROXY_CFG" ] || exit 1

# Konfiguration prüfen – bei Syntaxfehler nicht neu starten
"$HAPROXY_BIN" -c -f "$HAPROXY_CFG" >>"$LOG_FILE" 2>&1 || exit 1

NEW_HASH="$(md5sum "$HAPROXY_CFG" | awk '{print $1}')"
OLD_HASH=""
[ -f "$CFG_HASH_FILE" ] && OLD_HASH="$(cat "$CFG_HASH_FILE")"

OLDPID=""
[ -f "$HAPROXY_PID" ] && OLDPID="$(cat "$HAPROXY_PID" 2>/dev/null)"

RUNNING=0
if [ -n "$OLDPID" ] && kill -0 "$OLDPID" 2>/dev/null; then
    RUNNING=1
fi

# Fall 1: läuft nicht → starten
if [ "$RUNNING" -eq 0 ]; then
    echo "$(date) START haproxy" >>"$LOG_FILE"
    "$HAPROXY_BIN" -W -db -f "$HAPROXY_CFG" -p "$HAPROXY_PID" >>"$LOG_FILE" 2>&1 &
    echo "$NEW_HASH" > "$CFG_HASH_FILE"
    exit 0
fi

# Fall 2: läuft + Config unverändert → nichts tun
[ "$NEW_HASH" = "$OLD_HASH" ] && exit 0

# Fall 3: läuft + Config geändert → Reload mit -sf (seamless)
echo "$(date) RELOAD haproxy (config changed)" >>"$LOG_FILE"
"$HAPROXY_BIN" -W -db -f "$HAPROXY_CFG" -p "$HAPROXY_PID" -sf "$OLDPID" >>"$LOG_FILE" 2>&1 &
echo "$NEW_HASH" > "$CFG_HASH_FILE"
exit 0

-sf $OLDPID ist in Produktion Pflicht. Bestehende Verbindungen werden an den neuen Prozess übergeben. Der Master-Worker-Modus (-W) übernimmt die Prozesskontrolle. Keine abgebrochenen Sessions, kein erzwungener NTLM-Reauth.

4. Log-Rotation
#

Damit cron.log die UTM-Platte nicht füllt, rotiert rotate_log.sh ab 1 MB und hält fünf Generationen:

#!/bin/sh
BASE_DIR="/data/stylite-haproxy"
LOG_FILE="$BASE_DIR/cron.log"
MAX_SIZE=$((1024 * 1024))
KEEP=5

[ -f "$LOG_FILE" ] || exit 0
SIZE="$(wc -c < "$LOG_FILE" 2>/dev/null)"
[ "$SIZE" -lt "$MAX_SIZE" ] && exit 0

[ -f "$LOG_FILE.$KEEP" ] && rm -f "$LOG_FILE.$KEEP"

i=$KEEP
while [ "$i" -gt 1 ]; do
    PREV=$((i - 1))
    [ -f "$LOG_FILE.$PREV" ] && mv "$LOG_FILE.$PREV" "$LOG_FILE.$i"
    i=$PREV
done

mv "$LOG_FILE" "$LOG_FILE.1"
: > "$LOG_FILE"
chmod 644 "$LOG_FILE"

5. Der Persistenz-Trick: /etc/cronjobs/digest über die WebUI
#

Der eigentliche Schritt zur Persistenz in der Securepoint-WebUI:

  1. Extras → Templates öffnen.
  2. Template /etc/cronjobs/digest auswählen.
  3. Folgende Zeile ans Ende ergänzen:
*/5 * * * * [ -x /data/stylite-haproxy/cron.sh ] && /data/stylite-haproxy/cron.sh
  1. Speichern. Die Änderung wird sofort ausgerollt und überlebt Reboots, Updates und Cluster-Failover.
CLI-Ausgabe: cat /etc/cronjobs/digest zeigt die hinzugefügte HAProxy-Cron-Zeile auf der Securepoint UTM

Abbildung 2: Kontrolle auf der CLI – die Zeile ist in /etc/cronjobs/digest angekommen

Der [ -x ... ]-Check macht den Cron-Aufruf folgenlos, falls das Verzeichnis fehlt oder der Wrapper gelöscht wurde. Keine Fehler in den Systemlogs.

Überprüfung
#

Nach dem Eintragen der Cron-Zeile reicht ein Blick ins Verzeichnis:

cd /data/stylite-haproxy
ls -l
tail -f cron.log

Spätestens nach fünf Minuten existiert haproxy.pid, der Prozess läuft. Config-Änderungen zieht der nächste Cron-Tick per -sf nach. Ohne Verbindungsverlust.

Fazit
#

Ein statisches HAProxy-Binary. Ein kleines Wrapper-Script. Eine Cron-Zeile im richtigen Template. Mehr braucht es nicht für einen ernstzunehmenden Reverse-Proxy auf Securepoint UTM. NTLM, SfB Edge und Exchange laufen sauber. /data sorgt dafür, dass das Setup auch Firmware-Updates übersteht. Die Cron-Zeile gehört in den Template-Editor der WebUI. Nicht auf die CLI.

Related Project: haproxy-static-build - reproduzierbare, statisch gelinkte HAProxy-Builds für Linux.

Fragen zu NTLM-Szenarien hinter Securepoint-UTMs oder zu komplexeren Reverse-Proxy-Topologien? Die Stylite AG hilft gerne weiter.

Weiterführende Links#

HAProxy & Build:

nginx-Einschränkung bei NTLM:

Securepoint UTM – Reverse Proxy:

Microsoft-Hintergrund (NTLM, Kerberos, SfB, Exchange):


Wim Bonis ist CTO bei Stylite AG und beschäftigt sich schwerpunktmäßig mit Storage, Netzwerksicherheit und der Integration von Open-Source-Komponenten in Enterprise-Appliances.

Verwandte Artikel

Passwort-Policy 2026: Warum die meisten Regeln veraltet sind – und was wirklich schützt
Wim Bonis
Security Tools
Stylite Free Tools – Datenschutzfreundliche Open-Source-Werkzeuge im Browser
Wim Bonis
Tools Open Source Security
Phishing erkennen, verstehen, vermeiden: Ein Leitfaden für Unternehmen und Anwender
Wim Bonis
Security Tools
Open Source im Unternehmen: Digitale Souveränität, Chancen und Verantwortung
Matteo Keller
Open Source Security Tools
Achtung: Neue Sicherheitslücke bei Passwort-Managern entdeckt!
Matteo Keller
Security Tools
UTM am Ende? Warum modulare Security die Zukunft ist
Wim Bonis
Security Network Sophos UTM NGFW
TrueNAS 26 – Ransomware-Schutz, Hybrid-Pools und ein neues Versionsschema
Wim Bonis
Storage TrueNAS ZFS Security Open Source
NFON Call Monitor – Echtzeit-Anrufüberwachung für NFON-Telefonanlagen
Wim Bonis
Tools Open Source NFON Telefonanlage CTI ProjectFacts
Stoßgebete aus dem Rechenzentrum: Was sich jeder Storage-Admin wirklich wünscht
Wim Bonis
Storage ZFS Security Monitoring