Nginx: SSL Zertifikat (https) für lokal genutzte Domains/Container


Recommended Posts

Ich möchte möglichst alle Docker über https verschlüsseln. Über NPM kann ich jedem Docker eine Domain zuweisen und dann ein Let's Encrypt Zertifikat anfordern. Allerdings möchte ich nicht jeden Container öffentlich erreichbar machen. Daher kam ich auf die Idee nur lokale Zugriffe zu erlauben:

 

1.) Ich trage in NPM bei jedem Host, der nur lokal erreichbar sein soll, unter "Advanced" folgende Regel ein:

location / {
  # allow anyone in 192.168.178.0/24
  allow 192.168.178.0/24;
  # allow our public ipv4
  allow 169.254.1.1;
  # allow our public ipv6
  allow fe80::/10;
  # drop rest of the world
  deny all;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection $http_connection;
  proxy_http_version 1.1;
  # Proxy!
  include conf.d/include/proxy.conf;
}

 

2.) Nun wird das folgende Skript alle 5 Minuten ausgeführt, damit die Platzhalter IP 169.254.1.1 bzw fe80::/10 aus der zuvor genannten Konfiguration gegen meine öffentliche IP ersetzt wird:

#!/bin/bash

# make script race condition safe
if [[ -d "/tmp/${0//\//_}" ]] || ! mkdir "/tmp/${0//\//_}"; then exit 1; fi; trap 'rmdir "/tmp/${0//\//_}"' EXIT;

# get public ipv4
ipv4=$(getent ahostsv4 server.example.com | grep STREAM | head -n 1 | cut -d ' ' -f 1)
ipv6=$(ip -6 addr show dev br0 scope global | grep -oP "(?<=inet6 )[^/]+" | head -n 1 | cut -d ':' -f 1-4)"::/56"

# replace ipv4 in nginx config
sed -i "/# allow our public ipv4/!b;n;c\ \ allow $ipv4;" /mnt/user/appdata/npm/data/nginx/proxy_host/*.conf

# replace ipv6 in nginx config
sed -i "/# allow our public ipv6/!b;n;c\ \ allow $ipv6;" /mnt/user/appdata/npm/data/nginx/proxy_host/*.conf

# reload nginx configuration
docker exec -i npm nginx -s reload

 

Das ist wichtig, denn obwohl ich von lokal auf den Container zugreife, kommen meine Zugriffe "von außen" über die öffentliche IP-Adresse.

 

Ich komme nun über die Domain auf meinen Container (Falls ich den Proxy Host über NPM bearbeite, verliert er kurz die IP, aber nach 5 Minuten ist sie wieder erlaubt):

image.png.c97005237f35ea493a90898d233042c6.png

 

Haltet ihr das für die "einfachste" Lösung oder habt ihr eine bessere Idee wie man das umsetzen könnte?

 

  • Like 1
  • Thanks 1
Link to comment
1 hour ago, blinddark said:

Das Zertifikat holt doch so oder so der NPM.

Der holt nichts, sondern teilt Lets Encrypt nur mit, dass der Link http://<YOUR_DOMAIN>/.well-known/acme-challenge/<TOKEN> zur Bestätigung des Zertifikats aufgerufen werden kann. Wenn das dann nicht geht, verlängert Let's Encrypt auch nicht das Zertifikat.

 

1 hour ago, blinddark said:

dass du das Ganze scheinbar auch über die Access List lösen könntest.

Wie soll das gehen? Da kann ich ja auch nicht meine öffentliche IP eintragen und aktuell halten.

Link to comment
  • mgutt changed the title to Nginx: SSL Zertifikat (https) für lokal genutzte Domains/Container

@mguttWenn ich das richtig verstanden hab, ist der Zugriff aus dem Heimnetz möglich. Auf Sub/Domain vermute ich. Sowie der von der eigenen Public IP. VPN geht ebenso, da man dann wieder im Heim/Lokalnetz ist.

 

Alles andere sowie Regionen ist verboten. Somit stehen die Docker dann alle im Internet aber alle Angriffe/Zugriffe sind verboten?

 

Würde das auch gehen wenn man Internetausfall hat?

 

Wenn man dann was macht wird das dann auch über das Internet übertragen oder ist das Internet nur für die Auflösung von Sub/Domain zu Docker/Server zuständig und alles andere passiert lokal?

Link to comment
6 hours ago, Revan335 said:

Somit stehen die Docker dann alle im Internet aber alle Angriffe/Zugriffe sind verboten?

Korrekt. Wobei nur ein Container direkt aus dem Internet erreichbar ist und das ist der NPM. Der leitet ja den Traffic an andere Container weiter (oder blockt ihn).

 

6 hours ago, Revan335 said:

Würde das auch gehen wenn man Internetausfall hat?

Nein. Dann gehört die öffentliche IP, die bei der Domain hinterlegt ist, ja vermutlich schon jemand anderem.

 

6 hours ago, Revan335 said:

und alles andere passiert lokal?

Tatsächlich geht der Traffic, der von lokal auf die öffentliche IP geht, nicht ins Internet. Er landet beim Router, dem diese IP ja zugeordnet ist. Und wenn dieser NAT Loopback beherrscht, wie es bei einer Fritz!Box der Fall ist (Speedport kann es zb nicht), dann leitet dieser den Traffic von außen durch seine Firewall wieder ins lokale Netz zurück (wenn der entsprechende Port offen ist).

 

Man könnte einer Domain auch eine rein lokale IP geben, aber das geht nur mit https, wenn man ein kostenpflichtiges Wildcard Zertifikat für die komplette Domain hat oder man betreibt lokal einen DNS Server, der die DNS Anfragen für die eigene Domain "abfängt" und deren lokale IP zurückgibt. Dann ginge der Zugriff auch, wenn man kein Internet hat.

 

Link to comment
3 hours ago, Revan335 said:

Also würde man im Falle eines Internetausfalls nicht mehr an die Docker .... kommen

Korrekt bzw du kannst natürlich nach wie vor die lokale IP des Containers öffnen.

 

3 hours ago, Revan335 said:

Oder würde es dann zum Router/Fritz!Box und wieder zurück gehen, weil dieser ja dann nicht ins Internet kommt?

Der Router kennt die öffentliche IP nicht, weil er nicht ins Internet kommt und selbst keine öffentliche IP mehr hat. 

Link to comment

Super dass du das Thema aufgemacht hast. Ist etwas das mich auch schon lange beschäftigt ohne eine Lösung gefunden zu haben.
Ging aber erstmal nicht darum den Zugang nur auf lokal zu beschränken. Wollte die eingestellte Authentifizierung (bei externem Zugriff ja sinnvoll) bei lokalem Zugriff durch eine Access List Regel umgehen können. Aber wir haben ja im Prinzip das selbe Ziel.
Ich bin schon kurz davor mir eine fixe IP Adresse zuweisen zu lassen, aber ich scheue die 6 Euro / Monat die mein Provider dafür kassiert.

Deine Methode scheint ein möglicher Lösungsansatz zu sein. Werde ich demnächst auf jeden Fall mal ausprobieren.

Danke dafür!!

Edited by fk_muck1
Link to comment
  • 2 months later...

Ich hab das so gelöst das ich mir eine Domain gekauft habe, die habe ich dann bei Cloudflare eingetragen. Dort habe ich keine DNS-Einträge etc gemacht, sondern nur einen API-Token generiert. Den API-Token brauche ich um im NPM das Lets Encrypt zertifikat zu aktualisieren. Vorteil kein Port freigabe nötig.

Daraufhin habe ich im Pihole unter

 /etc/dnsmasq.d/03-custom-dns.conf

 folgendes eingetragen:

address=/.example.com/192.168.1.100

die 100 ist die vom NPM.

 

Jetzt muss ich im NPM einen Proxy Hosts für jeden Container erstellen und das Lets Encrypt Zertifikat auswählen und fertig.

Ich bin kein Sicherheitsexperte und weiß auch nicht ob das hier der richtige Weg ist, aber bei mir funktioniert es so.

 

Verbesserungsvorschläge sind willkommen :)

 

LG

Sakis

Link to comment

Ich habe mehre Container über SWAG von "außen" verfügbar gemacht.

a.meine.domain

b.meine.domain

c.meine.domain

 

Außerdem habe ich in SWAG noch weitere dienste eingetragen:

 

d.meine.domain

e.meine.domain

 

d.) und e.) möchte ich nur local haben. also habe ich einfach keine Subdomains dafür bei cloudflare eingerichtet. Desweiteren nutze ich lokal als DNS einen pihole. durch den löse ich meine komplette *.meine.domain auf die ip/local-domain direkt auf SWAG/Unraid auf.

 

Sprich Voraussetzung hierfür ist zwingend ein lokaler DNS-Server, oder das editieren der DNS Auflösung an den Geräten selbst.

Link to comment
8 hours ago, mgutt said:
8 hours ago, sakistech said:

Vorteil kein Port freigabe nötig.

Häh? Dh deine Domain hat nun eine lokale IP oder wie?

ich denke @sakistech nutzt ein Wildcard Zertifikat, dann brauch man keine Ports für die Validation.

Letztendlich macht es @sakistech genauso wie ich. Wildcard Zertifikat, keine Subdomains beim DNS-Provider und Lokale DNS Auflösung direkt auf den Reverse Proxy. 

Somit kann man aus einem RP auch nen mixed Betrieb von WAN und Local-Only DNS Zugriffe machen.

Link to comment

Dann ist das aber unsicher. Wenn ich a.example.com kenne, dann kenne ich eure öffentliche IP. Jetzt brauche ich nur noch das machen:

curl https://b.example.com --resolve 'b.example.com:443:1.2.3.4'
 

Ich lege mir also einfach einen hosts / DNS Eintrag an. Das geht natürlich auch per hosts Datei im jeweiligen Betriebssystem.

 

Was ihr macht, geht nur sicher, wenn ihr eine zweite Proxy Instanz aufsetzt, die ausschließlich eure lokalen Domains enthält und der nicht von außen erreichbar ist.

 

 

Link to comment
1 hour ago, mgutt said:

Dann ist das aber unsicher. Wenn ich a.example.com kenne, dann kenne ich eure öffentliche IP. Jetzt brauche ich nur noch das machen:

curl https://b.example.com --resolve 'b.example.com:443:1.2.3.4'

Da hast du natürlich recht.

Ich habe folgenden Block vergessen:

image.png.2ef2209872a718876ab058155e6af7d0.png

 

Damit sollte das Problem abgefrühstückt sein und mit nur einem Reverse Proxy klappen.

Abgesehen von dem Versuch, dass wirklich jemand "rein" will... da hilft dann wohl nur Stecker ziehen.

Edited by sonic6
Link to comment
On 6/29/2022 at 5:11 AM, sonic6 said:

ich denke @sakistech nutzt ein Wildcard Zertifikat, dann brauch man keine Ports für die Validation.

Letztendlich macht es @sakistech genauso wie ich. Wildcard Zertifikat, keine Subdomains beim DNS-Provider und Lokale DNS Auflösung direkt auf den Reverse Proxy. 

Somit kann man aus einem RP auch nen mixed Betrieb von WAN und Local-Only DNS Zugriffe machen.

Genau so mache ich das.

 

On 6/29/2022 at 10:38 AM, sonic6 said:

Da hast du natürlich recht.

Ich habe folgenden Block vergessen:

image.png.2ef2209872a718876ab058155e6af7d0.png

 

Damit sollte das Problem abgefrühstückt sein und mit nur einem Reverse Proxy klappen.

Abgesehen von dem Versuch, dass wirklich jemand "rein" will... da hilft dann wohl nur Stecker ziehen.

Kannst du mir sagen wo das kommt?

Link to comment
On 6/29/2022 at 11:13 AM, mgutt said:

Aber woher weiß der Client eigentlich, dass die Domain eine lokale IP hat?

Vom Lokalen DNS-Server. In meinem Fall Pihole per Local DNS Record von der Local-Domain des Unraid Servers und dann meine externen Domains per Local Cname Recods auf die Local-Domain des Unraid Server.

image.thumb.png.2b46c5a8ee8d0d22cecf5d47af94f1ed.png

image.thumb.png.0cf9809b641f365f084eb5d6f922cf48.png

 

10 hours ago, sakistech said:

Kannst du mir sagen wo das kommt?

Das kommt ganz auf deine Struktur der Configs an. Ich nutze aber SWAG, keine Ahnung wie es mit NPM aussieht. Würde mich dahingenede an GeoBlock orientieren, welches ähnlich aufgebaut ist.

Bevorzugt würd ich es in den "location" Block der conf des jeweiligen Dienstes packen.

Link to comment
18 minutes ago, sonic6 said:

Funktionier dann aber nur, solange ich auch "online" bin, oder?

Kommt auf die TTL an. Stell einfach 3 Monate oder so ein. Der Client merkt sich das dann solange. Oder hast du Clients, die niemals online sind?

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.