Kerim Kaan Dönmez
Şu tarihte

Tailscale + AdGuard Home: MagicDNS ile HA

Giriş

Geçen yazıda Tailscale + AdGuard Home ile dağıtık DNS kurmuştuk. Kurulum hızlıydı, kullanımı rahattı ama tek node çalıştırdığımız için önemli bir kırılganlığı vardı: AdGuard servisi bir sebeple giderse internet varmış gibi görünse de isim çözümleme gittiği için her şey kilitleniyor kısaca SPoF (single point of failure) durumu oluyor.

Bu yazıda o problemi kapatmak için iki node'lu bir mimari kuruyoruz.

Gerekenler:

  • 2 AdGuard node'u (Kısaca iki farklı node, node sayısı size kalmış, örnek olarak iki node'lu bir mimari kuruyoruz)
  • Tailscale MagicDNS
  • AdGuard Home konfigürasyon senkronizasyonu için bakito/adguardhome-sync

Yani iki node da aktif çalışıyor, biri düşerse de çözümleme öteki node'dan devam ediyor.

MagicDNS?

Tailscale istemcileri DNS sorgularını doğrudan node IP'lerine değil 100.100.100.100 adresindeki MagicDNS'e gönderir. MagicDNS de Tailscale panelinde tanımladığınız nameserver'lara bu sorguları iletir. Bu yüzden node'larınız aktif-aktif çalışırken sorgu dağılımını da MagicDNS tarafı yönetir.

0) Mimariyi Bir Çizelim

Clients (macOS / iOS / Android / Linux / Windows)
                    |
                    | DNS istekleri
                    v
      +------------------------------------+
      | MagicDNS (100.100.100.100)         |
      +-------------------+----------------+
                          |
                          | Tanımlı nameserver'lara iletir
                          v
      +------------------------------------+
      | Tailscale DNS Nameservers          |
      | - 100.77.34.12                     |
      | - 100.88.45.19                     |
      +-------------------+----------------+
                          |
            +-------------+-------------+
            |                           |
+-----------v--------------+ +----------v-------------+
| core-gateway-1           | | core-gateway-2         |
| AdGuard Home :53         | | AdGuard Home :53       |
| Admin/API :3000          | | Admin/API :3000        |
+------------+-------------+ +------------+-----------+
             \                           /
              \                         /
               +-----------+-----------+
                           |
                           v
              +--------------------------+
              | Upstream DNS (DoH/DoT)   |
              | 1.1.1.1 / 9.9.9.9 vb.    |
              +--------------------------+

+----------------------------------------------+
| adguardhome-sync (Docker @ core-gateway-1)   |
| CRON: */5 * * * *                            |
| Config source API: 100.77.34.12:3000         |
| Config target API: 100.88.45.19:3000         |
+----------------------------------------------+

1) Ön Kabul: Node'lar Zaten Tailnet'te

Bu yazıda Tailscale kurulumunu tekrar anlatmıyorum; bir önceki yazıdaki kurulumun hazır olduğunu varsayıyorum. Burada sadece DNS yüksek erişilebilirlik katmanına odaklanıyoruz.

Örnek node isimleri ve tailnet IP'leri:

  • core-gateway-1 -> 100.77.34.12 (Konfigürasyon için source node)
  • core-gateway-2 -> 100.88.45.19

Kontrol için her iki node'da da:

tailscale status

çıktısında node'ların online göründüğünden ve bu iki IP'nin erişilebilir olduğundan emin ol.

2) Her İki Node'a AdGuard Home Kur

curl -sSL https://static.adguard.com/adguardhome/release/AdGuardHome_linux_amd64.tar.gz -o adguard.tar.gz
tar xzf adguard.tar.gz
sudo ./AdGuardHome/AdGuardHome -s install

Kurulum sihirbazında iki not önemli:

  • Admin arayüzünü tailnet dışına açma (mümkünse, mümkün değilse ufw gibi birşeylerle kısıtla)
  • DNS portu 53, admin portu 3000

Bu noktada iki node da çalışıyor ama ayarları hala elle çift girmek gerekiyor. Orayı adguardhome-sync çözüyor.

3) adguardhome-sync ile Konfigürasyon Senkronu

Burada küçük ama önemli ayrım var: DNS tarafı aktif-aktif, ama konfigürasyon tarafında drift olmasın diye bir node'u source of truth seçiyoruz. Ayarı source node'da yapıyoruz, diğeri otomatik alıyor.

docker-compose.yml:

services:
  adguardhome-sync:
    image: ghcr.io/bakito/adguardhome-sync:latest
    container_name: adguardhome-sync
    command: run
    environment:
      LOG_LEVEL: info
      CRON: '*/5 * * * *'
      RUN_ON_START: 'true'

      ORIGIN_URL: 'http://100.77.34.12:3000'
      ORIGIN_USERNAME: 'admin'
      ORIGIN_PASSWORD: '${AGH_ORIGIN_PASSWORD}'

      REPLICA1_URL: 'http://100.88.45.19:3000'
      REPLICA1_USERNAME: 'admin'
      REPLICA1_PASSWORD: '${AGH_REPLICA1_PASSWORD}'

      API_PORT: '0'
    restart: unless-stopped

.env:

AGH_ORIGIN_PASSWORD='cokGucluBirSifre'
AGH_REPLICA1_PASSWORD='cokGucluBirSifre'

Çalıştır:

docker compose up -d
docker logs -f adguardhome-sync

Eğer AdGuard tarafında self-signed TLS varsa:

ORIGIN_INSECURE_SKIP_VERIFY='true'
REPLICA1_INSECURE_SKIP_VERIFY='true'

Not: Şifrede $ karakteri varsa docker compose interpolation yüzünden $$ olarak kaçırman gerekir.

4) Tailscale DNS Ayarı

Tailscale admin panelinde DNS kısmına iki nameserver gir:

  • 100.77.34.12
  • 100.88.45.19

MagicDNS açık kalsın.

Burada kritik nokta: client'lar sorguyu 100.100.100.100 (MagicDNS) adresine atar. MagicDNS de tanımlı nameserver'lara iletir. İletim davranışı her zaman katı bir sıra izlemek zorunda değil, client/OS/Tailscale durumuna göre iki node da aktif şekilde sorgu alabilir.

Node'lardan biri gittiğinde de çözümleme diğer nameserver üzerinden devam eder. Bunu MagicDNS tarafı yönetir, ekstra bir failover mekanizması kurmanız gerekmez.

Tailscale'de gerekli ayarı (Use Tailscale DNS) yaparsanız DNS istemcileriniz otomatik olarak 100.100.100.100 adresine yönlendirilecektir. Bu MagicDNS adresidir. İstemcileriniz (cihazlarınız) bu adresi kullanmalı, böylelikle DNS çözümleme işlemleri iki node'a da gidecektir.

5) Aktif-Aktif + Kesinti Testi

Normal durum:

dig @100.77.34.12 github.com +short
dig @100.88.45.19 github.com +short

Ardından istemciden seri sorgu at:

for i in {1..30}; do dig github.com +short > /dev/null; done

İstersen aynı anda iki node'da query log bakarak yükün tek node'a kilitlenmediğini görebilirsin.

Şimdi node-a'yı bilerek indir:

ssh root@100.77.34.12 "systemctl stop AdGuardHome"

İstemciden sorgu at:

dig github.com

Sonra node-a'yı geri kaldır:

ssh root@100.77.34.12 "systemctl start AdGuardHome"

Bu testi en az bir masaüstü bir de mobil istemcide dene. Resolver timeout davranışları cihazdan cihaza küçük fark gösterebiliyor.

6) Notlar

  • AdGuard admin panelini sadece tailnet IP aralığına aç.
  • Değişikliği hep config source node'da yap; target node'u elle kurcalama (drift yaratır).
  • Mümkünse hem node'ları hem AdGuard Home'u hem Tailscale'ı hem de adguardhome-sync'i güncel tut.
  • Query log'ları ve DNS istemcilerini takip et. (Bilinmeyen istemciler, timeout'lar vs.)
  • Tailscale'de Use Tailscale DNS ayarını kontrol et.
  • Adguard Home'da DoT/DoH upstream'leri kullanmaya özen göster.
  • Node'lar fiziksel olarak farklı yerlerde olmalı, aynı fiziksel ortamda olmamalı.
  • Clientlar ile nodelar fiziksel olarak çok uzakta olmamalı, DNS latency dert olabilir.

Saded

Tek node kurulum hızlı bir başlangıç için güzel ama olası bir kesinti durumunda erişimi kaybediyorsun. Aktif-aktif iki node + adguardhome-sync ile mimari hala sade kalıyor ama dayanıklılık (reliability) artıyor.