.. title: Fritz!Box WireGuard und systemd-networkd
.. slug: fritzbox-wireguard-und-systemd-networkd
.. date: 2026-01-06 23:03:50 UTC+01:00
.. tags: Technik
.. category: 
.. link: 
.. description: Protokoll der Konfiguration von WireGuard mit Fritzbox und systemd-networkd
.. type: text
.. author: Masin Wiedner
.. mastodon: 115850607269250116

Vor Jahren schon habe ich einfache WireGuard-Verbindungen zwischen meinem Heimserver und meinem virtuellen Server, damals bei Contabo, eingerichtet. Ich erinnere mich düster, dass ich den WireGuard-Schnittstellen eigene IP-Adressen zuweisen musste, über die dann das Routing eingerichtet wurde.

In diesem Eintrag werde ich Verbindungsschlüssel entfernen und IP-Adressen austauschen bzw. durch Labels ersetzen, die ihre Funktion beschreiben, damit das ggf. auf vergleichbare, aber nicht identische Situationen angewendet werden kann.

Die Situation
=============

Bei mir liegen zwei Spezialfälle vor: Ich habe auf meinem Server ein paar Systemcontainer mit ``systemd-nspawn`` am Laufen. Diese hängen dort an einer Network Zone, die von ``systemd-nspawn`` gemanagt wird. Für vorhersagbare IP-Adressen läuft auf der Bridge-Schnittstelle der DHCP-Server von ``systemd-networkd``. Der wird einfach mittels einer Drop-in-Datei aktiviert und konfiguriert.

::

    # /etc/systemd/network/80-container-vz.network.d/00-dhcp.conf
    [Network]
    Address=192.168.1.1/24
    Address=fd00:1::1/64
    DHCPServer=yes
    IPMasquerade=both

    [DHCPServer]
    ServerAddress=192.168.1.1/24
    EmitDNS=yes
    DNS=9.9.9.9
    EmitRouter=yes
    EmitTimezone=yes
    Timezone=Europe/Berlin
    PoolOffset=99
    PoolSize=150

    [DHCPServerStaticLease]
    # nspawn 1
    MACAddress=12:34:56:00:00:01
    Address=192.168.1.101

    [DHCPServerStaticLease]
    # nspawn 2
    MACAddress=12:34:56:00:00:02
    Address=192.168.1.102

    [DHCPServerStaticLease]
    # qemu 1
    MACAddress=12:34:56:00:01:01
    Address=192.168.1.201

Die einzelnen statischen Leases könnten jeweils auch in eigenen Dateien stecken.

Die andere Besonderheit ist, dass die Fritzbox bei mir nicht für das DHCP zuständig ist. Das macht ein ``dnsmasq`` auf meinem Heimserver in einem ``systemd-nspawn``-Container.

Wichtig ist, dass am Ende aus dem lokalen Netz hinter der Fritzbox via WireGuard auf die einzelnen Container zugegriffen werden kann.

## Konfiguration auf der Fritzbox
Der wichtige Teil findet statt auf der Seite "Internet > Freigaben > VPN (Wireguard)" (Fritz-OS 8.21). Der Assistent wird mit der Schaltfläche "WireGuard®-Verbindung hinzufügen" aufgerufen.

Effektiv musste ich in dem Assistenten immer die rechte Option wählen:

.. thumbnail:: /images/Fritzbox_WireGuard/01_Assistent_Verbindungsart.png
    :alt: Der Assistent fragt, ob ein einzelnes Gerät oder ein komplettes Netzwerk verbunden werden soll.
.. thumbnail:: /images/Fritzbox_WireGuard/02_Assistent_Verbindung_eingerichtet_Frage.png
    :alt: Der Assistent möchte wissen, ob die Verbindung hier gerade neu erstellt wird oder importiert werden soll.
.. thumbnail:: /images/Fritzbox_WireGuard/03_Assistent_weitere_Verbindung_vorhanden.png
    :alt: Jetzt will der Assistent wissen, ob dies die erste oder eine zusätzliche Verbindung auf der Gegenstelle ist.
.. thumbnail:: /images/Fritzbox_WireGuard/04_Assistent_WireGuard_Router.png
    :alt: Der Assistent will (nochmal?) wissen, ob ein einzelnes Gerät oder ein Router mit einem Netzwerk verbunden werden soll.


1. Welche Art Verbindung möchten Sie erstellen? → **Netzwerke koppeln**.
2. Ist diese WireGuard®-Verbindung auf der Gegenstelle bereits eingerichtet? → **Nein**.
3. Soll die Verbindung gleichzeitig zu einer bestehenden WireGuard®-Verbindung der Gegenstelle genutzt werden? → **Nein**. Ich habe nicht geschaut, was "ja" an der Stelle bewirkt. Ich nehme an, davon hängt ab, ob ich eine vollständige Konfiguration kriege oder nur einen Schnipsel zur Ergänzung.
4. Was für ein Gerät befindet sich auf der Gegenstelle? → **WireGuard®-fähiger Router**. Keine Ahnung, warum das abgefragt wird, wenn ich am Anfang "Netzwerke koppeln" ausgewählt habe. Ja natürlich muss da ein WireGuard®-fähiger Router sein.

Der Assistent warnt mich dann:

    Das manuelle Hinzufügen der neuen Verbindungseinstellungen wird nur erfahrenen Benutzern empfohlen.

Naja, wir sind ja erfahren, nicht wahr?

.. thumbnail:: /images/Fritzbox_WireGuard/05_Assistent_Name.png
    :alt: Der Assistent fragt nach einem Namen für die Verbindung.

Als nächstes vergeben wir einen Namen, unter dem die Verbindung geführt wird.

.. thumbnail:: /images/Fritzbox_WireGuard/06_Assistent_DNS_Domain.png
    :alt: Der Assistent fragt nach einer DNS-Domain für die Verbindung.

Der nächste Schritt ist ein wenig unklar. Der Assistent möchte eine Angabe der "DNS-Domains der WireGuard®-Gegenstelle". Nirgends scheint die Angabe eine Auswirkung zu haben. Ich kann nur mutmaßen, dass dieser Wert via DHCP als ``search domain`` verteilt wird. Wie eingangs erwähnt, kümmert sich ein anderes System hier um DHCP.

.. thumbnail:: /images/Fritzbox_WireGuard/07_Assistent_IP_Einstellungen.png
    :alt: Der Assistent fragt nach der IPv4-Adresse und -Subnetzmaske sowie nach der IPv6-Adresse (hier Subnetz per Default /64).

Im vorletzten Schritt fragt der Assistent nach den "IP-Einstellungen der Verbindung". Hier musste ich ein wenig experimentieren, um herauszufinden, was der Assistent damit meint. Letzten Endes funktionierte es mit der IP-Adresse der ``systemd-nspawn``-Zone, deren Netzmaske (`CIDR zu Netzmaske <Subnetz-Kalkulator_>`_) und der ULA-IPv6-Adresse ebendieser Schnittstelle. Bis zu dieser Konfiguration hatte ich der Zonen-Schnittstelle überhaupt keine IPv6-Adresse vergeben, was zu ein bisschen Recherche-Arbeit geführt hat.

.. thumbnail:: /images/Fritzbox_WireGuard/08_Assistent_weitere_Einstellungen.png
    :alt: Der Assistent fragt nach verschiedenen Einstellungen, zum Durchleiten des gesamten Netzverkehr, nach NetBIOS-Unterstützung und ob die Verbindung auf einzelne lokale Geräte beschränkt werden soll.

Im letzten Schritt gibt es ein paar Kästchen anzukreuzen oder auch nicht. In diesem Fall wird nichts davon gebraucht.

.. thumbnail:: /images/Fritzbox_WireGuard/09_Assistent_manuell_hinzufügen.png
    :alt: Die Konfiguration ist bereit zum Herunterladen, damit sie an der Gegenstelle importiert werden könne.

Wenn man zu lange brauchte seit der letzten Bestätigung, dass man berechtigt sei, Änderungen an der Konfiguration vorzunehmen, muss das jetzt nochmal bestätigt werden. Im Anschluss arbeitet die Fritzbox ein wenig und bietet dann den Download der erstellten Konfiguration an, was wir auch annehmen. Nach dem Download muss noch auf "Ok" geklickt werden. Der Assistent weist ein letztes Mal darauf hin, dass die geheimen Verbindungsdaten aus der Datei nicht wieder eingesehen werden können.

.. thumbnail:: /images/Fritzbox_WireGuard/10_Assistent_Zugangsdaten_gesichert.png
    :alt: Eine letzte Warnung, dass die Konfiguration gesichert werden muss. Man kann nochmal zurückgehen. Bei anderer Auswahl weiter am Anfang hätte es auch einen QR-Code im Schritt davor gegeben, den die Fritzbox nicht hätte kontrollieren können. So macht die Warnung wenig Sinn.

::

    [Interface]
    PrivateKey = <privater Schlüssel des Servers>
    Address = 192.168.1.1/24,fd12:3456:7891::/64
    DNS = <private IPv4 und IPv6 der Fritzbox>
    DNS = fritz.box

    [Peer]
    PublicKey = <öffentlicher Schlüssel der Fritzbox>
    PresharedKey = <geteilter Schlüssel der Verbindung>
    AllowedIPs = <private IPv4- und IPv6-Netze der Fritzbox>
    Endpoint = foobar.myfritz.net:52008
    PersistentKeepalive = 25

Eigentlich brauchen wir die Datei gar nicht, aber sie beinhaltet die Werte, die wir für die Konfiguration mit systemd-networkd brauchen.

## Konfiguration von ``systemd-networkd`` auf dem Server
Die Konfigurationsdateien von ``systemd-networkd`` liegen üblicherweise in ``/etc/systedm/network/``.

Die Verbindung wird auf drei Dateien aufgeteilt:

``wg0.netdev``
    Die Datei legt das Netzwerkgerät an. Sie beinhaltet die Verbindung zur Gegenstelle sowie alle für die Verbindung notwendigen Geheimnisse bzw. verweist auf entsprechende Dateien (`vgl. man-Page systemd.netdev, Abschnitt Wireguard <systemd.netdev_>`_).
``wg0.key``
    Die Datei beinhaltet den base64-kodierten privaten Schlüssel des Servers für diese Verbindung.
``wg0.network``
    Hier wird ganz normal das Netzwerk auf der Schnittstelle ``wg0`` konfiguriert – IP-Adressen, Routen und was sonst noch so anfällt (`vgl. man-Page systemd.network <systemd.network_>`_).

Die Namen der Dateien sind beliebig wählbar. Allein bei dem privaten Schlüssel muss drauf geachtet werden, dass die Datei in der ``.netdev``-Datei korrekt referenziert wird.

::

    # wg0.netdev
    [NetDev]
    Name=wg0
    Kind=wireguard
    Description=WireGuard tunnel wg0

    [WireGuard]
    # Vermutlich unnötig, ist einfach auf den gleichen Port gesetzt, den die Fritzbox auch nutzt.
    ListenPort=52008
    PrivateKeyFile=/etc/systemd/network/wg0.key

    [WireGuardPeer]
    AllowedIPs=192.168.178.1/24,fd12:3456:7890::/64
    PublicKey=<öffentlicher Schlüssel der Fritzbox>
    PresharedKey=<geteilter Schlüssel der Verbindung>
    Endpoint=foobar.myfritz.net:52008
    PersistentKeepalive=25

Die Werte für ``PublicKey`` und ``PresharedKey`` können einfach aus der heruntergeladenen Konfigurationsdatei kopiert werden. Tatsächlich benutzen WireGuard und systemd-networkd die gleichen Namen für die Werte, so dass sogar die Zeilen komplett kopiert werden können.

``systemd-networkd`` möchte nicht, dass diese Datei weltlesbar ist, weswegen wir die Berechtigungen und Eigentümerschaft anpassen::

    chmod 640 /etc/systemd/network/wg0.netdev
    chown root:systemd-network /etc/systemd/network/wg0.netdev

Das ``PrivateKeyFile`` beinhaltet einfach nur den Wert ``<privater Schlüssel des Servers>`` aus der Konfigurationsdatei ohne ``PrivateKey=`` oder ähnlichem. Netterweise ist der Wert bereits base64-kodiert, so dass dahingehend nichts weiter getan werden muss. Für die Datei **verlangt** ``systemd-networkd`` aber sogar, dass sie nicht weltlesbar ist::

    chmod 640 /etc/systemd/network/wg0.key
    chown root:systemd-network /etc/systemd/network/wg0.key

Bei der letzten Datei, der ``wg0.network``, ist ``systemd-networkd`` entspannter. Sie kann ruhig von allen gelesen werden.

::

    # wg0.network
    [Match]
    Name=wg0

    [Network]
    Address=192.168.1.1/24
    Address=fd00:1::1/64
    IPMasquerade=both

    [Route]
    Destination=<IPv4-Netzwerk der Fritzbox>

    [Route]
    Destination=<IPv6-Netzwerk der Fritzbox>

Aufmerksamen Leser*innen ist es sicher aufgefallen, und mir bereitet es auch Bauchschmerzen, aber es funktioniert tatsächlich: Die Schnittstelle ``wg0`` erhält die gleichen Adressen und Netzmasken wie die Schnittstelle der ``systemd-nspawn``-Zone.

Mit einem finalen ``networkctl reload`` wird die Schnittstelle aktiviert und der WireGuard-Tunnel aufgebaut.

Da die ``systemd-nspawn``-Container als Default-Route die Adresse der Zonen-Schnittstelle konfiguriert haben, funktionieren Verbindungen von Seiten der Container sofort. Auch die Geräte hinter der Fritzbox können die Container ohne Probleme erreichen, da die Fritzbox –wie in den meisten Fällen– als Gateway konfiguriert ist.

Dieser Blog-Eintrag wurde ohne Unterstützung generativer KI erstellt.

.. _systemd.netdev: https://man.archlinux.org/man/systemd.netdev.5#[WIREGUARD]_SECTION_OPTIONS
.. _systemd.network: https://man.archlinux.org/man/systemd.network.5
.. _Subnetz-Kalkulator: https://www.tunnelsup.com/subnet-calculator/