[Docker|Nginx|IPv6] IPv6 $Remote_IP im access.log sehen, anstatt IPv4 Gateway

  • Hallo liebe Leute,


    ich habe ein Problem mit Docker IPv6 Nginx.


    Aufbau (alles im Container):

    1x NGINX Webserver

    1x MariaDB Server

    1x PHP-FPM

    1x memcached

    1x robbertkl/ipv6nat


    Ziel:

    Im access.log im Nginx Container die $Remote_IP zu sehen, welche die Webseite anfragt.


    Produkt:

    1x Netcup Root-Server G8


    Stand der Dinge:


    Container NGINX ist via IPv6 NAT erreichbar. Ich kann meine Webseite aufrufen. Aus dem Container heraus kann ich auch "ping6 google.com" ausführen und auch mit "curl [IPv6] 80" Webseiten via IPv6 erreichen.

    Nur, surfe ich via IPv6 only mit meinem Desktop-Rechner auf meine Webseite, so sehe ich nur mein IPv4 Gateway in den NGINX Containerlogs.


    Was muss ich unternehmen um in NGINX im access.log die $Remote_IP sehen zu können?


    Besten Dank schon im Voraus für Eure Hilfe

    p_s

  • Du musst den Containern eine echte, geroutete IPv6 Adresse verpassen. Bei DNAT funktioniert das halt so, dass der Container nur die IP von der Zwischenstelle kennt. Das lässt sich auch nicht verhindern.


    Sofern Du mit "IPv4 Gateway" einen Reverse Proxy oder ähnliches meinst, kannst Du auch die Quell-IPv6 via Header durchreichen. Das erfordert dann aber eine entsprechende Logik im Container-NGINX.

  • 1. /etc/docker/daemon.json um "ipv6": true, "fixed-cidr-v6": "2a03:4000:bade:affe:1::/80" und "default-gateway-v6": "2a03:4000:bade:affe::1" ergänzen und den Docker Daemon neu starten.


    2. Dem Container eine fixe IPv6 zuweisen, macht das Leben einfacher


    3. ndppd installieren und konfigurieren


    2a03:4000:bade:affe:1::/80 ist ein Subnetz unterhalb deines dir zugewiesenen Subnetzes.

  • Hallo perryflynn,


    danke Dir für deine Antwort.


    Mit IPv4 Gateway meine ich, das docker IPv4 Gateway, welches meist 172.20.X.X bei mir ist. Das stammt von der Netzwerkschnittstelle docker0.


    Okay, also muss ich den NGINX-Container direkt mit einer IPv6 versorgen.


    Werde mal diese Anleitung versuchen. Es gab hier im NetCup Forum schon eine Diskussion, ob man einen NDP Proxy benötigt oder nicht.

    Ich habe ausschließlich eine IPv6/64 erhalten. Wenn ich das gesamte Netz an die eth0 Netzwerkschnittstelle "hänge" und dann in der daemon.json eine IPV6/80 angebe, dann sollte das doch direkt funktionieren und direkt pingbar sein. Frage stammt daher, weil sich einer extra ein zusätzliches IPv6 Netz kaufte.


    Aufbau:

    2001:db8::/64 an eth0 // primäre Netzerkschnittstelle

    | |

    2001:db8:a::/80 an docker0 // automatisch via daemon.json

    | |

    ip -6 route add 2001:db8:a::/80 dev docker0

    | |

    via sysctl IPv6 FORWARD aktivieren

    | |

    fertig --> iptables konfiguriert docker selbst beim dockerd Start.


    daemon.json

    Code
    {
      "ipv6": true,
      "fixed-cidr-v6": "2001:db8:a::/80"
    }


    Dann via docker-compose:



    Ich gehe mal davon aus, dass der Container sich dann doch noch via NDP Proxy bekannt machen muss, dass er eben an docker0 hängt und dort verfügbar ist!? Oder muss er das nicht, weil IPv6 FORWARD aktiv ist und das IPv6/80 direkt an docker0 hängt und daher via "ip -6 route add ***" direkt an ihn weitergeleitet wird!?

  • Okay, H6G, ich habe das mal so ausprobiert. Dabei stoße ich auf das Problem, dass ich das Default-Gateway leider so nicht anlegen kann, da dockerd immer gleich sagt, dass "2001:db8:a::1" schon benutzt wird. Schaue ich mit "ip -6 addr show" nach, hat die IP-Adresse noch niemand. Also löschte ausschließlich in der daemon.json mal das IPv6 Gateway raus und der dockerd startet und weißt docker0 direkt die "2001:db8:a::1" zu. Dann lud ich via


    docker run -itd -p 80:80 nginx


    Daraufhin erhält der Container auch eine IP aus dem "2001:db8:a::/80" nämlich die "2001:db8:a:42:ac11:2" und ist pingbar! Das ist super, aber dennoch komme ich nicht via "curl [2001:db8:a:42:ac11:2] 80" oder Firefox auf die Webseite. In ufw habe ich aber Port 80(v6) auf ALLOW gestellt.


    Was fehlt mir noch? ip6tables sollten ja durch ufw übernommen und komplett konfiguriert sein.


    Btw.:

    Wenn ich mit docker-compose arbeiten will, dann habe ich das Problem, dass docker das Netz "2001:db8:a::/80" der "Docker Standard Bridge" zuweist und ich daher via docker-compose immer den Fehler erhalte, dass das Netz ja schon benutzt werde. Eine Verwendung von docker-compose.yml mit 'network external "bridge"' brachte keinen Erfolg. Mein normaler NGINX-Container war dann nicht mehr erreichbar, erhielt irgendwie keinerlei Adresse.


    Wie kann ich das "2001:db8:a::/80" Netz verwenden? Soll ich in /etc/default/docker einfach als Startoption "--ipv6" mitgeben und dann via docker-compose mein derzeit einziges IPv6 Netzwerk definieren?


    Ich stehe hier noch echt auf dem Schlauch. Ich habe nämlich alles super einfach in einem docker-compose laufen und möchte auch alles darüber verwalten.


    Danke für Eure Hilfe!

  • Sooo, habe nun in /etc/default/docker einfach die Startoption mit --ipv6 versehen und mein docker-compose.yml aufgebaut.


    Nun hat NGINX auch eine IPv6 kann angepingt werden und auch vom NGINX-Container aus kann ich rauspingen mit "ping6 google.com".


    Lediglich auf port 80 und 443 antwortet NGINX nicht und auch aus dem Container komme ich mit curl auf keine Webseite. Ich denke, dass liegt noch an den ip6tables, welche hier blocken. Ich nutze ufw, habe es schon mit:


    ufw allow to 2001:db8:a:42:ac11:2 port 80


    versucht, brachte aber nichts. Was muss ich konfigurieren, sodass ausschließlich Port 80 und Port 443 offen sind?

    Geht das überhaupt mit ufw?

  • Lauscht denn nginx überhaupt auf der IPv6 Adresse? Kannst du denn innerhalb des Containers nginx über die IPv6 Adresse aufrufen? Evtl. liegt es ja einfach nur an der "listen" Direktive in deiner nginx.conf.

  • Disclaimer: Anderer Anbieter, aber gleiches Datacenter!


    Bei mir ist das Setup wie folgt:


    Ich habe aus meinem /64 zwei /80 heraus gesplittet. Eines ist public, das andere privat. Das ist auch entsprechend in ip6tables konfiguriert. Danach weise ich den Containern je nach dem wie sie kommunizieren eine freigegebene oder gesperrte IPv6 zu.



    Die Container Netzwerke werden dann ganz normal mit docker run --network und docker network connect den Containern zugewiesen.


    NDP habe ich nicht im Einsatz, meine Deployment Playbooks setzen einfach ein post-up ins Debian Network Setup:


    Code
    iface eth0 inet6 static
        address 2a01:4f8:xx:xx::42
        netmask 64
        gateway fe80::1
        post-up ip -6 addr add 2a01:4f8:xx:xx::1:1/64 dev eth0
        post-up ip -6 addr add 2a01:4f8:xx:xx::1:2/64 dev eth0
        post-up ip -6 addr add 2a01:4f8:xx:xx::1:3/64 dev eth0
        post-up ip -6 addr add 2a01:4f8:xx:xx::1:4/64 dev eth0
        post-up ip -6 addr add 2a01:4f8:xx:xx::1:5/64 dev eth0
  • Vielen Vielen Dank an Euch alle! Vor allem an H6G und perryflynn!


    Danke Paul, im NGINX Docker hatte ich den "listen [::]" schon gesetzt.


    Es lag wirklich an den ip6tables:


    Code
    -A FORWARD -s 2a01:4f8:xx:xx::/64 -o eth0 -j ACCEPT
    -A FORWARD -d 2a01:4f8:xx:xx:4::/80 -j ACCEPT

    Das sind die hilfreichen Zeilen gewesen. Denn Docker legt nur iptables an, aber keine ip6tables. Daher musste ich diese separat setzen.


    Die Umsetzung mit NDP läuft bei mir gut. Leider ist es jedoch so, dass immer die ersten PING-Pakete nicht durchkommen. Der NDP-Proxy braucht irgendwie immer eine Weile, es fehlen immer so 2-4 Pakete am Start, wenn lange keine Verbindung zum Server bestand.


    Meine ndppd.conf:


    Code
    proxy eth0 {
        rule 2001:db8:a::/80 {
            auto
        }
    }


    Ich binde mit "auto" nicht direkt an ein Interface, er soll selbst in der Routing-Tabelle schauen, wer zuständig (ROUTER SOLICITATIONS) ist.
    Kann meine "Wartezeit" genau damit zusammenhängen?

    Ernstgemeinte Frage, denn normalerweise, so habe ich es verstanden, ruft der NDPProxy regelmäßig raus und fragt, welche Router verfügbar sind und meldet sein Netz an, dass er eben für "2001:db8:a::/80" zuständig ist. Der Router packt das Netz in seine Routing-Tabelle. Ruft einer bei "2001:db8:a::1" an, so weiß der Router wo er hinsenden muss. Hat er nichts in der Routing-Tabelle stehen, fragt er im Netz nach, ob sich jemand dafür zuständig fühlt und wartet auf Antwort. Ist das soweit korrekt? Vor allem der letzte Satz?


    Genau dieser Vorgang ruft dann eben meine 2-4 ICMPv6-Paketloss hervor. Korrekt soweit?
    Wenn ja, wie kann ich das, außer ab und an mal manuell ping6 zu benutzen, verbessern?


    Note: Dadurch habe ich eben oft das Problem, dass der Browser einen "Fallback" zu IPv4 vornimmt.