Software

CoreDNS im Heimnetz: Lokales DNS mit mehr Freiheit

Lokales DNS beginnt oft harmlos: hier ein Host Override, dort ein interner Dienst. Doch sobald VLANs, mehrere Interfaces und ein wachsendes Homelab ins Spiel kommen, verwandeln sich diese praktischen kleinen Firewall-UI-Einträge in versteckten Infrastrukturzustand. In diesem Beitrag zeige ich, wie ich mein LAN-DNS von pfSense Host Overrides auf eine saubere CoreDNS-basierte Steuerungsebene umgestellt habe – schnell, deterministisch, reproduzierbar und endlich passend zu der Art, wie das Netzwerk tatsächlich funktioniert.

Es gibt Infrastrukturprobleme, die von außen fast lächerlich trivial wirken.

„Trag doch einfach einen DNS-Eintrag ein.“

„Mach eben eine Firewall-Regel.“

„Nimm einfach den DNS-Resolver des Routers.“

Und technisch stimmt das zunächst sogar. Es funktioniert – bis das Netzwerk ein wenig wächst, bis VLANs hinzukommen, bis Dienste auf mehreren Interfaces leben, bis Reproduzierbarkeit wichtig wird und bis aus jedem „nur noch schnell ein Override“ ein weiteres kleines Stück versteckter, nicht-idempotenter Infrastrukturzustand in einer Firewall-Weboberfläche wird.

Das hier ist die Geschichte eines solchen Problems, das kleiner aussieht, als es ist: lokales DNS in einem segmentierten LAN.

Genauer gesagt:

Wie betreibt man sauberes, schnelles und deterministisches DNS für interne Dienste über mehrere VLANs hinweg, ohne pfSense Host Overrides bis in alle Ewigkeit manuell zu pflegen?

Die endgültige Lösung war nicht exotisch. Kein Kubernetes, kein Consul, keine Enterprise-Appliance, kein Service Mesh. Nur ein Debian-Server, CoreDNS, pfSense/Unbound, Ansible – und etwas sorgfältige Denkarbeit darüber, wie DNS-Auflösung tatsächlich abläuft.

Denn wie so oft in der Infrastruktur lag die Schwierigkeit nicht darin, Software zu installieren. Die Schwierigkeit lag darin, den Kontrollfluss wirklich zu verstehen.


Der Ausgangspunkt: pfSense-DNS funktionierte – aber nicht mehr gut genug

Das Netzwerk nutzte bereits pfSense als zentrale Firewall und DNS-Resolver. Das ist ein verbreitetes und grundsätzlich sehr vernünftiges Setup.

pfSense betreibt Unbound als DNS Resolver, und für viele Umgebungen reicht das vollkommen aus:

  • DHCP-Integration
  • lokale Host Overrides
  • Domain Overrides
  • Forwarding oder rekursive Auflösung
  • Unterstützung für DNS over TLS
  • eine hinreichend zugängliche Weboberfläche

Für ein kleines LAN ist das absolut in Ordnung.

Doch mit der Zeit war das lokale DNS-Setup deutlich über „ein paar Host Overrides“ hinausgewachsen.

Es gab zahlreiche interne Dienste:

prometheus.myhost.lan
grafana.myhost.lan
git.myhost.lan
dev.myhost.lan
vpn.myhost.lan

Einige Einträge waren ausschließlich intern. Andere gehörten zu einer öffentlichen Domain, die innerhalb des Netzes anders aufgelöst werden sollte. Wieder andere mussten je nach Client-VLAN unterschiedliche Antworten liefern. Und all das wurde über die pfSense-Oberfläche verwaltet.

Das erzeugte mehrere Probleme:

  • manuelle Änderungen
  • keine saubere Versionskontrolle
  • kein unkompliziertes Rollback
  • keine Idempotenz
  • keine wiederverwendbare Deployment-Logik
  • kein echtes Infrastructure-as-Code-Arbeitsmodell

Das war also nicht primär ein DNS-Performance-Problem. Es war ein DNS-Control-Plane-Problem.

pfSense blieb hervorragend als Firewall und als zentraler Resolver beziehungsweise Cache. Aber es war nicht der richtige Ort, um eine wachsende, strukturierte lokale DNS-Autorität dauerhaft zu pflegen.


Die architektonische Entscheidung: Resolver und Authority trennen

Der entscheidende gedankliche Schritt war dieser:

Die Firewall muss nicht zwangsläufig die Quelle der Wahrheit für sämtliche internen DNS-Einträge sein.

Sauberer ist es, Verantwortlichkeiten zu trennen:

Clients
   ↓
CoreDNS / pfSense DNS Resolver
   ↓
Lokale autoritative Einträge
   ↓
pfSense / Unbound
   ↓
Öffentliche Upstream-DNS-Server

Oder etwas präziser:

CoreDNS = lokale DNS-Autorität / Overlay / VLAN-bewusste Logik
pfSense Unbound = rekursiver Resolver, Cache, Upstream-Forwarding, Firewall-Integration
Public DNS = globale Namensauflösung

Daraus ergibt sich ein geschichtetes Modell:

Ebene Verantwortung
CoreDNS Interne Einträge, lokale Overlays, VLAN-bewusste Antworten
pfSense / Unbound Allgemeine DNS-Auflösung, Cache, Upstream-Forwarding
Öffentliche Resolver Externe DNS-Auflösung

Wichtig ist: CoreDNS muss pfSense nicht vollständig ersetzen.

Es kann schlicht der Teil des Systems werden, der lokale DNS-Logik deklarativ und nachvollziehbar abbildet.


Warum CoreDNS?

CoreDNS ist klein, schnell, pluginbasiert und wird über eine einfache Textdatei namens Corefile konfiguriert.

Genau das macht es für diesen Zweck attraktiv:

  • unkompliziert auf Debian zu betreiben
  • gut mit Ansible zu templaten
  • sauber in Git versionierbar
  • Unterstützung für statische Host-Einträge
  • Unterstützung für Forwarding
  • Prometheus-Metriken
  • clientabhängige Views
  • insgesamt einfach genug, um den Ablauf wirklich zu verstehen

Das Ziel war nicht, eine überkomplexe interne DNS-Plattform zu konstruieren. Das Ziel war, versteckten UI-Zustand durch ein sauberes, reproduzierbares System zu ersetzen.


Das grundlegende CoreDNS-Modell

Ein minimales CoreDNS-Setup für lokale Records sieht etwa so aus:

myhost.lan:53 {
    errors
    cache 300

    hosts {
        192.168.10.20 prometheus.myhost.lan
        192.168.10.21 grafana.myhost.lan
        fallthrough
    }

    forward . 192.168.10.1
}

Die Logik dahinter:

  1. Kennt CoreDNS den Hostnamen, liefert es die lokale IP zurück.
  2. Falls nicht, greift fallthrough.
  3. Die noch nicht aufgelöste Anfrage wird an pfSense/Unbound weitergereicht.

Für eine öffentliche Domain, die intern teilweise anders beantwortet werden soll, funktioniert derselbe Ansatz:

example.org:53 {
    errors
    cache 300

    hosts {
        192.168.10.30 internal-api.example.org
        192.168.10.31 dev-only.example.org
        fallthrough
    }

    forward . 192.168.10.1
}

Das eignet sich für Split-Horizon-artiges DNS:

internal-api.example.org → lokale IP im LAN
www.example.org          → öffentliche DNS-Auflösung über Upstream

Bis hierhin ist alles recht geradlinig.

Das eigentliche Problem war jedoch interessanter.


Das Multi-VLAN-Problem

Ein interner Dienst, git.myhost.lan, war aus vier VLANs erreichbar.

Der Server selbst verfügte über Interfaces in allen vier VLANs:

VLAN 10 → 192.168.10.50
VLAN 20 → 192.168.20.50
VLAN 30 → 192.168.30.50
VLAN 40 → 192.168.40.50

Das Ziel war schlicht:

Client in VLAN 10 → git.myhost.lan → 192.168.10.50
Client in VLAN 20 → git.myhost.lan → 192.168.20.50
Client in VLAN 30 → git.myhost.lan → 192.168.30.50
Client in VLAN 40 → git.myhost.lan → 192.168.40.50

Warum?

Weil der Traffic dann lokal im jeweiligen VLAN bleibt.

Ohne diese Logik könnte ein Client in VLAN 20 git.myhost.lan beispielsweise auf die VLAN-10-IP auflösen. Der Datenverkehr müsste dann unnötig durch die Firewall laufen. Da das Netzwerk zu diesem Zeitpunkt noch keine Switches mit sauberer Inter-VLAN-Routing-Fähigkeit nutzte, bedeutete das unnötige Firewall-Traversierung – und eine unschöne Topologie-Leakage.

Der bisherige Workaround sah ungefähr so aus:

git1.myhost.lan → VLAN-10-IP
git2.myhost.lan → VLAN-20-IP
git3.myhost.lan → VLAN-30-IP
git4.myhost.lan → VLAN-40-IP

Funktional, aber nicht elegant.

Ein Hostname sollte den Dienst beschreiben, nicht die Netzwerktopologie.

Die eigentliche Anforderung lautete daher:

Derselbe Hostname soll abhängig vom abfragenden Client-Subnetz unterschiedliche Antworten liefern.

Das ist Split-Horizon-DNS – oder genauer: client-subnetzabhängiges DNS.


CoreDNS Views: der vielversprechende Mechanismus

CoreDNS besitzt ein view-Plugin, das Anfragen anhand von Client-Informationen filtern kann.

Konzeptionell lässt sich damit etwa Folgendes umsetzen:

myhost.lan:53 {
    view vlan10 {
        expr incidr(client_ip(), '192.168.10.0/24')
    }

    hosts {
        192.168.10.50 git.myhost.lan
        fallthrough
    }

    forward . 192.168.10.1
}

Und für VLAN 20:

myhost.lan:53 {
    view vlan20 {
        expr incidr(client_ip(), '192.168.20.0/24')
    }

    hosts {
        192.168.20.50 git.myhost.lan
        fallthrough
    }

    forward . 192.168.10.1
}

Das war genau das richtige Konzept.

Bis der tatsächliche Kontrollfluss in CoreDNS korrekt funktionierte, brauchte es allerdings mehrere Iterationen.


Wichtige Erkenntnis 1: CoreDNS muss die echte Client-IP sehen

Damit VLAN-abhängiges DNS funktioniert, muss CoreDNS die ursprüngliche Client-IP erkennen.

Das klingt offensichtlich, hat aber eine entscheidende Konsequenz.

Wenn Clients pfSense befragen und pfSense die Anfrage anschließend an CoreDNS weiterleitet, sieht CoreDNS womöglich nur pfSense als Quelle:

Client → pfSense/Unbound → CoreDNS

Aus CoreDNS-Sicht ist der Client dann nicht 192.168.20.123, sondern die Firewall.

Damit bricht das View-Matching.

Für dieses Setup sollten Clients, die VLAN-abhängige DNS-Antworten benötigen, CoreDNS deshalb direkt befragen – typischerweise über die DHCP-DNS-Server-Einstellungen je VLAN.

Alternativ müsste die Split-Horizon-Logik vollständig in Unbound beziehungsweise pfSense selbst abgebildet werden.

Für dieses Setup war der saubere Pfad daher:

Clients → CoreDNS → pfSense/Unbound → Upstream

CoreDNS wird zum ersten Resolver für LAN-Clients. Es verarbeitet die lokale Logik und reicht alles andere an pfSense weiter.


Wichtige Erkenntnis 2: CoreDNS korrekt an Interfaces binden

Auf dem Debian-Server liefen bereits weitere DNS-nahe Dienste, unter anderem dnsmasq auf einem Docker-/libvirt-artigen Subnetz.

Der erste CoreDNS-Startversuch scheiterte mit:

listen tcp :53: bind: address already in use

Zunächst wirkte es, als würde CoreDNS explizit gesetzte IP-Adressen ignorieren. Tatsächlich war das Problem eine Grammatikbesonderheit in CoreDNS.

Das hier bedeutet nicht intuitiv „binde ausschließlich an 127.0.0.1“:

127.0.0.1:53 {
    ...
}

Der korrekte Weg, Listener-Interfaces einzuschränken, ist das bind-Plugin innerhalb des Server-Blocks:

.:53 {
    bind 192.168.10.53 192.168.20.53 192.168.30.53 192.168.40.53

    errors
    cache 300
    forward . 192.168.10.1
}

Und entscheidend: Jeder relevante Server-Block muss dieselbe Bind-Einschränkung enthalten.

Andernfalls versucht CoreDNS unter Umständen weiterhin, breit auf Port 53 zu lauschen.

Das resultierende Muster:

myhost.lan:53 {
    bind 192.168.10.53 192.168.20.53 192.168.30.53 192.168.40.53

    ...
}

Damit lassen sich Konflikte mit dnsmasq oder anderen Diensten vermeiden, die auf anderen lokalen Interfaces gebunden sind.


Wichtige Erkenntnis 3: CoreDNS kaskadiert nicht zwischen Server-Blöcken

Das war die wichtigste logische Falle.

Die erste Struktur sah ungefähr so aus:

VLAN-spezifischer Block für myhost.lan
Generischer/globaler Block für myhost.lan

Die Erwartung war:

1. VLAN-spezifische Hosts prüfen
2. Wenn nicht gefunden, zu globalen Hosts durchfallen
3. Wenn weiterhin nicht gefunden, upstream weiterleiten

CoreDNS funktioniert jedoch nicht so.

Sobald eine Anfrage in einem passenden Server-Block beziehungsweise View landet, wird dessen Plugin-Kette abgearbeitet. Danach springt CoreDNS nicht in einen späteren, allgemeineren Server-Block weiter.

Diese Variante schlug also fehl:

myhost.lan:53 {
    view vlan10 {
        expr incidr(client_ip(), '192.168.10.0/24')
    }

    hosts {
        192.168.10.50 git.myhost.lan
        fallthrough
    }

    forward . 192.168.10.1
}

myhost.lan:53 {
    hosts {
        192.168.10.20 prometheus.myhost.lan
        192.168.10.21 grafana.myhost.lan
        fallthrough
    }

    forward . 192.168.10.1
}

Ein Client aus VLAN 10, der prometheus.myhost.lan abfragt, landet im VLAN-10-Block, findet dort keinen Eintrag und wird anschließend upstream weitergereicht. Der spätere globale Hosts-Block wird nicht mehr betrachtet.

Damit war auch klar, warum das vermeintliche „globale Overlay“ ignoriert zu werden schien.


Wichtige Erkenntnis 4: hosts lässt sich pro Zone-Block nicht beliebig wiederholen

Die nächste Idee war, mehrere hosts-Sektionen innerhalb desselben Blocks zu platzieren:

myhost.lan:53 {
    view vlan10 { ... }

    hosts {
        192.168.10.50 git.myhost.lan
        fallthrough
    }

    hosts {
        192.168.10.20 prometheus.myhost.lan
        fallthrough
    }

    forward . 192.168.10.1
}

Doch auch das scheiterte, weil sich das hosts-Plugin innerhalb desselben Zone-Blocks nicht einfach mehrfach auf diese Weise verwenden lässt.

Die finale Lösung war deutlich simpler – und robuster:

Die globalen Zone-Records werden in jeden passenden VLAN-spezifischen Block hineingeneriert.

Anders gesagt: Jeder VLAN-spezifische Block enthält:

VLAN-spezifische Records
+ globale Records derselben Zone
+ fallthrough
+ forward

Das hält die Plugin-Kette einfach, explizit und deterministisch.


Das funktionierende CoreDNS-Muster

Eine vereinfachte finale CoreDNS-Struktur sieht so aus:

.:53 {
    bind 192.168.10.53 192.168.20.53 192.168.30.53 192.168.40.53

    errors
    cache 300
    prometheus 192.168.10.53:9153

    forward . 192.168.10.1
}

myhost.lan:53 {
    bind 192.168.10.53 192.168.20.53 192.168.30.53 192.168.40.53

    view vlan10 {
        expr incidr(client_ip(), '192.168.10.0/24')
    }

    errors
    cache 300

    hosts {
        192.168.10.50 git.myhost.lan

        # Globale Records, in die VLAN-View injiziert
        192.168.10.20 prometheus.myhost.lan
        192.168.10.21 grafana.myhost.lan
        192.168.10.22 alertmanager.myhost.lan

        fallthrough
    }

    forward . 192.168.10.1
}

myhost.lan:53 {
    bind 192.168.10.53 192.168.20.53 192.168.30.53 192.168.40.53

    view vlan20 {
        expr incidr(client_ip(), '192.168.20.0/24')
    }

    errors
    cache 300

    hosts {
        192.168.20.50 git.myhost.lan

        # Dieselben globalen Records
        192.168.10.20 prometheus.myhost.lan
        192.168.10.21 grafana.myhost.lan
        192.168.10.22 alertmanager.myhost.lan

        fallthrough
    }

    forward . 192.168.10.1
}

Nun verhält sich das System exakt wie gewünscht:

VLAN-10-Client:
git.myhost.lan        → 192.168.10.50
prometheus.myhost.lan → 192.168.10.20
google.com            → Weiterleitung an pfSense

VLAN-20-Client:
git.myhost.lan        → 192.168.20.50
prometheus.myhost.lan → 192.168.10.20
google.com            → Weiterleitung an pfSense

Dienstspezifische Topologie wird lokal behandelt, während allgemeine Records gemeinsam verfügbar bleiben.


Idempotent machen mit Ansible

Der Punkt war nicht, DNS ein einziges Mal zum Laufen zu bringen. Der Punkt war, es reproduzierbar zu machen.

Die Rolle arbeitet mit Variablen wie diesen:

coredns_upstreams:
  - "192.168.10.1"

coredns_bind_ips:
  - "192.168.10.53"
  - "192.168.20.53"
  - "192.168.30.53"
  - "192.168.40.53"

coredns_prometheus_enabled: true
coredns_prometheus_listen: "192.168.10.53:9153"

coredns_global_zones:
  - name: "myhost.lan"
    records:
      - "192.168.10.20 prometheus.myhost.lan"
      - "192.168.10.21 grafana.myhost.lan"
      - "192.168.10.22 alertmanager.myhost.lan"

  - name: "example.org"
    records:
      - "192.168.10.30 internal-api.example.org"
      - "192.168.10.31 dev-only.example.org"

coredns_views:
  - name: "vlan10"
    client_cidrs:
      - "192.168.10.0/24"
    zones:
      - name: "myhost.lan"
        records:
          - "192.168.10.50 git.myhost.lan"

  - name: "vlan20"
    client_cidrs:
      - "192.168.20.0/24"
    zones:
      - name: "myhost.lan"
        records:
          - "192.168.20.50 git.myhost.lan"

Der entscheidende Teil im Jinja-Template ist die Stelle, an der globale Records in passende View-spezifische Zonen injiziert werden:

hosts {
{% for record in zone.records %}
    {{ record }}
{% endfor %}

{# Globale Zone-Einträge ergänzen, sofern dieselbe Domain betroffen ist #}
{% for gzone in coredns_global_zones %}
{% if gzone.name == zone.name %}
    # Globale Records für {{ gzone.name }}
{% for grecord in gzone.records %}
    {{ grecord }}
{% endfor %}
{% endif %}
{% endfor %}

    fallthrough
}

Damit erhält jede VLAN-View eine vollständige lokale Sicht auf die betreffende Zone.

Das ist nicht die theoretisch eleganteste Modellierung, aber sie ist explizit, robust und sehr leicht zu durchdenken – und genau das ist in Infrastruktur häufig der bessere Maßstab.


Docker: die Loopback-Falle

Nach der DNS-Umstellung auf dem Debian-Host selbst tauchte noch ein zusätzliches Problem auf.

Der Host nutzte eine neue /etc/resolv.conf, unter anderem mit:

nameserver 127.0.0.1
nameserver 192.168.10.1

Für den Host funktionierte das.

Docker-Container haben jedoch ihren eigenen Network Namespace. Innerhalb eines Containers bedeutet:

127.0.0.1

nicht der Debian-Host, sondern der Container selbst.

Container konnten das Loopback-DNS des Hosts daher nicht nutzen.

Die Lösung bestand darin, Docker explizit einen DNS-Server zuzuweisen, der aus Containern erreichbar ist:

{
  "dns": [
    "192.168.10.53",
    "192.168.10.1"
  ]
}

in:

/etc/docker/daemon.json

Danach:

sudo systemctl restart docker

Und testen:

docker run --rm alpine nslookup git.myhost.lan
docker run --rm alpine nslookup google.com

Damit funktionierte Namensauflösung auch innerhalb der Container wieder sauber.


Erst testen, dann produktiv umstellen

Das ist der Teil, der in realer Infrastrukturarbeit zählt: Niemals blind alles umschalten.

Der sichere Testablauf war:

dig @192.168.10.53 git.myhost.lan +short
dig @192.168.10.53 prometheus.myhost.lan +short
dig @192.168.10.53 google.com +short

Von Clients in unterschiedlichen VLANs:

dig @192.168.10.53 git.myhost.lan +short
dig @192.168.20.53 git.myhost.lan +short
dig @192.168.30.53 git.myhost.lan +short
dig @192.168.40.53 git.myhost.lan +short

Erwartet:

VLAN 10 → 192.168.10.50
VLAN 20 → 192.168.20.50
VLAN 30 → 192.168.30.50
VLAN 40 → 192.168.40.50

Während des Rollouts waren CoreDNS-Logs hilfreich:

log
errors

Und natürlich die Systemlogs:

journalctl -u coredns -f

Der kritische Punkt war zu verifizieren, dass CoreDNS tatsächlich die realen Client-IPs sieht – und nicht nur die Firewall.


Observability: Prometheus-Metriken

CoreDNS kann mit einer einzigen Zeile Prometheus-Metriken bereitstellen:

prometheus 192.168.10.53:9153

Prometheus kann diese anschließend scrapen:

scrape_configs:
  - job_name: "coredns"
    static_configs:
      - targets:
          - "192.168.10.53:9153"

Nützliche Metriken sind unter anderem:

coredns_dns_requests_total
coredns_dns_responses_total
coredns_cache_hits_total
coredns_cache_misses_total
coredns_dns_request_duration_seconds

Das ist nicht bloß ein nettes Extra. DNS ist grundlegend genug, dass Sichtbarkeit wirklich zählt.

Hohe NXDOMAIN-Raten, langsame Upstream-Antworten, fehlerhafte Clients, übermäßige Lookups – all das wird damit sichtbar.


Die finale Architektur

Das resultierende Setup sieht so aus:

LAN-Clients
   ↓
CoreDNS auf zentralem Debian-Server
   ↓
lokale Records / VLAN-bewusste Views
   ↓
pfSense Unbound
   ↓
öffentliche Upstream-DNS-Server

Für reguläre interne Dienste:

prometheus.myhost.lan → gemeinsame lokale IP
grafana.myhost.lan    → gemeinsame lokale IP

Für topologiebewusste Dienste:

git.myhost.lan → VLAN-lokale IP abhängig vom Client-Subnetz

Für alles andere:

externe Domains → pfSense/Unbound → Upstream-DNS

Und all das wird über Ansible ausgerollt.

Das bedeutet:

  • keine manuelle Pflege von pfSense Host Overrides mehr
  • kein versteckter Zustand
  • keine einmaligen UI-Änderungen
  • keine Topologie verratenden Hostnamen wie git1, git2, git3
  • vorhersehbares lokales DNS-Verhalten
  • beobachtbare DNS-Metriken
  • reproduzierbares Deployment

Das ist genau die Art von Infrastrukturverbesserung, die auf den ersten Blick nicht glamourös wirkt – aber ein Netzwerk sofort kohärenter und ruhiger macht.


Warum das über DNS hinaus relevant ist

Das ist ein lokales LAN-Thema. Das zugrunde liegende Muster ist jedoch deutlich allgemeiner.

Viele IT-Probleme entstehen nicht, weil Werkzeuge fehlen. Sie entstehen, weil Verantwortlichkeiten unscharf ineinanderlaufen.

In diesem Fall waren:

Firewall-UI
+ DNS-Resolver
+ lokale Autorität
+ Topologie-Routing
+ manuelle Records

zu sehr an einem Ort zusammengezogen.

Die Lösung lautete nicht: „Nimm einfach einen cooleren DNS-Server.“

Die Lösung lautete: Verantwortlichkeiten trennen.

pfSense = Firewall und Resolver/Cache
CoreDNS = lokale Autorität und DNS-Logik
Ansible = gewünschter Zielzustand
Prometheus = Sichtbarkeit

Das ist der Unterschied zwischen etwas, das bloß funktioniert, und etwas, das sich tatsächlich betreiben lässt.


Eine kleine Notiz aus der Beratungsperspektive

Genau solche Arbeiten mache ich auch beruflich ausgesprochen gern: ein System, das organisch gewachsen ist, auf seine versteckten strukturellen Reibungen hin untersuchen – und es anschließend sauberer, reproduzierbarer und leichter betreibbar machen.

Bei Neoground arbeiten wir meist an größeren digitalen Systemen – AI Consulting, Webplattformen, Automatisierung, SaaS-Architekturen, Infrastruktur und Strategie. Doch das Grundprinzip bleibt überall dasselbe:

Gute Technologiearbeit ist nicht bloß Implementierung. Sie ist strukturelle Klärung.

Manchmal bedeutet das, ein digitales Produkt zu entwerfen. Manchmal, einen internen Workflow zu entwirren. Und manchmal eben, DNS in einem segmentierten LAN so zu ordnen, dass die gesamte Infrastruktur endlich so funktioniert, wie sie gedanklich längst funktionieren sollte.

Wenn ein System grundsätzlich läuft, sich aber zunehmend manuell, fragil oder schwer durchdringbar anfühlt, ist das meist ein Zeichen dafür, dass es seiner ursprünglichen Steuerungsebene entwachsen ist.

Genau an diesem Punkt wird strategische Beratung wertvoll.


Das Ergebnis

Nach der Migration ist DNS nun:

  • schnell
  • lokal
  • VLAN-bewusst
  • reproduzierbar
  • beobachtbar
  • nicht länger in der pfSense-Oberfläche gefangen

Das Befriedigende ist nicht nur, dass git.myhost.lan nun aus jedem VLAN korrekt auflöst.

Das Befriedigende ist, dass das System jetzt wieder zum mentalen Modell passt.

Und in der Infrastruktur ist genau das meist der Moment, in dem wieder Ruhe einkehrt.

Dieser Blogbeitrag wurde von mir mit Unterstützung von KI (GPT 5.5 Thinking) auf Grundlage meiner langen Troubleshooting-Sessions, Notizen und zahlreichen Iterationen verfasst.

Über Sarah Robin

Sarah Robin ist Gründerin, Strategin, Technologin und Autorin aus der Nähe von Frankfurt am Main. Sie arbeitet an der Schnittstelle von KI-/IT-Beratung, Softwarearchitektur, Medien, öffentlichem Denken und Systemdenken. Durch Neoground und ihre unabhängige Arbeit hilft sie Menschen und Organisationen, Komplexität in Struktur zu verwandeln.

Noch keine Kommentare

Kommentar hinzufügen

In Ihrem Kommentar können Sie **Markdown** nutzen. Ihre E-Mail-Adresse wird nicht veröffentlicht. Mehr zum Datenschutz finden Sie in der Datenschutzerklärung.