
Mit dieser Anleitung baust du einen zentralen DNS-Resolver mit AdGuard Home und einen sicheren Fernzugriff mit WireGuard auf einem Linux-Server auf. Beide Dienste laufen als Docker-Container und werden mit Docker Compose verwaltet. Verbundene VPN-Geräte verwenden AdGuard automatisch als DNS-Server und können interne Namen wie nas.home.arpa auflösen.
1. Ziel und Netzwerkarchitektur
Der WireGuard-Container stellt das VPN-Gateway bereit. AdGuard Home teilt sich dessen Netzwerk-Namespace. Dadurch ist AdGuard unter der WireGuard-Serveradresse 10.13.13.1 erreichbar, ohne den DNS-Port 53 öffentlich am Docker-Host freizugeben.
- WireGuard: UDP-Port 51820 von außen erreichbar.
- AdGuard Home: DNS über TCP/UDP 53 innerhalb des VPN; Verwaltungsoberfläche über einen nur intern bzw. per Firewall freizugebenden Host-Port.
- VPN-Netz:
10.13.13.0/24; Serveradresse10.13.13.1. - Interne DNS-Zone: beispielhaft
home.arpa.
Wichtig: „100 % Docker“ bedeutet hier, dass WireGuard und AdGuard als Container laufen. WireGuard benötigt trotzdem Funktionen des Linux-Kernels (WireGuard-Modul, Netzwerk-Forwarding und die Berechtigung NET_ADMIN). Ein Linux-Host ohne passende Kernel-Unterstützung kann den Tunnel nicht allein durch Docker bereitstellen.
Zudem wenn man Serverseitig auf einem LXC Container, virtualisieren möchte, so muss man in /etc/pve/lxc/<deine-lxc-ct-id>.conf folgendes eintragen um WireGuard zu ermöglichen:

lxc.cgroup.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net dev/net none bind,create=dir
2. Voraussetzungen
- Debian oder Ubuntu auf einem Linux-Server mit aktueller Docker Engine und Docker Compose Plugin.
- Root- bzw. sudo-Rechte und ein öffentlich erreichbarer UDP-Port 51820.
- Eine feste öffentliche IP oder ein DynDNS-Hostname, z. B.
vpn.example.net. - Ein freies VPN-Netz, das nicht mit deinem LAN kollidiert. In diesem Beispiel
10.13.13.0/24. - Für den Zugriff auf LAN-Geräte zusätzlich die passende LAN-Route und Firewall-/Forwarding-Regeln.
Prüfe zunächst, ob der Kernel WireGuard unterstützt:
modprobe wireguard
lsmod | grep wireguard
Falls modprobe meldet, dass das Modul nicht gefunden wird, installiere das passende Kernel-Modul für deine Distribution bzw. deinen Kernel. Das Modul wird auf dem Host benötigt, nicht als separates Paket im Container.
3. Docker Dienste installieren
Wir installieren und testen auf dem OS-System: Debian 13 – Trixie auf einem LXC Container
Dazu gibt es hier eine Offizielle Anleitung zum installieren für die Docker-Dienste
# Add Docker's official GPG key:
apt update
apt install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
apt update
apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
4. Verzeichnisse anlegen
mkdir -p /opt/wireguard/config
mkdir -p /opt/adguard/work
mkdir -p /opt/adguard/conf
mkdir -p /opt/vpn-dns
chown -R 1000:1000 /opt/wireguard /opt/adguard
Die Verzeichnisse speichern Schlüssel, Peer-Konfigurationen, DNS-Statistiken und die AdGuard-Einstellungen dauerhaft. Sichere diese Daten regelmäßig und behandle insbesondere den WireGuard-Ordner wie ein Geheimnis.
5. Docker Compose erstellen
Lege /opt/vpn-dns/docker-compose.yml an. Passe unbedingt SERVERURL, Zeitzone und bei Bedarf UID/GID sowie die Netze an.
services:
wireguard:
image: lscr.io/linuxserver/wireguard:latest
container_name: wireguard
cap_add:
- NET_ADMIN
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Berlin
- SERVERURL=vpn.example.com
- SERVERPORT=51820
- PEERS=peer1,peer2
- PEERDNS=10.13.13.1
- INTERNAL_SUBNET=10.13.13.0
- ALLOWEDIPS=0.0.0.0/0
- LOG_CONFS=false
- USE_COREDNS=false
volumes:
- /opt/wireguard/config:/config
ports:
- "51820:51820/udp"
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv4.ip_forward=1
restart: unless-stopped
adguardhome:
image: adguard/adguardhome:latest
container_name: adguardhome
network_mode: "service:wireguard"
depends_on:
- wireguard
volumes:
- /opt/adguard/work:/opt/adguardhome/work
- /opt/adguard/conf:/opt/adguardhome/conf
restart: unless-stopped
Warum teilt AdGuard den Netzwerk-Namespace?
Der AdGuard-Container hängt damit direkt im Netzwerk des WireGuard-Containers. Er kann DNS-Anfragen an der VPN-Adresse 10.13.13.1:53 entgegennehmen. Es gibt absichtlich keine öffentliche Portfreigabe für DNS. Die Verwaltungsports 3000 und 8080 werden dagegen am Host veröffentlicht und müssen durch die Host-Firewall auf vertrauenswürdige Quellnetze begrenzt werden.
Hinweis zu PEERDNS: Die LinuxServer-WireGuard-Variable schreibt die DNS-Adresse in die generierten Peer-Konfigurationen. Hier wird explizit 10.13.13.1 gesetzt, damit VPN-Clients AdGuard Home statt eines öffentlichen DNS-Resolvers verwenden. Falls deine Container-Version oder ein zusätzlich aktivierter DNS-Dienst Port 53 bereits belegt, prüfe die Container-Logs und die Listener, bevor du fortfährst.
Hinweis zu ALLOWEDIPS: 0.0.0.0/0 ist ein Full-Tunnel-Beispiel: Der gesamte IPv4-Verkehr des Clients läuft durch das VPN. Für Split-Tunneling trägst du stattdessen nur die VPN- und benötigten LAN-Netze ein. IPv6 ist in diesem Beispiel nicht als Full-Tunnel konfiguriert; ergänze IPv6 bewusst und vollständig, wenn du es nutzen möchtest.
6. Container starten
cd /opt/vpn-dns
docker compose config
docker compose pull
docker compose up -d
docker compose ps
Kontrolliere bei Problemen die Logs:
docker compose logs --tail=100 wireguard
docker compose logs --tail=100 adguardhome
7. AdGuard Home einrichten
Öffne während der Ersteinrichtung die Oberfläche über http://SERVER-IP:3000. Der Assistent führt durch die Einrichtung. Wähle als DNS-Listener eine Adresse, die im gemeinsamen Netzwerk-Namespace erreichbar ist (für diesen Aufbau typischerweise alle Interfaces), und Port 53. Richte einen sicheren Administratorzugang ein.
Nach dem Assistenten erreichst du die Weboberfläche über http://SERVER-IP:8080, sofern du im Assistenten den Web-Port 80 im Container gewählt hast. Beschränke den Zugriff auf das LAN oder den VPN-Zugang. Stelle die Verwaltungsoberfläche niemals ungeschützt ins Internet.
Unter Filter kannst du passende Filterlisten aktivieren. Unter Einstellungen → DNS-Einstellungen legst du vertrauenswürdige Upstream-DNS-Server fest. Wähle Anbieter und Datenschutzrichtlinie bewusst aus.
8. Interne DNS-Namen anlegen
Lege in AdGuard Home unter Filter → DNS-Umschreibungen (DNS rewrites) Einträge für deine internen Geräte an. Beispiel:
| Hostname | Interne IPv4-Adresse |
|---|---|
nas.home.arpa | 192.168.1.10 |
proxmox.home.arpa | 192.168.1.20 |
printer.home.arpa | 192.168.1.30 |
Ersetze die Beispieladressen durch die tatsächlichen, möglichst statischen IP-Adressen deines Netzes. home.arpa ist für Heimnetze reserviert und eignet sich besser als frei erfundene öffentliche Domains oder die veraltete Endung .local.
9. WireGuard-Peers prüfen
Der LinuxServer-Container erzeugt für phone und laptop Peer-Konfigurationen im persistenten Verzeichnis. Zeige die Konfigurationen an:
find /opt/wireguard/config -maxdepth 3 -type f
docker exec -it wireguard /app/show-peer phone laptop
Importiere die jeweilige Konfiguration in die offizielle WireGuard-App oder scanne den QR-Code. Prüfe in der Client-Konfiguration, dass als DNS-Server 10.13.13.1 eingetragen ist. Teile private Schlüssel und QR-Codes niemals öffentlich.
Skript für Peer Generieren
Ich habe einmal ein Skript angefertigt womit man peers einfacher und schneller für wireguard generieren kann.
Speicherort bitte bei: /opt/vpn-dns/create_peer.sh
Und mit: ./create_peer.sh ausführen
#!/bin/bash
set -e
# Eingaben
read -rp "Peer Name (ohne Leerzeichen): " peer
read -rp "Peer Local-IP: " ipv4
# Peer-Namen validieren
if [[ ! "$peer" =~ ^[a-zA-Z0-9_-]+$ ]]; then
echo "Fehler: Ungueltiger Peer-Name!"
exit 1
fi
# IP-Adresse validieren
if [[ ! "$ipv4" =~ ^10\.13\.13\.[0-9]+$ ]]; then
echo "Fehler: Ungueltige WireGuard-IP!"
exit 1
fi
PEER_DIR="/opt/wireguard/config/peer_${peer}"
# Prüfen, ob Peer bereits existiert
if [[ -d "$PEER_DIR" ]]; then
echo "Fehler: Peer existiert bereits!"
exit 1
fi
# Verzeichnis im Container erstellen
docker exec wireguard mkdir -p "/config/peer_${peer}"
# Berechtigungen setzen und Keys generieren
docker exec wireguard sh -c "
umask 077
wg genkey > /config/peer_${peer}/privatekey
wg pubkey < /config/peer_${peer}/privatekey > /config/peer_${peer}/publickey
"
# Ins Config-Verzeichnis wechseln
cd /opt/wireguard/config
# Schlüssel auslesen
SERVER_PUBLIC_KEY=$(docker exec wireguard wg show wg0 public-key)
CLIENT_PRIVATE_KEY=$(cat "${PEER_DIR}/privatekey")
CLIENT_PUBLIC_KEY=$(cat "${PEER_DIR}/publickey")
# Konfigurationsdatei erstellen
cat > "${PEER_DIR}/peer_${peer}.conf" <<EOF
[Interface]
PrivateKey = ${CLIENT_PRIVATE_KEY}
Address = ${ipv4}/32
DNS = 10.13.13.1
[Peer]
PublicKey = ${SERVER_PUBLIC_KEY}
Endpoint = ${SERVERURL}:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF
# Berechtigungen setzen
chown -R 1000:1000 "${PEER_DIR}"
chmod 700 "${PEER_DIR}"
chmod 600 "${PEER_DIR}"/*
# Peer zu WireGuard hinzufügen
docker exec wireguard wg set wg0 peer "$CLIENT_PUBLIC_KEY" allowed-ips "${ipv4}/32"
# WireGuard Status anzeigen
docker exec wireguard wg show
echo ""
echo "Peer erfolgreich angelegt!"
echo "Peer: ${peer}"
echo "IP: ${ipv4}"
echo "Config: ${PEER_DIR}/peer_${peer}.conf"
ls -lah "${PEER_DIR}"
exit 0
10. DNS und VPN testen
Aktiviere den Tunnel auf einem Mobilgerät oder Laptop und teste zunächst die Erreichbarkeit des VPN-Servers sowie die DNS-Auflösung:
ping 10.13.13.1
nslookup nas.home.arpa 10.13.13.1
# alternativ:
dig @10.13.13.1 nas.home.arpa
Die Antwort für nas.home.arpa sollte die von dir in AdGuard hinterlegte LAN-IP enthalten. Im AdGuard-Abfrageprotokoll sollte die Anfrage des VPN-Clients auftauchen.
DNS-Auflösung und Zugriff auf das Zielgerät sind zwei verschiedene Dinge: Damit du anschließend auch nas.home.arpa öffnen kannst, muss der Client eine Route zum LAN besitzen und der Server muss Pakete zwischen VPN und LAN weiterleiten dürfen. Bei Split-Tunneling muss das LAN-Netz in ALLOWEDIPS der Peer-Konfiguration enthalten sein. Auf dem Server sind IP-Forwarding und passende Firewall-/NAT- oder Rückrouten erforderlich. Die genaue Regel hängt von deiner LAN-Schnittstelle, Firewall und deinem Router ab; übernimm keine pauschale NAT-Regel ohne Anpassung.
11. Sicherheit und Firewall
- Öffne am Internet-Router nur UDP 51820 zum VPN-Server.
- Gib TCP/UDP 53 nicht öffentlich frei. DNS soll nur über vertrauenswürdige Netze bzw. das VPN erreichbar sein.
- Beschränke TCP 3000 (Ersteinrichtung) und TCP 8080 (AdGuard-Admin) per Firewall auf LAN/VPN und entferne die 3000-Portfreigabe nach der Einrichtung aus Compose, wenn sie nicht mehr benötigt wird.
- Verwende starke, einzigartige Zugangsdaten für AdGuard Home.
- Halte Docker-Images aktuell und sichere
/opt/wireguard/configsowie/opt/adguard. - Veröffentliche keine Peer-Konfigurationen, privaten Schlüssel oder QR-Codes.
12. Häufige Fehler und Lösungen
Port 53 ist bereits belegt
Prüfe mit sudo ss -lntup | grep ':53', welcher Dienst Port 53 verwendet. Häufig ist es systemd-resolved. Ändere die Host-DNS-Konfiguration nur mit Bedacht und erst, nachdem du einen Rückfallweg sichergestellt hast. In dieser Compose-Architektur wird DNS nicht am Host veröffentlicht; ein Konflikt kann daher auch aus dem gemeinsam genutzten Container-Namespace kommen.
VPN verbindet, aber DNS funktioniert nicht
Prüfe, ob AdGuard läuft, auf Port 53 lauscht und die Peer-Konfiguration DNS = 10.13.13.1 enthält. Prüfe außerdem, ob die Client-Route das VPN-Netz umfasst und ob die Firewall DNS über UDP und TCP 53 zulässt.
Interne Namen lösen auf, aber Dienste sind nicht erreichbar
Das ist meist ein Routing- oder Firewall-Problem und kein DNS-Problem. Prüfe LAN-Routen, IP-Forwarding, Rückroute zum VPN-Netz und die Firewall des Zielgeräts. Stelle sicher, dass dein Router Antworten zum VPN-Netz 10.13.13.0/24 zurückleiten kann oder richte eine bewusst geplante NAT-Lösung ein.
AdGuard-Weboberfläche ist nicht erreichbar
Prüfe den im Setup-Assistenten gewählten Web-Port, die Portzuordnung in Compose und die Host-Firewall. Der hier gezeigte Zugriff über Port 80 / http setzt voraus, dass AdGuard im Container auf Port 80 lauscht.
Wichtig: AdGuard Home ist unter: http://10.13.13.1/ nach der Einrichtung aber auf zuerst 3000 und dann im Anschluss auf Port 80 / http wieder erreichbar.
Nach einer Änderung greift die Peer-DNS-Einstellung nicht
Prüfe die tatsächlich generierte Peer-Konfiguration. Änderungen an Umgebungsvariablen regenerieren nicht in jedem Fall bestehende Peer-Dateien automatisch. Sichere zuerst die Konfiguration und folge dann der Dokumentation des verwendeten Images zur gezielten Regeneration.
13. Fazit
Mit WireGuard und AdGuard Home in Docker erhältst du einen zentral verwalteten VPN-Zugang und einen internen DNS-Resolver. VPN-Geräte können damit interne Namen auflösen und – sofern Routing und Firewall korrekt eingerichtet sind – auf Dienste im Heim- oder Firmennetz zugreifen. Die Trennung der persistenten Konfigurationen erleichtert Backups und Wartung.
