DNS-Filter + Full-Tunnel-VPN auf einem VPS. Upstream ist Cloudflare (DoH). Query-Log und Statistiken sind deaktiviert. Images: :latest.
Korrekturen gegenüber der Original-Anleitung: siehe NOTES.md.
- Linux-Host mit Docker + Compose-Plugin
perl(für Passwort-Hash beim Erstdeploy)- UDP-Port
51820(oderSERVERPORT) in der Firewall offen - Root für den Deploy (Verzeichnis unter
/opt) - Ideal: Kernel-Modul
wireguard(sonst Fallback auf userspace)
cd /path/to/dieses-repo
cp .env.example .env
# .env anpassen: SERVERURL, PEERS, ADMIN_PASSWORD, BLOCKLIST_LEVEL, optional DEPLOY_DIR
# Passwörter mit Sonderzeichen in Anführungszeichen: ADMIN_PASSWORD='P@ss$w0rd!'
# Blocklist: soft | medium | hard (Default: medium)
sudo ./deploy.sh
# optional Firewall: sudo ./deploy.sh --ufwStandard-Ziel: /opt/wirehole-adguard. DEPLOY_DIR setzen per Umgebung (Vorrang) oder in .env (muss unter /opt liegen):
DEPLOY_DIR=/opt/mein-vpn sudo ./deploy.shsudo ./deploy.shAktualisiert den Stack, ohne bestehende Config zu überschreiben:
.env,adguard-conf/AdGuardHome.yaml,adguard-data/wireguard-config/(Keys, Peer-Confs, vorhandenestemplates/peer.conf)docker-compose.ymlnur wenn identisch oder mit--force-compose(legt.bak.<timestamp>an)
sudo ./deploy.sh --force-compose # Compose aus dem Repo übernehmen
sudo ./deploy.sh --ufw # UFW: SERVERPORT/udp erlauben (wenn ufw aktiv)├── deploy.sh
├── docker-compose.yml
├── .env.example
├── NOTES.md
├── adguard-conf/
│ └── AdGuardHome.yaml.example # → AdGuardHome.yaml beim Erstdeploy
└── wireguard-config/
└── templates/
└── peer.conf # inkl. MTU = 1360
Alle Compose-Befehle im Deploy-Verzeichnis:
cd /opt/wirehole-adguard
docker compose --env-file .env ps
docker compose --env-file .env logs -f adguardhome
docker compose --env-file .env restart
docker compose --env-file .env pull && docker compose --env-file .env up -dWireGuard-Logs sind absichtlich deaktiviert (logging: driver: none). Diagnose über Peer-Configs und wg-Status im Container:
docker exec -it wireguard wg showClients steuerst du über PEERS in der Deploy-.env (Standard: /opt/wirehole-adguard/.env). Namen nur alphanumerisch, kommagetrennt (z. B. myphone, nicht mein-laptop).
sudo nano /opt/wirehole-adguard/.env
# z. B. PEERS=myphone,spousephone,tablet,laptop
cd /opt/wirehole-adguard
docker compose --env-file .env up -dDas Image erkennt die geänderte Liste und erzeugt für neue Namen Keys + Config. Bestehende Peers behalten ihre Keys.
Anschließend QR oder Config holen (siehe unten), z. B.:
docker exec -it wireguard /app/show-peer laptopNamen aus PEERS streichen und Stack neu starten (docker compose --env-file .env up -d). Der Ordner unter wireguard-config/peer_… bleibt oft liegen — zum endgültigen Löschen Ordner manuell entfernen und erneut neu starten.
LOG_CONFS=false belassen (Default), damit beim Start keine QR-Codes in Logs landen.
Alles liegt unter dem Deploy-Verzeichnis (Standard: /opt/wirehole-adguard/wireguard-config/). Peer-Namen entsprechen den Einträgen in PEERS (z. B. myphone → Ordner peer_myphone).
docker exec -it wireguard /app/show-peer myphoneMehrere Peers auf einmal:
docker exec -it wireguard /app/show-peer myphone spousephone tabletPro Peer:
/opt/wirehole-adguard/wireguard-config/peer_myphone/
peer_myphone.conf ← Client-Config (App-Import / QR)
peer_myphone.png ← QR als Bilddatei
privatekey-peer_myphone
publickey-peer_myphone
presharedkey-peer_myphone
Anzeigen bzw. herunterladen:
cat /opt/wirehole-adguard/wireguard-config/peer_myphone/peer_myphone.conf
# vom lokalen Rechner:
scp user@VPS:/opt/wirehole-adguard/wireguard-config/peer_myphone/peer_myphone.conf .
scp user@VPS:/opt/wirehole-adguard/wireguard-config/peer_myphone/peer_myphone.png .Die .conf reicht für die WireGuard-App. Einzelne Keys brauchst du nur für manuelle Setups.
/opt/wirehole-adguard/wireguard-config/server/
privatekey-server
publickey-server
Nur auf 127.0.0.1:8080 des VPS — per SSH-Tunnel:
ssh -N -L 8080:localhost:8080 user@DEINE_VPS_IPBrowser: http://localhost:8080 — Login: ADMIN_USER / Passwort aus der Erstinstallation.
Nach dem ersten Login ADMIN_PASSWORD aus der Deploy-.env entfernen oder auskommentieren (Klartext).
HaGeZi Multi über BLOCKLIST_LEVEL in der Deploy-.env:
| Level | HaGeZi-Liste | Datei |
|---|---|---|
soft |
Multi Light | light.txt |
medium (Default) |
Multi Normal | multi.txt |
hard |
Multi Pro | pro.txt |
sudo nano /opt/wirehole-adguard/.env
# BLOCKLIST_LEVEL=hard
sudo ./deploy.shdeploy.sh schreibt die Filter-URL in AdGuardHome.yaml (Container wird dafür kurz gestoppt, falls nötig) und startet den Stack neu. In der UI unter Filter sollte die gewählte Liste erscheinen; einmal „Filter aktualisieren“ falls noch leer.
Default: IPv4-only Full-Tunnel (ALLOWEDIPS=0.0.0.0/0).
AdGuard setzt dns.aaaa_disabled: true: keine AAAA-Antworten → Clients nutzen IPv4 über den VPN und umgehen ihn nicht über Handy-IPv6. (Bei echtem IPv6-Tunnel später wieder auf false setzen.)
Nur Link-Local (fe80::…) oder gar kein IPv6 am Host → ALLOWEDIPS so belassen. Mit ::/0 ohne vollständige IPv6-WG-Konfiguration drohen Timeouts.
Wenn der Host öffentliches IPv6 hat und du IPv6 mit tunneln willst (zusätzlicher Aufwand, siehe linuxserver-Limits):
ALLOWEDIPS='0.0.0.0/0, ::/0' # Anführungszeichen PflichtDann in AdGuardHome.yaml aaaa_disabled: false setzen, Stack/Peers neu laden.
Nach jeder ALLOWEDIPS-Änderung Stack neu starten und Peer-Configs neu importieren.
Bestehende Installation (YAML wird von deploy.sh nicht überschrieben): in der UI unter DNS-Einstellungen „IPv6 deaktivieren“, oder:
# AdGuard kurz stoppen, in AdGuardHome.yaml unter dns: ergänzen:
# aaaa_disabled: true
cd /opt/wirehole-adguard
docker compose --env-file .env stop adguardhome
# YAML editieren, dann:
docker compose --env-file .env up -dAdGuard leitet Anfragen per DoH an Cloudflare weiter:
https://cloudflare-dns.com/dns-queryhttps://1.1.1.1/dns-query- Bootstrap:
1.1.1.1,1.0.0.1 - Fallback:
tls://1.0.0.1
VPN-Clients nutzen PEERDNS=10.2.0.100 (AdGuard im Docker-Netz). Port 53 bleibt vom Host isoliert.
| Symptom | Prüfung |
|---|---|
| Kein Handshake | Firewall UDP SERVERPORT; SERVERURL = öffentliche IP/DNS; docker exec wireguard wg show |
| Modul-Warnung beim Deploy | modprobe wireguard bzw. wireguard/wireguard-tools installieren |
| DNS im VPN tot | docker compose ps — AdGuard healthy?; Peer-DNS = ADGUARD_IP |
| UI nicht erreichbar | SSH-Tunnel aktiv? Nur 127.0.0.1:8080 am VPS |
| Compose-Änderung greift nicht | sudo ./deploy.sh --force-compose (legt Backup an) |
| Peer ohne MTU 1360 | Template existiert schon — manuell MTU = 1360 in templates/peer.conf, dann Env-Änderung oder Peer-Conf neu erzeugen |
| Filter leer | Ausgehendes HTTPS; in der UI Filter aktualisieren; BLOCKLIST_LEVEL prüfen |
| Langsame Apps / IPv6-Timeouts | ALLOWEDIPS=0.0.0.0/0; aaaa_disabled: true in AdGuard; Peers neu importieren |
compression cannot be enabled when max file count is 1 |
Compose aktualisieren (sudo ./deploy.sh --force-compose) — Logging-Fix |
- Zero-Log: Query-Log/Statistiken aus; WireGuard-Docker-Logs
driver: none. Container-Logs (AdGuard), Filter-Downloads und Handshake-State können trotzdem anfallen. - Passwort:
ADMIN_PASSWORDgilt nur beim ersten Anlegen vonAdGuardHome.yaml. Sonderzeichen in.envquoten. - Rechte: Deploy setzt
700auf Config-Dirs und600auf.env, YAML und Keys. - Peers: Anlegen/Entfernen siehe Abschnitt „Clients anlegen und verwalten“. Bei Endpoint-/DNS-Änderung Clients ggf. neu importieren.
- MTU: Template setzt
MTU = 1360für Mobilfunk. Nur wirksam für neu generierte / regenerierte Peer-Confs. - Blocklist:
BLOCKLIST_LEVEL=soft|medium|hard— Wechsel per.env+sudo ./deploy.sh. - IPv4/IPv6: Default
ALLOWEDIPS=0.0.0.0/0undaaaa_disabled: true.::/0nur mit echter IPv6-WG-Konfiguration; dannaaaa_disabled: false. Wert mit::/0immer quoten.