Eigenständige Anleitung, unabhängig von einzelnen Diensten – relevant für jeden Container auf Mimir, der eine eigene, “echte” LAN-IP braucht (Adblocker, Reverse Proxies mit eigener IP, etc.). Ursprünglich für AdGuard Home erarbeitet.
Warum Macvlan (statt Bridge)?
Docker-Standard ist Bridge-Netzwerk mit NAT – dabei erscheinen alle Container hinter derselben internen Bridge-IP, echte Client-IPs aus dem LAN gehen verloren. Für Anwendungsfälle, in denen ein Dienst als eigenständiges Gerät im LAN auftreten muss (z. B. AdGuard Home für Pro-Client-Erkennung), ist das ungeeignet.
Erkennungsmerkmal eines “falschen” Bridge-Netzwerks in Container Manager: Auch wenn du es ..._macvlan nennst – wenn in der GUI unter Treiber “bridge” steht und “IP Masquerade: Aktivieren” angezeigt wird, ist es kein echtes Macvlan. Die Container-Manager-GUI kann kein echtes Macvlan-Netzwerk erstellen – das geht ausschließlich per SSH.
Die zentrale Einschränkung von Macvlan
Der Host (die NAS selbst) kann seine eigenen Macvlan-Container nicht direkt erreichen – auch nicht über localhost oder Docker-interne Bridges. Das ist eine bewusste Kernel-Einschränkung (Isolation zwischen einem physischen Parent-Interface und seinen Macvlan-Kindern), keine Fehlkonfiguration.
Betrifft:
- Die NAS selbst (Ping/Curl auf die Container-IP schlägt fehl)
- Alle anderen Container auf derselben NAS, deren Traffic über die Host-Routingtabelle läuft (z. B. Bridge-Mode-Container wie NPM)
Nicht betroffen: Alle anderen Geräte im LAN (Laptop, Handy etc.) – die erreichen Macvlan-Container ganz normal, weil diese ja eine echte LAN-IP haben.
Setup-Daten (dieses Netz)
| Wert | |
|---|---|
| LAN-Subnetz | 172.16.46.0/24 |
| Gateway | 172.16.46.1 (FritzBox) |
Reservierter Macvlan-Bereich (Docker --ip-range, nur für Docker-interne Auto-Vergabe relevant, wir setzen aber immer feste IPs) | 172.16.46.200/29 (.200–.207) |
| FritzBox-DHCP-Pool | eingeschränkt auf .1–.199 |
| Parent-Interface | eth0 (kein Open vSwitch aktiv, daher nicht ovs_eth0) |
| Docker-Netzwerkname | lan_macvlan |
| Host-Shim-IP | 172.16.46.206 (per --aux-address reserviert) |
| Statischer IP-Bereich für neue Container ab jetzt | 172.16.46.230–.239 (organisatorische Reservierung, kein Docker-Setting – siehe Konflikt-Abschnitt unten) |
1. Docker-Macvlan-Netzwerk anlegen (per SSH)
sudo docker network create -d macvlan \
--subnet=172.16.46.0/24 \
--gateway=172.16.46.1 \
--ip-range=172.16.46.200/29 \
--aux-address 'host=172.16.46.206' \
-o parent=eth0 lan_macvlan--aux-addressreserviert.206exklusiv für den Host-Shim (siehe unten), damit Docker sie nicht versehentlich an einen Container vergibt.- Danach taucht
lan_macvlanauch in Container Manager auf (Treiber: macvlan, kein Masquerade) und Container können ihr dort per GUI zugewiesen werden.
2. Container mit fester IP im Compose-File
services:
meinservice:
image: irgendein/image
networks:
lan_macvlan:
ipv4_address: 172.16.46.201 # freie IP aus dem reservierten Bereich
...
networks:
lan_macvlan:
external: true3. Host-Zugriff reparieren: Macvlan-Shim
Damit die NAS selbst (und darüber auch Bridge-Mode-Container wie NPM) die Macvlan-Container erreichen kann, braucht der Host ein eigenes virtuelles Interface im selben L2-Segment:
#!/bin/sh
# Kurze Wartezeit, damit eth0 beim Boot sicher bereit ist
sleep 15
# Shim-Interface anlegen (gebunden an dasselbe Parent-Interface wie das Docker-Netzwerk)
ip link add macvlan-shim link eth0 type macvlan mode bridge
# Host bekommt die reservierte Aux-Adresse
ip addr add 172.16.46.206/32 dev macvlan-shim
# Interface aktivieren
ip link set macvlan-shim up
# Route auf den gesamten Macvlan-Bereich über das Shim-Interface
ip route add 172.16.46.200/29 dev macvlan-shimAls Boot-Task einrichten (Synology Taskplaner)
- Systemsteuerung → Taskplaner → Erstellen → Ausgelöste Aufgabe → Benutzerdefiniertes Skript
- Allgemein: Benutzer = root, Ereignis = Beim Start
- Aufgabeneinstellungen → Ausführen des Befehls: obiges Skript einfügen
Test ohne Neustart
# Skript einmalig manuell ausführen (als root), dann:
ip addr show macvlan-shim
ping 172.16.46.200 # IP eines Macvlan-ContainersTest, ob die Boot-Task wirklich greift (empfohlen!)
Nicht nur manuell testen – das sagt nichts über den echten Boot-Vorgang aus:
ip link del macvlan-shim # sauberen Zustand simulieren
ping 172.16.46.200 # sollte jetzt fehlschlagenDanach die Taskplaner-Aufgabe manuell auslösen (Rechtsklick → Ausführen, nicht das Skript direkt in der Shell!) und erneut prüfen. Der eigentliche Beweis ist aber ein echter Reboot.
Bekannte Stolperfalle: Adresse löschen reißt die Route mit
Wenn man testweise nur die IP vom Shim-Interface löscht:
ip addr del 172.16.46.206/32 dev macvlan-shimverschwindet nicht nur die Adresse, sondern auch die zuvor gesetzte Route (ip route get zeigt danach wieder dev eth0 statt dev macvlan-shim). Das Wiederherstellen der Adresse allein reicht dann nicht – die Route muss explizit neu gesetzt werden:
ip addr add 172.16.46.206/32 dev macvlan-shim
ip route add 172.16.46.200/29 dev macvlan-shimFür das Boot-Skript ist das irrelevant, da dort ohnehin beide Befehle bei jedem Start neu ausgeführt werden – die Falle tritt nur beim manuellen Herumprobieren im laufenden Betrieb auf.
4. Bridge-Mode-Container erreichen Macvlan-Container automatisch
Sobald der Shim aktiv ist, profitieren auch andere Container (z. B. NPM im normalen Bridge-Modus mit Portmapping) automatisch mit – deren Traffic zu Macvlan-IPs läuft über die Host-Routingtabelle, die jetzt korrekt auf macvlan-shim zeigt. Keine zusätzliche Netzwerk-Konfiguration am jeweiligen Container nötig.
Quick-Check:
docker exec -it <container-name> curl -I http://172.16.46.200:<port>Verwendet in
- AdGuard Home (Container-IP
172.16.46.200)
⚠️ Konflikt mit FritzBox WireGuard-VPN (entdeckt 2026-07)
Die FritzBox vergibt für jeden neuen WireGuard-VPN-Tunnel automatisch eine IP aus dem LAN – ohne manuelle Vergabe- oder Ausschluss-Möglichkeit. Sie nimmt dabei die erste ARP-unsichtbare (= nicht aktiv antwortende) Adresse direkt oberhalb der DHCP-Pool-Grenze (.199). Reservierte, aber noch nicht durch einen laufenden Container belegte Macvlan-IPs sind für die FritzBox unsichtbar und werden dadurch für VPN-Tunnel eingesammelt.
Passiert: 172.16.46.201, .202, .203, .205 wurden von vier WireGuard-Geräteverbindungen belegt, obwohl im reservierten Docker-Bereich (172.16.46.200/29). Nur .200 (AdGuard) und .206 (Shim) waren durch aktive Container/Interfaces geschützt.
Konsequenz: Diese vier IPs sind dauerhaft an die VPN-Tunnel gebunden (FritzOS erlaubt keine nachträgliche Änderung der VPN-Client-IP außer Löschen+Neuanlegen des Zugangs).
Entscheidung für künftige Macvlan-Container: Neuer, klar getrennter Reservierungsbereich mit Puffer zur DHCP-Pool-Grenze, statt direkt angrenzend:
| DHCP-Pool FritzBox | bleibt .1–.199 |
| Bereits durch VPN belegt | .201, .202, .203, .205 – nicht mehr für Docker nutzen |
| Neuer Docker-Reservierungsbereich | .230–.239 (reichlich Puffer, weitere VPN-Geräte sind unwahrscheinlich, aber übliche Praxis: lieber zu viel Abstand als zu wenig) |
Für mehr Robustheit bei künftigen Containern: Feste mac_address: im Compose-File setzen und die IP vor dem Deployment manuell als Gerät in der FritzBox eintragen (Heimnetz → Netzwerk → Gerät hinzufügen, „IP-Adresse immer diesem Netzwerkgerät zuweisen”). Damit gilt die IP als bekannt/reserviert, auch bevor der Container läuft und ARP-sichtbar ist – verhindert eine Wiederholung dieses Problems, sobald mal mehr VPN-Geräte dazukommen.