Apache Httpd als Revere Proxy für den enaio Gateway unter Windows

In bestimmten Fällen hatten wir bei Kunden die Herausforderung vor den enaio Gateway einen Reverse Proxy zu schalten um zum Beispiel einen anderen enaio unabhängigen Service hinter die selbe Adresse zu stellen.
Zum Beispiel um den ONLYOFFICE Service für embedded office hinter die selbe Adresse zu legen und damit mögliche Cross-Site-Scripting Einschränkungen zu vermeiden.

In dem meisten Fällen gibt es beim Kunden bereits einen entsprechenden zentralen ReverseProxy der diese Aufgabe übernehmen kann.

Hin und wieder muss dies aber direkt im Kontext der enaio Installation gelöst werden.

Um dies zu realisieren, kann zum Beispiel der NGINX Service verwendet werden. Dieser hat aber den Nachteil, dass NGINX NTLM-Autorisierungen nicht korrekt weiterleitet.

Eine weitere Option ist der Apache HTTPD Service:

Der Apache HTTPD wird Offiziell nur für Linux bereitgestellt. Es gibt jedoch schon seit langer Zeit eine passende Windows Version unter:

https://www.apachehaus.com/cgi-bin/download.plx

Das heruntergeladene Zip (in meinem Fall httpd-2.4.48-o111k-x64-vc15.zip) einfach an einen passenden Ort entpacken.

Anschliessend im Ordner confdie Datei httpd.conf öffnen.
Diese Datei ist mit diversen Beispielen befüllt und daher ziemlich unübersichtlich.
Für einen ReverseProxy benötigt es aber nicht sehr viele Einträge.

Einfacher Proxy

  • enaio Gateway läuft auf dem Port 81
  • Reverse Proxy soll die Anfragen einfach weiterleiten
Define SRVROOT "C:\enaio\httpd"
ServerRoot "${SRVROOT}"
Listen 80

ServerAdmin info@ecmind.ch
ServerName MeinServer.ecmind:80

#
# Dynamic Shared Object (DSO) Support
#
LoadModule authz_core_module modules\mod_authz_core.so

LoadModule proxy_module modules\mod_proxy.so
LoadModule headers_module modules\mod_headers.so
LoadModule proxy_balancer_module modules\mod_proxy_balancer.so
LoadModule proxy_http_module modules\mod_proxy_http.so
LoadModule proxy_http2_module modules\mod_proxy_http2.so
LoadModule lbmethod_bybusyness_module modules\mod_lbmethod_bybusyness.so
LoadModule lbmethod_byrequests_module modules\mod_lbmethod_byrequests.so
LoadModule lbmethod_bytraffic_module modules\mod_lbmethod_bytraffic.so
LoadModule lbmethod_heartbeat_module modules\mod_lbmethod_heartbeat.so
LoadModule slotmem_shm_module modules\mod_slotmem_shm.so
LoadModule socache_shmcb_module modules\mod_socache_shmcb.so

LoadModule log_config_module modules\mod_log_config.so

ErrorLog "logs/error.log"
LogLevel warn

<IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    <IfModule logio_module>
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>
    CustomLog "logs/access.log" common
</IfModule>

<VirtualHost * >
	ProxyPreserveHost On
	ProxyPass / http://localhost:81
	ProxyPassReverse / http://localhost:81
</VirtualHost>

Load Balancing

  • enaio Gateway läuft auf zwei anderen Servern
  • Die Benutzer sollen auf die Gateways verteilt werden
  • Pro Benutzer soll aber nach Möglichkeit immer der gleiche Gateway verwendet werden (Sticky Session)
Define SRVROOT "C:\enaio\httpd"
ServerRoot "${SRVROOT}"
Listen 80

ServerAdmin info@ecmind.ch
ServerName MeinServer.ecmind:80

#
# Dynamic Shared Object (DSO) Support
#
LoadModule authz_core_module modules\mod_authz_core.so

LoadModule proxy_module modules\mod_proxy.so
LoadModule headers_module modules\mod_headers.so
LoadModule proxy_balancer_module modules\mod_proxy_balancer.so
LoadModule proxy_http_module modules\mod_proxy_http.so
LoadModule proxy_http2_module modules\mod_proxy_http2.so
LoadModule lbmethod_bybusyness_module modules\mod_lbmethod_bybusyness.so
LoadModule lbmethod_byrequests_module modules\mod_lbmethod_byrequests.so
LoadModule lbmethod_bytraffic_module modules\mod_lbmethod_bytraffic.so
LoadModule lbmethod_heartbeat_module modules\mod_lbmethod_heartbeat.so
LoadModule slotmem_shm_module modules\mod_slotmem_shm.so
LoadModule socache_shmcb_module modules\mod_socache_shmcb.so

LoadModule log_config_module modules\mod_log_config.so

ErrorLog "logs/error.log"
LogLevel warn

<IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    <IfModule logio_module>
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>
    CustomLog "logs/access.log" common
</IfModule>

<VirtualHost * >
	<Proxy balancer://gateway>
			BalancerMember http://server1 route=Server1
			BalancerMember http://server2 route=Server2
			ProxySet stickysession=ROUTEID
	</Proxy>
	ProxyPreserveHost On
	ProxyPass / balancer://gateway/
	ProxyPassReverse / balancer://gateway/
	
	Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
</VirtualHost>

Proxy mit ONLYOFFICE

  • enaio Gateway läuft auf dem Port 81
  • ONLYOFFICE läuft auf einem weiteren Server und ist unter /onlyoffice eingehängt
Define SRVROOT "C:\enaio\httpd"	
ServerRoot "${SRVROOT}"
Listen 80

ServerAdmin info@ecmind.ch
ServerName meinserver.ecmind:80

#
# Dynamic Shared Object (DSO) Support
#
LoadModule authz_core_module modules\mod_authz_core.so

LoadModule setenvif_module modules\mod_setenvif.so 
LoadModule rewrite_module modules\mod_rewrite.so
LoadModule proxy_module modules\mod_proxy.so
LoadModule headers_module modules\mod_headers.so
LoadModule proxy_balancer_module modules\mod_proxy_balancer.so
LoadModule proxy_http_module modules\mod_proxy_http.so
LoadModule proxy_http2_module modules\mod_proxy_http2.so
LoadModule lbmethod_bybusyness_module modules\mod_lbmethod_bybusyness.so
LoadModule lbmethod_byrequests_module modules\mod_lbmethod_byrequests.so
LoadModule lbmethod_bytraffic_module modules\mod_lbmethod_bytraffic.so
LoadModule lbmethod_heartbeat_module modules\mod_lbmethod_heartbeat.so
LoadModule slotmem_shm_module modules\mod_slotmem_shm.so
LoadModule socache_shmcb_module modules\mod_socache_shmcb.so

LoadModule log_config_module modules\mod_log_config.so

ErrorLog "logs/error.log"
LogLevel warn

<IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    <IfModule logio_module>
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>
    CustomLog "logs/access.log" common
</IfModule>


<VirtualHost * >
	ProxyPreserveHost On

	<Location /onlyoffice>
	  Require all granted
	  SetEnvIf Host "^(.*)$" THE_HOST=$1
	  RequestHeader setifempty X-Forwarded-Proto http
	  RequestHeader setifempty X-Forwarded-Host %{THE_HOST}e
	  RequestHeader edit X-Forwarded-Host (.*) $1/onlyoffice
	  ProxyAddHeaders Off
	</Location>

	ProxyPassMatch ^\/onlyoffice(.*)(\/websocket)$ "ws://ooserver:20080/$1$2"

	ProxyPass /onlyoffice "http://ooserver:20080"
	ProxyPassReverse /onlyoffice "http://ooserver:20080"

	ProxyPass / http://localhost:81/
	ProxyPassReverse / http://localhost:81/
	
</VirtualHost>

Den httpd kann man einfach über eine CMD (im Administrator Modus) per httpd.exe -K install als Windows Service registrieren.

Per httpd.exe -k uninstall kann der Service bei bedarf wieder entfernt werden.