Skip to content

Instantly share code, notes, and snippets.

@jpawlowski
Last active November 24, 2020 18:08
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jpawlowski/9774485256beb98e1bf0 to your computer and use it in GitHub Desktop.
Save jpawlowski/9774485256beb98e1bf0 to your computer and use it in GitHub Desktop.
Setup HAproxy on an Uberspace webspace

HAproxy als Reverse Proxy auf Uberspace installieren

Wer bei verschiedenen Reverse Proxy Aktivitäten auf seinem Uberspace mit Apache auf Grenzen stößt, kann HAproxy installieren. Ähnlich wie Pound ist es DASein Swiss Army Knife für alle HTTP, HTTPS und TCP Aktivitäten. Man kann sehr granular auf Layer 3-7 beeinflussen, wie Daten an andere Server und Dienste weitergeschleust werden sollen.

Ich benötigte HAproxy, um eine Website von einem externen Server via TLS gesichert per Uberspace verfügbar zu machen, also ein recht simles Szenario.

Apache Proxy einrichten

Wahrscheinlich möchte man gerne, dass HAproxy über Port 80 und 443 erreichbar ist. Natürlich sind diese Ports bereits von Uberspace's Pound belegt. Pound leitet aber seine Anfragen an Apache weiter und den können wir wie hier beschrieben über eine .htaccess Datei konfigurieren, um Anfragen an unseren eigenen HAproxy weiterzuleiten:

[mareike@neon html]$ cat .htaccess
RewriteEngine On
RewriteRule (.*) http://localhost:64223/$1 [P]

Der Port ist dabei derjenige, auf den wir unseren HAproxy später lauschen lassen. Bitte unbedingt die Hinweise für die Wahl eines Ports beachten! Durch RewriteCond kann noch weiter eingeschränkt werden, wann die Anfragen an HAproxy weitergereicht werden.

Wer zum Beispiel einfach alle Domains, die nicht auf dem Uberspace über ein Verzeichnis angelegt sind, an HAproxy weiterreichen möchte, kann dies hiermit tun:

RewriteCond /var/www/virtual/hund/%{HTTP_HOST} !-d
RewriteCond %{HTTP:X-Forwarded-Server} ^$
RewriteCond %{HTTP_HOST} !^[A-Za-z0-9]+\.[A-Za-z]+\.uberspace\.de$
RewriteRule (.*) http://127.0.0.1:61578/$1 [P]

Das User Verzeichnis hund muss dabei natürlich entsprechend angepasst werden. Wer die Uberspace-Subdomains auch ausschließen möchte ohne dafür jeweils ein Verzeichns oder einen Symlink anzulegen, ändert das RegEx auf !^.*\.[A-Za-z0-9]+\.[A-Za-z]+\.uberspace\.de$ ab. Um einen Loop zu vermeiden, prüfen wir außerdem auf das Vorhandensein des Headers X-Forwarded-Server, welchen HAproxy automatisch hinzufügt.

HAproxy installieren

Jetzt geht es ans Werk. Zunächst laden wir uns die aktuellen Sourcen:

[hund@menkar ~]$ wget -P ~/src http://www.haproxy.org/download/1.6/src/haproxy-1.6.4.tar.gz

Anschließend entpacken wir diese und wechseln in das entsprechende Verzeichnis:

[hund@menkar ~]$ tar xfz ~/src/haproxy-1.6.4.tar.gz -C ~/src; cd ~/src/haproxy-*

Anschließend wird HAproxy mit dem folgenden Befehl übersetzt:

[hund@menkar haproxy-1.6.4]$ make TARGET=linux26 USE_OPENSSL=1 USE_ZLIB=1 ADDLIB=-lz

Nun können wir HAproxy in unserem User Verzeichnis installieren:

[hund@menkar haproxy-1.6.4]$ make PREFIX=$HOME/bin/haproxy install

HAproxy wurde damit unter ~/bin/haproxy/sbin/haproxy installiert. Abschließend räumen wir noch etwas auf, um Speicherplatz zu sparen:

[hund@menkar haproxy-1.6.4]$ cd ~; rm -rf ~/src/haproxy-*

HAproxy konfigurieren

Jetzt legen wir eine kleine Beispielkonfiguration für HAproxy an. Hier wird ein Backend angelegt, welches nur beim Zugriff auf den Hostnamen example.hund.menkar.uberspace.de reagiert:

[hund@menkar ~]$ mkdir ~/etc/haproxy
[hund@menkar ~]$ cat >> ~/etc/haproxy/haproxy.cfg <<__EOF__
global

frontend HTTP
	bind			127.0.0.1:64223
	mode			http
	timeout client		5000
	
	acl			a_example hdr(X-Forwarded-Host) -i example.hund.menkar.uberspace.de
	use_backend		b_example if a_example

	default_backend		uberspace_81

backend uberspace_81
	mode	http
	timeout connect		3000
	timeout server		3000
	server	uberspace 95.143.172.241:81

backend b_example
	mode	http
	timeout connect		5000
	timeout server		7200000
	server	server1-a www.example.com:443 ssl ca-file /etc/ssl/certs/ca-bundle.trust.crt

__EOF__

Alle Anfragen, die HAproxy auf Port 64223 für den Hostnamen example.hund.menkar.uberspace.de beantwortet, werden somit TLS verschlüsselt an den Webserver weitergereicht, der unter www.example.com auf Port 443 lauscht. Wenn auf der Gegenseite kein valides Zertifikat vorliegt, gibt man hinter ssl einfach verify none an statt ca-file.

Verschlüsselung für Zugriffe

Für die Verschlüsselung in Richtung des Browsers sollte für den Uberspace unbedingt ein Zertifikat eingespielt werden (z.B. von LetsEncrypt).

Rückverbindung zum Uberspace Apache

Wenn HAproxy für einen nicht konfigurierten Hostnamen angesprochen wird, dann zeigt dieser normalerweise eine interne 503er Fehlerseite an. Um stattdessen die Fehlerseiten zu verwenden, die der Apache des Uberspace ausgibt, werden alle unbekannten Anfragen zurück an den lokalen Apache von Uberspace zurück gegeben. Um den Loop hier zu vermeiden ist es deshalb sehr wichtig in der .htaccess wie oben genannt auf das Vorhandensein der X-Forwarded Header zu prüfen. Die IP-Adresse des uberspace Servers beim Backend uberspace_81 muss natürlich je nach Host entsprechend angepasst werden, sonst landen die Anfragen auf dem falschen Uberspace Server.

Backend mit SNI

Es ist wohl häufig so, dass der Backend Webserver seine Seite nur dann richtig ausliefert, wenn man den richtigen Hostnamen mitschickt. Der HAproxy übernimmt zunächst den Hostnamen, welche der Browser angesprochen hat. Um dies für die Weiterleitung an den Backend Server zu ändern, kann man dem Backend noch diese Zeilen hinzufügen:

reqirep ^Host: Host:\ www.example.com
rspirep ^Location:\ https://www.example.com(.*)      Location:\ https://example.hund.menkar.uberspace.de\1
rspirep ^Location:\ http://www.example.com(.*)       Location:\ https://example.hund.menkar.uberspace.de\1

HAproxy als Dienst starten

Wir können HAproxy nun bereits manuell starten:

[hund@menkar ~]$ ~/bin/haproxy/sbin/haproxy -D -f ~/etc/haproxy/haproxy.cfg

Komfortabler zum staren und stoppen ist es allerdings einen Dienst über die daemontools einzurichten. Wir beenden also HAproxy erstmal wieder:

[hund@menkar ~]$ killall haproxy

Anschließend richten wir den Dienst ähnlich wie in der verlinkten Anleitung beschrieben ein. Als Service-Verzeichnis bietet sich ~/etc/haproxy an; dort wo wir bereits unsere haproxy.cfg liegen haben.

Die Datei run für den Dienst kann so aussehen:

[hund@menkar ~]$ cat ~/etc/haproxy/run 
#!/bin/sh
exec ~/bin/haproxy/sbin/haproxy -f ~/etc/haproxy/haproxy.cfg 2>&1

Nachdem der Dienst aktiviert wurde, läuft HAproxy und nimmt die Anfragen, die der Apache weiterleitet, für uns an:

[hund@menkar ~]$ ps aux | grep haproxy
hund      9775  0.0  0.0  44660  3124 ?        S    22:07   0:00 /home/hund/bin/haproxy/sbin/haproxy -f /home/hund/etc/haproxy/haproxy.cfg
hund     23556  0.0  0.0 103304   876 pts/9    S+   22:09   0:00 grep haproxy
hund     29021  0.0  0.0   3932   392 ?        S    20:35   0:00 supervise haproxy
[hund@menkar ~]$

Ab sofort schränken uns nur noch die Grenzen von HAproxy ein (und das sind nicht sonderlich viele 😉).

@MarcJandt
Copy link

Vielen herzlichen Dank!
Für andere 2.0-User auf einem Uberspace 6 die alternative make-Zeile:
make TARGET=linux-glibc USE_NS= USE_OPENSSL=1 USE_ZLIB=1 ADDLIB=-lz
Und für noch neuere Versionen der folgende Hinweis, der von der 2.0 ausgespuckt wird:

The 'reqirep' directive is deprecated in favor of 'http-request replace-header' and will be removed in next version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment