Wartungsseite für alle Apache vhosts eines Webservers realisieren

Über eine Lösung um einen einzelnen Apache Vhost mit einer Wartungsseite auszustatten habe ich bereits vor einigen Jahren hier geschrieben.

Jetzt stand ich vor der Aufgabe wegen Wartungsarbeiten auf meinem Webserver eine Wartungsseite für alle dort gehosteten Apache Vhosts zu schalten. Davor sitzt ein Gate-Server mit Apache und mod_proxy. Eine Lösung das zu realisieren wäre auf dem Gate-Server mit mod_rewrite nach dem Vorhandensein einer Maintenance-Datei zu schauen und wenn die Bedingung zutrifft alle Anfragen auf die Wartungsseite weiterzuleiten. Eine solche Lösung ist in Ansätzen unter anderem hier skizziert. Unschön finde ich dabei die unnötig vielen Prüfungen nach der Maintenance-Datei.

Ich habe nun eine andere Lösung realisiert, die in meinen Augen deutlich einfacher und eleganter ist. Auf dem Gate-Server lasse ich einen Apache-Vhost auf einem gesonderten Port laufen auf dem die Wartungsseite angezeigt wird. Für den Fall, dass ich die Wartungsseite vorschalten möchte, leite ich einfach allen HTTP und HTTPS Traffic auf die IP des Gate-Servers und den gesonderten Port um. Mit nur einer iptables Regel ist somit für alle vhosts auf dem Webserver eine Wartungsseite vorgeschaltet:

iptables -t nat -A OUTPUT -p tcp -d INTERNALWEBSERVERIP --match multiport --dports 80,443 -j DNAT --to-destination EXTERNALGATESERVERIP:PORT

Bei dem Apache Vhost auf dem Gateserver ist noch zu beachten, dass man nach Möglichkeit den aufrufenden Browsern / Bots etc. mitteilt, dass es sich um etwas temporäres handelt. Aus diesem Grund habe ich in dem Vhost zwei Dinge beachtet:

  1. Es wird ein HTTP Status Code 503 (Temporarily Unavailable) gesendet
  2. Es wird der HTTP Header Retry-After gesetzt

Im vhost sieht das wie folgt aus. Spannend sind die letzten 3 Zeilen. Meine Wartungsseite heißt übrigens auch 503.html

<VirtualHost *:PORT>
  ServerName maintenance.example.net
  ServerAdmin webmaster@example.net
 
  DocumentRoot "/var/www/maintenance"
 
  <Directory "/var/www/maintenance">
    Options -Indexes
    AllowOverride None
    Require all granted
  </Directory>
 
 
  ErrorLog "/var/log/apache2/maintenance.example.net_error.log"
  CustomLog "/var/log/apache2/maintenance.example.net_access.log" combined 
 
  RedirectMatch 503  ^/(?!503.html)  
  ErrorDocument 503 /503.html
  Header always set Retry-After "18000"
</VirtualHost>

Apache2 mod_proxy und mod_rpaf

Mein Webserver ist in einem internen Netz und davor sitzt ein Apache Webserver der die Anfragen mittels mod_proxy nach hinten weiterreicht. Damit in den Logfiles des internen Webservers dennoch die korrekten IP Adressen auftauchen muss dort das Apache Modul rpaf installiert und konfiguriert werden.

Vor der Installation und Konfiguration sehen bei mir die Logeintraege wie folgt aus:

[Sat Nov 09 18:32:14 2013] [error] [client 10.10.10.10] File does not exist: /var/www/foobar

Die Installation des Moduls erfolgt bei Debian aus den Paketquellen:

apt-get install libapache2-mod-rpaf

Anschliessend muss das Modul aktiviert werden:

a2enmod rpaf

Konfiguriert wird es in der Datei /etc/apache2/mods-enabled/rpaf.conf. Dort muss die IP des oder der Proxy-Server entsprechend hinzugefuegt werden. In dem Beispiel oben ist 10.10.10.10 der Proxy-Server und wird entsprechend unter RPAFproxy_ips hinzugefuegt:

<IfModule rpaf_module>
    RPAFenable On
 
    # When enabled, take the incoming X-Host header and
    # update the virtualhost settings accordingly:
    RPAFsethostname On
 
    # Define which IP's are your frontend proxies that sends
    # the correct X-Forwarded-For headers:
    RPAFproxy_ips 10.10.1.2
 
    # Change the header name to parse from the default
    # X-Forwarded-For to something of your choice:
#   RPAFheader X-Real-IP
</IfModule>

Nach dem Neustart des Apache Webservers steht dann die korrekte IP in der Logdatei:

[Sat Nov 09 18:46:32 2013] [error] [client 77.176.69.123] File does not exist: /var/www/foobar