NGINX kann auch für Umgebungen mit Exchange Systemen eingesetzt werden, hierfür müssen allerdings einige Punkte beachtet werden. Ich möchte hier einmal meine Erkenntnisse teilen, damit sich andere die Zeit sparen können welche ich hierfür aufbringen musste.
Hauptmerkmale von NGINX
- Webserver: Dient zur Auslieferung statischer Inhalte (HTML, CSS, JS, Bilder) mit extrem hoher Effizienz.
- Reverse Proxy: Leitet Anfragen an Backend-Server weiter und ermöglicht Lastverteilung.
- Load Balancer: Verteilt Traffic auf mehrere Server, um die Verfügbarkeit und Ausfallsicherheit zu erhöhen.
- Caching: Speichert häufig angeforderte Inhalte zwischen, um die Ladezeiten zu verkürzen.
- Modularität: Unterstützt Module wie SSL/TLS, HTTP/2 und andere moderne Web-Technologien.
- Ereignisgesteuertes Design: Bewältigt eine hohe Anzahl gleichzeitiger Verbindungen mit minimalem Ressourcenverbrauch.

Problematik: NGINX war vor einen Exchange-Server geschaltet und bediente alle relevanten virtuellen Verzeichnisse: OWA/ECP/EWS/Microsoft-Server-ActiveSync/RPC/MAPI. Hierfür hatte ich ein Vorlage für NGINX Reverse-Proxy verwendet die man in Umgebungen mit Exchange-Server einsetzt. Hier gibt es dutzende Anleitungen dazu. Jedoch hatte ich immer wieder Probleme, dass bei Outlook die Benutzereingabe + Passwort aufging. Immer und immer wieder. Also hab ich mir das einmal genauer angeschaut.
BASIC vs NTLM
Basic Authentifizierungen zählen zu den “einfachen” Legitimierungen, hier wird die klassischen Benutzer/Password abfrage gestartet. NGINX kann das von Haus aus abhandeln, man kann diese Anfragen aber auch abfangen und direkt weiterleiten, mit folgenden Ergänzungen:
more_set_input_headers 'Authorization: $http_authorization';
more_set_headers -s 401 'WWW-Authenticate: Basic realm="meine.domain.de"';
Wichtig hierbei: Es handelt sich um die einfach Basic Authentifizierung hier findet keine Negotiation mit dem Exchange statt! Grundsätzlich kann Exchange-Server auch mit Basic Authentifizierung umgehen jedoch gelten diese als unsicher, da Benutzernamen und Passwörter im Klartext übertragen werden.
NTLM (Windows New Technology LAN Manager)
NTLM zählt zum Standard der Windows Authentifizierung, mittlerweile gibt es hier bereits NTLMv2, NTLMv1 wird als weniger sicher eingestuft. Bei dieser Authentifizierung wird eine Challenge vom Server aufgerufen , genauso wie bei Kerberos. Problem hier: NGINX unterstützt kein NTLM in der OpenSource Variante, nur in der PlusVariante.
upstream exchange_backend {
server X.X.X.X:443;
ntlm;
}
server {
server_name mail.meine.domain.de autodiscover.meine.domain.de.de;
# Enable SSL
#ssl_certificate /etc/nginx/cert/https://meine.domain.de.pem;
#ssl_certificate_key /etc/nginx/cert/https://meine.domain.de.pem;
# Redirect from "/" to "/owa" by default
rewrite ^/$ https://meine.domain.de/owa permanent;
###########################Basic#######################
location /owa { proxy_pass https://meine.domain.de/owa; }
location /ecp { proxy_pass hhttps://meine.domain.de/ecp; }
location /Microsoft-Server-ActiveSync {proxy_pass https://meine.domain.de/Microsoft-Server-ActiveSync;}
############################Upstream####################
location /mapi { proxy_pass https://exchange_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
location /Rpc { proxy_pass https://exchange_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
Hier mal ein Beispiel: Einige Dienste vom Exchange kommen ohne NTLM aus, hier genügt die Basic Authentifizierungen. Jedoch für MAPI und besonders für RPC reicht diese nicht aus, hier benötigt man unter anderem NTLM.
Mögliche Lösungen:
1.) Lösungsvorschlag ohne NTLM
Möchte man nur OWA freigeben kann man dies mit der BASIC Authentifizierung problemlos tun, hier einmal ein erste Lösungsvorschlag. Hier wird der Exchange hauptsächlich im internen Netzwerk verwendet über MAPI und RPC.
server {
listen 80;
listen [::]80;
server_name $mail.domain.tld;
ssl_verify_client off;
location /owa { proxy_pass https://$exchange_server/owa; }
proxy_pass_request_headers on;
proxy_pass_header Date;
proxy_pass_header Server;
proxy_set_header Host $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 https;
more_set_input_headers 'Authorization: $http_authorization';
proxy_set_header Accept-Encoding "";
more_set_headers -s 401 'WWW-Authenticate: Basic realm="$mail.domain.tld"';
proxy_buffering off;
proxy_request_buffering off;
access_log /var/log/nginx/$mail.domain.tld-access.log;
error_log /var/log/nginx/$mail.domain.tld-error.log;
2.) Lösungsvorschlag mit NTLM
- Erstes Projekt für NTLM hatte ich hier gefunden:
- Git: https://github.com/gabihodoroaga/nginx-ntlm-module
- Hier wurde das NTLM Modul aus dem NGINX-Plus nachgebaut, der Quellcode ist derselbige.
- Ich konnte das Module erfolgreich mit NGINX Version 1.22.1 kompilieren.
- Git: https://github.com/gabihodoroaga/nginx-ntlm-module
- Anleitung zur Module Erstellung für NTLM:
sudo apt install git
git clone https://github.com/gabihodoroaga/nginx-ntlm-module.git
ls
nginx-ntlm-module <-- Dieses Module sollte jetzt nach dem Git clone da sein.
nginx -v <-- Checkt Eure Nginx Version, diese brauchen wir gleich.
nginx version: nginx/1.22.1
Geht nun auf die NGINX Downloadseite: https://nginx.org/en/download.html
Ladet Euch die gleiche NGINX Version herunter, welche bereits auf Eurem System installiert ist, in meinen Fall ist das NGINX Version: 1.22.1
wget https://nginx.org/download/nginx-1.22.1.tar.gz
tar -xvf nginx-1.22.1.tar.gz
cd nginx-1.22.1
Nun müssen die Pakete vom installierten NGINX einmal ausgegeben werden.
nginx -V <--Das "V" ist hier jetzt großgeschrieben.
nginx version: nginx/1.22.1
built with OpenSSL 3.0.8 7 Feb 2023 (running with OpenSSL 3.0.15 3 Sep 2024)
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -ffile-prefix-map=/build/nginx-AoTv4W/nginx-1.22.1=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=stderr --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_secure_link_module --with-http_sub_module --with-mail_ssl_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-stream_realip_module --with-http_geoip_module=dynamic --with-http_image_filter_module=dynamic --with-http_perl_module=dynamic --with-http_xslt_module=dynamic --with-mail=dynamic --with-stream=dynamic --with-stream_geoip_module=dynamic
Jetzt sehen wir die Ausgabe, kopiert den gesamten Text Euch zwischenzeitlich in Notepad++ oder einen Editor Eure Wahl. Jetzt fügt ihr noch den Pfad vom Modul ein drückt nun Enter. Sollter hier ein Fehlermeldung erhalten, prüft ob Ihr Euch im “nginx-1.22.1” Ordner befindet. Es sollte ein Überprüfung stattfinden. (Hilfe: https://nginx.org/en/docs/configure.html)
Solltet Ihr gar nicht klarkommen dann liest nochmal hier nach: https://docs.vultr.com/how-to-compile-nginx-from-source-on-debian-10?lang=de
./configure --add-dynamic-module=../nginx-ntlm-module --with-cc-opt='-g -O2 -ffile-prefix-map=/build/nginx-AoTv4W/nginx-1.22.1=. -fstack-protector-strong
-Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx
--conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-p ......................
Wenn die Überprüfung erfolgreich war dann sollte das wie folgt aussehen:

Nun müssen wir das Module noch erstellen, hierfür muss folgendes eingetippt werden
make modules
Anschließend finden wir unser NTLM Module hier unter /objs

Jetzt verschieben wir das Module noch
cp /opt/nginx-1.22.1/objs/ngx_http_upstream_ntlm_module.so /usr/share/nginx/modules/
Sollte der Pfad nicht existieren schaut nochmal hier nach: /usr/lib/nginx/modules
Nun binden wir das Modul noch ein in NGINX, das geht mit “load_module” und dann den vollständigen UNC dahinter.
cd /etc/nginx
vim nginx.conf

Jetzt prüfen wir ob alles passt!

Hier nun die finale Config für NGINX mit NTLM im Exchange Betrieb. Grundsätzlich habe ich für die einzelnen “location” einzelne Blöcke definiert und nicht , wie überlich, generel im Server-Block, dies würde kollidieren mit den NTLM-Upstream Block bei der Authentifizierung.
upstream exchange_backend {
server $exchange_server:443;
ntlm;
}
server {
server_name mail.domain.de autodiscover.domain.de;
# Enable SSL
ssl_certificate /etc/nginx/cert/mail_acs-transporte.de.pem;
ssl_certificate_key /etc/nginx/cert/priv-key.pem;
# Redirect from "/" to "/owa" by default
rewrite ^/$ https://mail.acs-transporte.de/owa permanent;
# In the 'server' block for HTTPS traffic
client_max_body_size 3G;
location /owa { proxy_pass https://$exchange_server/owa;
more_set_input_headers 'Authorization: $http_authorization';
more_set_headers -s 401 'WWW-Authenticate: Basic realm="$exchange_server"';
}
location /ecp { proxy_pass https://$exchange_server/ecp;
more_set_input_headers 'Authorization: $http_authorization';
more_set_headers -s 401 'WWW-Authenticate: Basic realm="$exchange_server"';
}
location /Microsoft-Server-ActiveSync { proxy_pass https://$exchange_server/Microsoft-Server-ActiveSync;
more_set_input_headers 'Authorization: $http_authorization';
more_set_headers -s 401 'WWW-Authenticate: Basic realm="$exchange_server"';
}
location /Autodiscover { proxy_pass https://$exchange_server/Autodiscover;
more_set_input_headers 'Authorization: $http_authorization';
more_set_headers -s 401 'WWW-Authenticate: Basic realm="$exchange_server"';
}
location /autodiscover { proxy_pass https://$exchange_server/autodiscover;
more_set_input_headers 'Authorization: $http_authorization';
more_set_headers -s 401 'WWW-Authenticate: Basic realm="$exchange_server"';
}
location /mapi { proxy_pass https://exchange_backend;
proxy_http_version 1.1;
proxy_set_header Connection "Keep-Alive";
}
location /rpc { proxy_pass https://exchange_backend;
proxy_http_version 1.1;
proxy_set_header Connection "Keep-Alive";
}
location /Rpc { proxy_pass https://exchange_backend;
proxy_http_version 1.1;
proxy_set_header Connection "Keep-Alive";
}
location /ews { proxy_pass https://exchange_backend;
proxy_http_version 1.1;
proxy_set_header Connection "Keep-Alive";
}
location /EWS { proxy_pass https://exchange_backend;
proxy_http_version 1.1;
proxy_set_header Connection "Keep-Alive";
}
proxy_pass_request_headers on;
proxy_pass_header Date;
proxy_pass_header Server;
proxy_set_header Host $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 https;
proxy_set_header Accept-Encoding "";
proxy_buffering off;
proxy_request_buffering off;
error_log /var/log/nginx/exchange-error.log;
access_log /var/log/nginx/exchange-access.log;
listen [::]:80 ipv6only=on;
listen 80;
}
Letzter check mit nginx -t . Sollte alles passen könnt ihr nun mit Euren Outlook -Clients wieder verbinden ohne Abbrüche oder Passwort Aufforderungen.
Tipp: Installiert Euch noch NGINX-Certbot
sudo apt install certbot python3-certbot-nginx
Anschließend gebt Ihr in der Kommandozeile “certbot” einfach ein und Euch wird eine Auswahl präsentiert:

Anschließend sollten die Domainen erreichbar sein und die entsprechende Verschlüsselung von let’s encrypt haben. Hinweise: Stellt sicher das im Backend Eure Exchange erreichbar ist, hierfür würde ich die IP-Adresse direkt immer nehmen. Certbot erstellt nicht nur Certificates sonder verlängert diese auch automatisch verlängert. 😉
Microsoft hat RPC over HTTP abgekündigt (Link)
- RPC over HTTP ist abgekündigt von Microsoft und wir nicht mehr supportet.
- MAPI over HTTP ist der “neue” Standard welcher weiter verwendet wird von der Microsoft, hier gibt es bessere Möglichkeiten bietet.
Ich hoffe das diese Anleitung eine gute Hilfestellung gibt.