{"id":3762,"date":"2024-02-26T07:00:00","date_gmt":"2024-02-26T06:00:00","guid":{"rendered":"https:\/\/www.my-it-brain.de\/wordpress\/?p=3762"},"modified":"2024-01-08T20:09:58","modified_gmt":"2024-01-08T19:09:58","slug":"mit-einem-dualstack-reverse-proxy-internet-protokolle-verbinden","status":"publish","type":"post","link":"https:\/\/www.my-it-brain.de\/wordpress\/mit-einem-dualstack-reverse-proxy-internet-protokolle-verbinden\/","title":{"rendered":"Mit einem Dualstack-Reverse-Proxy Internet-Protokolle verbinden"},"content":{"rendered":"\n<p><a href=\"https:\/\/www.my-it-brain.de\/wordpress\/mit-einem-dualstack-proxy-internet-protokolle-verbinden\/\">Mit einem Dualstack-Proxy Internet-Protokolle verbinden<\/a> beschrieb eine M\u00f6glichkeit, um von Hosts, welche ausschlie\u00dflich \u00fcber IPv6-Adressen verf\u00fcgen, auf Ziele zugreifen zu k\u00f6nnen, die ausschlie\u00dflich \u00fcber IPv4-Adressen verf\u00fcgen. In diesem Beitrag betrachte ich die andere Richtung.<\/p>\n\n\n\n<p>Zu diesem Beitrag motiviert hat mich der <a href=\"https:\/\/www.my-it-brain.de\/wordpress\/ipv6-kein-anschluss-unter-dieser-nummer\/#comment-48426\">Kommentar von Matthias<\/a>. Er schreibt, dass er f\u00fcr den bei einem Cloud-Provider gehosteten Jenkins Build Server IPv4 deaktivieren wollte, um Kosten zu sparen. Dies war jedoch nicht m\u00f6glich, da Kollegen aus einem Co-Workingspace nur mit IPv4 angebunden sind und den Zugriff verloren h\u00e4tten.<\/p>\n\n\n\n<p>Doch wie kann man nun ein IPv6-Netzwerk f\u00fcr ausschlie\u00dflich IPv4-f\u00e4hige Clients erreichbar machen, ohne f\u00fcr jeden Host eine IPv4-Adresse zu buchen? Dazu m\u00f6chte ich euch anhand eines einfachen Beispiels eine m\u00f6gliche L\u00f6sung pr\u00e4sentieren.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Vorkenntnisse<\/h2>\n\n\n\n<p>Um diesem Text folgen zu k\u00f6nnen, ist ein grunds\u00e4tzliches Verst\u00e4ndnis von <a href=\"https:\/\/de.wikipedia.org\/wiki\/Domain_Name_System\">DNS<\/a>, dessen <a href=\"https:\/\/de.wikipedia.org\/wiki\/Resource_Record\">Resource Records<\/a> (RR) und des <a href=\"https:\/\/de.wikipedia.org\/wiki\/Host_(HTTP-Header-Feld)\">HTTP-Host-Header-Felds<\/a> erforderlich. Die Kenntnis der verlinkten Wikipedia-Artikel sollte hierf\u00fcr ausreichend sein.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Umgebung<\/h2>\n\n\n\n<p>Zu diesem Proof of Concept geh\u00f6ren:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ein Dualstack-Reverse-Proxy-Server (<a href=\"https:\/\/www.haproxy.org\/\">HAProxy<\/a>) mit den DNS-RR:\n<ul class=\"wp-block-list\">\n<li>haproxy.example.com. IN A 203.0.113.1<\/li>\n\n\n\n<li>haproxy.example.com IN AAAA 2001:DB8::1<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Zwei HTTP-Backend-Server mit den DNS-RR:\n<ul class=\"wp-block-list\">\n<li>www1.example.com IN AAAA 2001:DB8::2<\/li>\n\n\n\n<li>www2.example.com IN AAAA 2001:DB8::3<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Zwei DNS-RR:\n<ul class=\"wp-block-list\">\n<li>www1.example.com IN A 203.0.113.1<\/li>\n\n\n\n<li>www2.example.com IN A 203.0.113.1<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Ein Client mit einer IPv4-Adresse<\/li>\n<\/ul>\n\n\n\n<p>Ich habe mich f\u00fcr <a href=\"https:\/\/www.haproxy.org\/\">HAProxy<\/a> als Reverse-Proxy-Server entschieden, da dieser in allen Linux- und BSD-Distributionen verf\u00fcgbar sein sollte und mir die <a href=\"https:\/\/www.haproxy.com\/blog\/introduction-to-haproxy-maps\">HAProxy Maps<\/a> gefallen, welche ich hier ebenfalls vorstellen m\u00f6chte.<\/p>\n\n\n\n<p>Der Versuchsaufbau kann wie folgt skizziert werden:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"508\" height=\"321\" src=\"https:\/\/www.my-it-brain.de\/wordpress\/wp-content\/uploads\/2024\/01\/reverse-proxy-skizze.png\" alt=\"\" class=\"wp-image-3764\" srcset=\"https:\/\/www.my-it-brain.de\/wordpress\/wp-content\/uploads\/2024\/01\/reverse-proxy-skizze.png 508w, https:\/\/www.my-it-brain.de\/wordpress\/wp-content\/uploads\/2024\/01\/reverse-proxy-skizze-300x190.png 300w\" sizes=\"auto, (max-width: 508px) 100vw, 508px\" \/><figcaption class=\"wp-element-caption\">Ein Dualstack-Reverse-Proxy-Server (B) verbindet IPv4-Clients mit IPv6-Backend-Servern<\/figcaption><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">HAProxy-Konfiguration<\/h2>\n\n\n\n<p>F\u00fcr dieses Minimal-Beispiel besteht die HAProxy-Konfiguration aus zwei Dateien, der HAProxy Map <code>hosts.map<\/code> und der Konfigurationsdatei <code>poc.cfg<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>~]$ cat \/etc\/haproxy\/conf.d\/hosts.map \nwww1.example.com\tserversa\nwww2.example.com\tserversb<\/code><\/pre>\n\n\n\n<p>Eine <a href=\"https:\/\/www.haproxy.com\/blog\/introduction-to-haproxy-maps\">HAProxy Map<\/a> besteht aus zwei Spalten. In der ersten Spalte stehen die FQDNs, welche vom HTTP-Client aufgerufen werden k\u00f6nnen. In der zweiten Spalte steht der Name des Backends aus der HAProxy-Konfiguration, welcher bestimmt, an welche Backend-Server eine eingehende Anfrage weitergeleitet wird. In obigem Beispiel werden Anfragen nach <code>www1.example.com<\/code> an das Backend <code>serversa<\/code> und Anfragen nach <code>www2.example.com<\/code> an das Backend <code>serversb<\/code> weitergeleitet.<\/p>\n\n\n\n<p>Die HAProxy Maps lassen sich unabh\u00e4ngig von der HAProxy-Konfigurations-Datei pflegen und bereitstellen. Map-Dateien werden in ein Elastic Binary Tree-Format geladen, so dass ein Wert aus einer Map-Datei mit Millionen von Elementen ohne sp\u00fcrbare Leistungseinbu\u00dfen nachgeschlagen werden kann.<\/p>\n\n\n\n<p>Die HAProxy-Konfigurations-Datei <code>poc.cfg<\/code> f\u00fcr dieses Minimal-Beispiel ist \u00e4hnlich simpel:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>~]$ cat \/etc\/haproxy\/conf.d\/poc.cfg \nfrontend fe_main\n\tbind :80\n\tuse_backend %&#91;req.hdr(host),lower,map(\/etc\/haproxy\/conf.d\/hosts.map)]\n\nbackend serversa\n\tserver server1 2001:DB8::1:80\nbackend serversb\n\tserver server1 2001:DB8::2:80<\/code><\/pre>\n\n\n\n<p>In der ersten Zeile wird ein Frontend mit Namen <code>fe_main<\/code> definiert. Zeile 2 bindet Port 80 f\u00fcr den entsprechenden Prozess und Zeile 3 bestimmt, welches Backend f\u00fcr eingehende HTTP-Anfragen zu nutzen ist. Dazu wird der HTTP-Host-Header ausgewertet, falls notwendig, in Kleinbuchstaben umgewandelt. Mithilfe der Datei <code>hosts.map<\/code> wird nun ermittelt, welches Backend zu verwenden ist.<\/p>\n\n\n\n<p>Die weiteren Zeilen definieren zwei Backends bestehend aus jeweils einem Server, welcher auf Port 80 Anfragen entgegennimmt. In diesem Beispiel sind nur Server mit IPv6-Adressen eingetragen. IPv4-Adressen sind selbstverst\u00e4ndlich auch zul\u00e4ssig und beide Versionen k\u00f6nnen in einem Backend auch gemischt auftreten.<\/p>\n\n\n\n<p>Kann eine HTTP-Anfrage nicht \u00fcber die <code>hosts.map<\/code> aufgel\u00f6st werden, l\u00e4uft die Anfrage in diesem Beispiel in einen Fehler. F\u00fcr diesen Fall kann ein Standard-Backend definiert werden. Siehe hierzu den englischsprachigen Artikel <a href=\"https:\/\/www.haproxy.com\/blog\/introduction-to-haproxy-maps\">Introduction to HAProxy Maps<\/a> von <a href=\"https:\/\/www.haproxy.com\/blog\/author\/clavoie\">Chad Lavoie<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Der Kommunikationsablauf im \u00dcberblick und im Detail<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"508\" height=\"494\" src=\"https:\/\/www.my-it-brain.de\/wordpress\/wp-content\/uploads\/2024\/01\/dualstack-reverse-proxy-poc.png\" alt=\"\" class=\"wp-image-3767\" srcset=\"https:\/\/www.my-it-brain.de\/wordpress\/wp-content\/uploads\/2024\/01\/dualstack-reverse-proxy-poc.png 508w, https:\/\/www.my-it-brain.de\/wordpress\/wp-content\/uploads\/2024\/01\/dualstack-reverse-proxy-poc-300x292.png 300w\" sizes=\"auto, (max-width: 508px) 100vw, 508px\" \/><figcaption class=\"wp-element-caption\">Der Kommunikationsablauf im \u00dcberblick<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Von einem IPv4-Client aus benutze ich <code>curl<\/code>, um die Seite <code>www1.example.com<\/code> abzurufen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>~]$ curl -4 -v http:\/\/www1.example.com\n* processing: http:\/\/www1.example.com\n*   Trying 203.0.113.1:80...\n* Connected to www1.example.com (203.0.113.1) port 80\n&gt; GET \/ HTTP\/1.1\n&gt; Host: www1.example.com\n&gt; User-Agent: curl\/8.2.1\n&gt; Accept: *\/*\n&gt; \n&lt; HTTP\/1.1 200 OK\n&lt; server: nginx\/1.20.1\n&lt; date: Sat, 06 Jan 2024 18:44:22 GMT\n&lt; content-type: text\/html\n&lt; content-length: 5909\n&lt; last-modified: Mon, 09 Aug 2021 11:43:42 GMT\n&lt; etag: \"611114ee-1715\"\n&lt; accept-ranges: bytes\n&lt; \n&lt;!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD XHTML 1.1\/\/EN\" \"http:\/\/www.w3.org\/TR\/xhtml11\/DTD\/xhtml11.dtd\"&gt;\n\n&lt;html xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\" xml:lang=\"en\"&gt;\n\t&lt;head&gt;\n\t\t&lt;title&gt;Test Page for the HTTP Server on Red Hat Enterprise Linux&lt;\/title&gt;<\/code><\/pre>\n\n\n\n<p>Der FQDN <code>www1.example.com<\/code> wird mit der IPv4-Adresse <code>203.0.113.1<\/code> aufgel\u00f6st, welche dem Host <code>haproxy.example.com<\/code> geh\u00f6rt. Bei der Zeile <code>Host: www1.example.com<\/code> handelt es sich um den HTTP-Host-Header, welchen  der HAProxy ben\u00f6tigt, um das richtige Backend auszuw\u00e4hlen.<\/p>\n\n\n\n<p>Es ist zu sehen, dass wir eine Antwort von einem NGINX-HTTP-Server erhalten. Der HTML-Quelltext wurde gek\u00fcrzt.<\/p>\n\n\n\n<p>Damit ist es gelungen, von einem IPv4-Client eine Ressource abzurufen, die von einem IPv6-Server bereitgestellt wird.<\/p>\n\n\n\n<p>Im Access-Log des Backend-Servers mit der IPv6-Adresse <code>2001:DB8::2<\/code> sieht man:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>2001:DB8::1 - - &#91;06\/Jan\/2024:19:44:22 +0100] \"GET \/ HTTP\/1.1\" 200 5909 \"-\" \"curl\/8.2.1\" \"192.0.2.1\"<\/code><\/pre>\n\n\n\n<p>Die Anfrage erreicht den Backend-Server von der IPv6-Adresse des <code>haproxy.example.com<\/code> (<code>2001:DB8::1<\/code>). Die am Ende der Zeile zu sehende IPv4-Adresse (<code>192.0.2.1<\/code>) geh\u00f6rt dem IPv4-Client, von dem ich die Anfrage gesendet habe.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Gedanken zur Skalierung<\/h2>\n\n\n\n<p>In diesem Beispiel sind die Server <code>www1.example.com<\/code> und <code>www2.example.com<\/code> \u00fcber ihre IPv6-Adressen direkt erreichbar. Nur die Client-Anfragen von IPv4-Clients laufen \u00fcber den Reverse-Proxy. Wenn man es w\u00fcnscht, kann man selbstverst\u00e4ndlich s\u00e4mtliche Anfragen (von IPv4- und IPv6-Clients) \u00fcber den Reverse-Proxy laufen lassen.<\/p>\n\n\n\n<p>In kleinen Umgebungen kann man einen Reverse-Proxy wie HAProxy zusammen mit Squid (vgl. Artikel <a href=\"https:\/\/www.my-it-brain.de\/wordpress\/mit-einem-proxy-internet-protokolle-verbinden\/\">Mit einem Dualstack-Proxy Internet-Protokolle verbinden<\/a>) auf einem Host laufen lassen. Selbstverst\u00e4ndlich kann man sie auch auf separate Hosts verteilen.<\/p>\n\n\n\n<p>Hochverf\u00fcgbarkeit l\u00e4sst sich auch hier mit <a href=\"https:\/\/keepalived.org\/\">keepalived<\/a> nachr\u00fcsten:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.ibm.com\/docs\/en\/linux-on-z?topic=available-keepalived-haproxy\">Keepalived and HAProxy<\/a> in IBM Documentation<\/li>\n\n\n\n<li><a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_enterprise_linux\/7\/html\/load_balancer_administration\/s2-lvs-keepalived-haproxy-vsa\">Chapter 1.3. keepalived and haproxy<\/a> in RHEL 7 Documentation<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Abschlie\u00dfende Gedanken<\/h2>\n\n\n\n<p>Die Internet-Protokolle IPv4 und IPv6 werden wohl noch eine ganze Zeit gemeinsam das Internet bestimmen und parallel existieren. Ich bin mir sogar sicher, dass ich das Ende von IPv4 nicht mehr miterleben werde. Dualstack-(Reverse)-Proxy-Server stellen eine solide und robuste L\u00f6sung dar, um beide Welten miteinander zu verbinden.<\/p>\n\n\n\n<p>Sicher bleiben noch ausreichend Herausforderungen \u00fcbrig. Ich denke da nur an Firewalls, Loadbalancer, NAT und Routing. Und es werden sich auch F\u00e4lle finden lassen, in denen Proxyserver nicht infrage kommen. Doch mit diesen Herausforderungen besch\u00e4ftige ich mich dann in anderen Artikeln.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Quellen und weiterf\u00fchrende Links<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/de.wikipedia.org\/wiki\/Domain_Name_System\">https:\/\/de.wikipedia.org\/wiki\/Domain_Name_System<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/de.wikipedia.org\/wiki\/Hypertext_Transfer_Protocol\">https:\/\/de.wikipedia.org\/wiki\/Hypertext_Transfer_Protocol<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/de.wikipedia.org\/wiki\/Host_(HTTP-Header-Feld)\">https:\/\/de.wikipedia.org\/wiki\/Host_(HTTP-Header-Feld)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/de.wikipedia.org\/wiki\/Resource_Record\">https:\/\/de.wikipedia.org\/wiki\/Resource_Record<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc2606.html\">https:\/\/www.rfc-editor.org\/rfc\/rfc2606.html<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc3849.html\">https:\/\/www.rfc-editor.org\/rfc\/rfc3849.html<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc5737.html\">https:\/\/www.rfc-editor.org\/rfc\/rfc5737.html<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.haproxy.org\/\">https:\/\/www.haproxy.org\/<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.haproxy.com\/blog\/introduction-to-haproxy-maps\">https:\/\/www.haproxy.com\/blog\/introduction-to-haproxy-maps<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/keepalived.org\/\">https:\/\/keepalived.org\/<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.ibm.com\/docs\/en\/linux-on-z?topic=available-keepalived-haproxy\">Keepalived and HAProxy<\/a> in IBM Documentation<\/li>\n\n\n\n<li><a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_enterprise_linux\/7\/html\/load_balancer_administration\/s2-lvs-keepalived-haproxy-vsa\">Chapter 1.3. keepalived and haproxy<\/a> in RHEL 7 Documentation<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Mit einem Dualstack-Proxy Internet-Protokolle verbinden beschrieb eine M\u00f6glichkeit, um von Hosts, welche ausschlie\u00dflich \u00fcber IPv6-Adressen verf\u00fcgen, auf Ziele zugreifen zu k\u00f6nnen, die ausschlie\u00dflich \u00fcber IPv4-Adressen verf\u00fcgen. In diesem Beitrag betrachte ich die andere Richtung. Zu diesem Beitrag motiviert hat mich der Kommentar von Matthias. Er schreibt, dass er f\u00fcr den bei einem Cloud-Provider gehosteten Jenkins<span class=\"continue-reading\"> <a href=\"https:\/\/www.my-it-brain.de\/wordpress\/mit-einem-dualstack-reverse-proxy-internet-protokolle-verbinden\/\">[Weiterlesen&#8230;]<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_metis_text_type":"","_metis_text_length":0,"_post_count":0,"footnotes":""},"categories":[51],"tags":[825,824,826,821,430,305,610],"class_list":["post-3762","post","type-post","status-publish","format-standard","hentry","category-linux","tag-dualstack","tag-haproxy","tag-ipv4","tag-ipv6","tag-osbn","tag-planet","tag-reverse-proxy"],"_links":{"self":[{"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/posts\/3762","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/comments?post=3762"}],"version-history":[{"count":7,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/posts\/3762\/revisions"}],"predecessor-version":[{"id":3774,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/posts\/3762\/revisions\/3774"}],"wp:attachment":[{"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/media?parent=3762"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/categories?post=3762"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/tags?post=3762"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}