WireGuard ile Dinamik DNS Kullanımı

Eve internet bağlantısının IP adresi her gece değişiyor, sunucunda WireGuard kurulu ama sabah işe gittiğinde tünel kopmuş oluyor. Tanıdık geldi mi? Bu senaryo, WireGuard ile dinamik DNS kullanımının neden bu kadar önemli olduğunu en güzel şekilde açıklıyor. Statik IP adresi lüksüne sahip olmayan kullanıcılar için dinamik DNS, WireGuard kurulumunun vazgeçilmez bir parçası haline geliyor.

Bu yazıda WireGuard ile dinamik DNS’i nasıl düzgün entegre edeceğini, hangi tuzaklara düşmemek gerektiğini ve gerçek dünya senaryolarında nasıl stabil bir kurulum elde edeceğini adım adım ele alacağız.

Dinamik DNS Neden Gerekli?

WireGuard peer konfigürasyonunda Endpoint parametresi bir IP adresi veya hostname kabul eder. Çoğu ev ve küçük ofis internet bağlantısı dinamik IP kullandığı için bu adres periyodik olarak değişir. ISP’ler genellikle her 24 saatte bir, bazen de modem yeniden başlatıldığında yeni bir IP atar.

Sorun şu: WireGuard, endpoint’i bağlantı kurma anında çözümler ve sonra hafızasına yazar. IP değiştiğinde WireGuard yeni DNS çözümlemesi yapmaz. Bağlantı kesilir ve elle müdahale gerekir.

Dinamik DNS (DDNS) servisleri bu sorunu şöyle çözer: Bir istemci yazılım, IP adresindeki değişikliği sürekli izler ve değişim olduğunda DNS kaydını otomatik günceller. Böylece vpn.evim.duckdns.org gibi bir hostname her zaman güncel IP adresine işaret eder.

Ama burada da WireGuard’a özgü bir sorun var: WireGuard, DNS adı çözümlenince IP’yi önbelleğe alır ve bağlantı aktif olduğu sürece tekrar sorgulamaz. Bu yüzden sadece DDNS kurmak yetmez, WireGuard’ın periyodik olarak DNS’i yeniden sorgulamasını da sağlamak gerekir.

Hangi DDNS Servisini Kullanmalısın?

Ücretsiz ve güvenilir seçenekler şunlardır:

  • DuckDNS: Kurulumu en basit olan, ücretsiz, duckdns.org alt alanı sağlar
  • No-IP: Ücretsiz planda 30 günde bir manuel doğrulama gerektirir, ücretli planı daha kullanışlıdır
  • Dynu: Ücretsiz planda kendi domain adını da kullanabilirsin
  • Cloudflare: Kendi domainin varsa en iyi seçenek, API üzerinden güncelleme çok temiz çalışır
  • FreeDNS (afraid.org): Eskiden beri kullanılan, güvenilir bir seçenek

Ben genellikle Cloudflare’i tercih ediyorum çünkü kendi domain adını kullanmak hem profesyonel görünüyor hem de servis değiştirdiğinde DNS kaydını yönlendirmen yeterli oluyor. Ama evde basit bir kurulum için DuckDNS fazlasıyla yeterli.

DuckDNS ile Temel Kurulum

Önce DuckDNS’e kayıt ol ve bir subdomain oluştur. Token’ını not et, her şeyde bu kullanılacak.

İstemci Tarafında DDNS Güncelleme Scripti

#!/bin/bash
# /usr/local/bin/ddns-update.sh

DOMAIN="evimvpn"
TOKEN="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
LOG_FILE="/var/log/ddns-update.log"

CURRENT_IP=$(curl -s https://api.ipify.org)
DDNS_RESPONSE=$(curl -s "https://www.duckdns.org/update?domains=${DOMAIN}&token=${TOKEN}&ip=${CURRENT_IP}")

echo "$(date '+%Y-%m-%d %H:%M:%S') | IP: ${CURRENT_IP} | Response: ${DDNS_RESPONSE}" >> "$LOG_FILE"

if [ "$DDNS_RESPONSE" = "OK" ]; then
    echo "DDNS guncellendi: ${CURRENT_IP}"
else
    echo "DDNS guncelleme basarisiz!" >&2
    exit 1
fi

Bu scripti çalıştırılabilir yap ve cron’a ekle:

chmod +x /usr/local/bin/ddns-update.sh

# Crontab'a ekle - her 5 dakikada bir kontrol et
crontab -e

Crontab içine şunu ekle:

*/5 * * * * /usr/local/bin/ddns-update.sh > /dev/null 2>&1

Cloudflare ile Daha Gelişmiş DDNS Kurulumu

Kendi domain’in varsa Cloudflare çok daha temiz bir çözüm sunar. Önce Cloudflare API token’ı oluşturman gerekiyor. Cloudflare panelinde Profile > API Tokens > Create Token > Edit zone DNS şablonunu kullan.

#!/bin/bash
# /usr/local/bin/cloudflare-ddns.sh

# Konfigürasyon
CF_API_TOKEN="your_cloudflare_api_token_here"
ZONE_ID="your_zone_id_here"
RECORD_NAME="vpn.example.com"
LOG_FILE="/var/log/cloudflare-ddns.log"

# Mevcut public IP'yi al
CURRENT_IP=$(curl -s https://api.ipify.org)

# DNS kaydinin ID'sini bul
RECORD_ID=$(curl -s -X GET 
    "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records?name=${RECORD_NAME}&type=A" 
    -H "Authorization: Bearer ${CF_API_TOKEN}" 
    -H "Content-Type: application/json" | 
    python3 -c "import sys,json; data=json.load(sys.stdin); print(data['result'][0]['id'])")

# DNS kaydini guncelle
UPDATE_RESULT=$(curl -s -X PUT 
    "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records/${RECORD_ID}" 
    -H "Authorization: Bearer ${CF_API_TOKEN}" 
    -H "Content-Type: application/json" 
    --data "{"type":"A","name":"${RECORD_NAME}","content":"${CURRENT_IP}","ttl":60,"proxied":false}")

SUCCESS=$(echo "$UPDATE_RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['success'])")

echo "$(date '+%Y-%m-%d %H:%M:%S') | IP: ${CURRENT_IP} | Success: ${SUCCESS}" >> "$LOG_FILE"

Burada önemli bir detay var: Cloudflare DNS proxy’sini (proxied: false) devre dışı bırakmalısın. WireGuard UDP kullandığı için Cloudflare’in HTTP proxy’si bu trafiği işleyemez, direkt IP’ye ihtiyaç var.

WireGuard Tarafında DNS Yenileme Sorunu ve Çözümü

WireGuard’ın DNS önbellekleme sorununu çözmek için birkaç yöntem var.

Yöntem 1: PostUp ile Periyodik Yenileme

WireGuard konfigürasyonuna PostUp ve PreDown hook’ları ekleyebilirsin:

# /etc/wireguard/wg0.conf (sunucu tarafı)
[Interface]
PrivateKey = server_private_key_here
Address = 10.10.0.1/24
ListenPort = 51820
PostUp = /usr/local/bin/wg-dns-refresh.sh start
PreDown = /usr/local/bin/wg-dns-refresh.sh stop

Buna karşılık gelen scripti de oluşturalım:

#!/bin/bash
# /usr/local/bin/wg-dns-refresh.sh

INTERFACE="wg0"
PEER_ENDPOINT="vpn.evim.duckdns.org"
PEER_PUBKEY="peer_public_key_here"
PIDFILE="/var/run/wg-dns-refresh.pid"

refresh_loop() {
    while true; do
        sleep 30
        # Hostname'i yeniden coz ve peer'i guncelle
        NEW_IP=$(dig +short "$PEER_ENDPOINT" | head -1)
        if [ -n "$NEW_IP" ]; then
            wg set "$INTERFACE" peer "$PEER_PUBKEY" endpoint "${NEW_IP}:51820"
        fi
    done
}

case "$1" in
    start)
        refresh_loop &
        echo $! > "$PIDFILE"
        ;;
    stop)
        if [ -f "$PIDFILE" ]; then
            kill "$(cat $PIDFILE)" 2>/dev/null
            rm -f "$PIDFILE"
        fi
        ;;
esac

Yöntem 2: systemd Timer ile Çözüm

Bu yöntem daha temiz ve systemd ekosistemiyle bütünleşik çalışır. İki dosya oluşturman gerekiyor:

# /etc/systemd/system/wg-dns-refresh.service
[Unit]
Description=WireGuard DNS Refresh
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/wg-peer-update.sh
# /etc/systemd/system/wg-dns-refresh.timer
[Unit]
Description=WireGuard DNS Refresh Timer
After=network.target

[Timer]
OnBootSec=2min
OnUnitActiveSec=30s
Persistent=true

[Install]
WantedBy=timers.target

Timer’ı aktif et:

systemctl daemon-reload
systemctl enable --now wg-dns-refresh.timer
systemctl status wg-dns-refresh.timer

Gerçek Dünya Senaryosu: Ev Ofis VPN Kurulumu

Şöyle bir senaryo düşün: Şirkette statik IP’li bir sunucu var, evde ise dinamik IP’li bir bağlantı. Evden şirket ağına VPN üzerinden bağlanmak istiyorsun.

Bu durumda WireGuard peer konfigürasyonu şöyle olur. Şirket sunucusunda:

# /etc/wireguard/wg0.conf (sirket sunucusu - statik IP)
[Interface]
PrivateKey = SERVER_PRIVATE_KEY
Address = 10.8.0.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PreDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
# Ev bilgisayari
PublicKey = HOME_CLIENT_PUBLIC_KEY
AllowedIPs = 10.8.0.2/32
# Ev peer'i icin endpoint belirtmiyoruz, o bize baglanacak

Ev bilgisayarında (dinamik IP):

# /etc/wireguard/wg0.conf (ev bilgisayari - dinamik IP)
[Interface]
PrivateKey = HOME_PRIVATE_KEY
Address = 10.8.0.2/24
DNS = 10.8.0.1

[Peer]
# Sirket sunucusu - statik IP veya hostname kullanabilirsin
PublicKey = SERVER_PUBLIC_KEY
Endpoint = sirket.example.com:51820
AllowedIPs = 10.8.0.0/24, 192.168.1.0/24
PersistentKeepalive = 25

Bu senaryoda ev bilgisayarının IP’si değişse bile sorun olmaz çünkü bağlantıyı başlatan ev bilgisayarıdır. Sunucu, bağlantı gelince yeni endpoint’i öğrenir.

Gerçek Dünya Senaryosu: İki Dinamik IP Arasında VPN

İşte asıl zorlayıcı senaryo bu: Her iki tarafın da dinamik IP’si var ve peer to peer bağlantı kurmak istiyorsun. Örneğin iki farklı şube ofisi, ikisi de dinamik IP kullanıyor.

Bu durumda her iki tarafın da DDNS kullanması ve WireGuard’ın her iki tarafı için de periyodik DNS yenileme mekanizması kurulması gerekir.

Her iki taraf için de DDNS scripti çalışıyor olacak. Şube A konfigürasyonu:

# /etc/wireguard/wg0.conf (Sube A)
[Interface]
PrivateKey = SUBE_A_PRIVATE_KEY
Address = 10.9.0.1/24
ListenPort = 51820
PostUp = systemctl start [email protected]

[Peer]
PublicKey = SUBE_B_PUBLIC_KEY
Endpoint = subeb.duckdns.org:51820
AllowedIPs = 10.9.0.2/32, 192.168.2.0/24
PersistentKeepalive = 30

Bu senaryoda PersistentKeepalive çok önemli. Bu parametre WireGuard’ın her 30 saniyede bir karşı tarafa boş bir paket göndermesini sağlar. Böylece NAT tabloları taze kalır ve her iki taraf da birbirinin güncel IP’sini öğrenir.

IP Değişim Tespiti ve Otomatik Yeniden Bağlanma

Sadece DDNS güncellemesi yetmez, WireGuard’ın IP değişimini fark edip bağlantıyı yenilemesi de gerekir. Bunun için daha akıllı bir script yazalım:

#!/bin/bash
# /usr/local/bin/wg-smart-reconnect.sh

INTERFACE="wg0"
CONFIG_FILE="/etc/wireguard/wg0.conf"
STATE_FILE="/var/run/wg-last-ip"
LOG="/var/log/wg-reconnect.log"

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG"
}

# Her peer icin endpoint hostname'lerini bul ve coz
while IFS= read -r line; do
    if [[ $line =~ ^Endpoint = (.+):([0-9]+)$ ]]; then
        HOSTNAME="${BASH_REMATCH[1]}"
        PORT="${BASH_REMATCH[2]}"
        
        # IP mi hostname mi kontrol et
        if ! [[ $HOSTNAME =~ ^[0-9]+.[0-9]+.[0-9]+.[0-9]+$ ]]; then
            RESOLVED_IP=$(dig +short "$HOSTNAME" | grep -E '^[0-9]+.[0-9]+.[0-9]+.[0-9]+$' | head -1)
            
            if [ -z "$RESOLVED_IP" ]; then
                log "DNS cozumlemesi basarisiz: $HOSTNAME"
                continue
            fi
            
            # Onceki IP ile karsilastir
            PREV_IP=$(cat "${STATE_FILE}.${HOSTNAME}" 2>/dev/null)
            
            if [ "$RESOLVED_IP" != "$PREV_IP" ]; then
                log "IP degisimi tespit edildi: $HOSTNAME $PREV_IP -> $RESOLVED_IP"
                
                # WireGuard peer'ini guncelle
                PUBKEY=$(grep -A5 "Endpoint = ${HOSTNAME}:${PORT}" "$CONFIG_FILE" | grep "PublicKey" | awk '{print $3}')
                
                if [ -n "$PUBKEY" ]; then
                    wg set "$INTERFACE" peer "$PUBKEY" endpoint "${RESOLVED_IP}:${PORT}"
                    log "Peer guncellendi: $PUBKEY -> ${RESOLVED_IP}:${PORT}"
                fi
                
                echo "$RESOLVED_IP" > "${STATE_FILE}.${HOSTNAME}"
            fi
        fi
    fi
done < "$CONFIG_FILE"

Bu script her çalıştığında konfigürasyon dosyasındaki tüm hostname’leri çözümler, önceki IP ile karşılaştırır ve değişim varsa WireGuard peer’ini günceller.

Monitoring ve Alert Kurulumu

Bağlantı sorunlarını önceden fark etmek için basit bir monitoring scripti şart:

#!/bin/bash
# /usr/local/bin/wg-monitor.sh

INTERFACE="wg0"
PEER_PUBKEY="peer_public_key_here"
PING_TARGET="10.8.0.2"
ALERT_EMAIL="[email protected]"
FAILURE_COUNT_FILE="/var/run/wg-failure-count"
MAX_FAILURES=3

# Ping testi
if ! ping -c 3 -W 5 "$PING_TARGET" > /dev/null 2>&1; then
    FAILURES=$(cat "$FAILURE_COUNT_FILE" 2>/dev/null || echo 0)
    FAILURES=$((FAILURES + 1))
    echo "$FAILURES" > "$FAILURE_COUNT_FILE"
    
    if [ "$FAILURES" -ge "$MAX_FAILURES" ]; then
        # Alert gonder
        echo "WireGuard baglantisi koptu! Interface: $INTERFACE, Peer: $PEER_PUBKEY" | 
            mail -s "WireGuard Alert: Baglanti Sorunu" "$ALERT_EMAIL"
        
        # Yeniden baglantı dene
        wg-quick down "$INTERFACE" && sleep 5 && wg-quick up "$INTERFACE"
        
        # Sayaci sifirla
        echo "0" > "$FAILURE_COUNT_FILE"
    fi
else
    echo "0" > "$FAILURE_COUNT_FILE"
fi

# WireGuard durum bilgisi
LAST_HANDSHAKE=$(wg show "$INTERFACE" latest-handshakes | grep "$PEER_PUBKEY" | awk '{print $2}')
CURRENT_TIME=$(date +%s)

if [ -n "$LAST_HANDSHAKE" ] && [ "$LAST_HANDSHAKE" -gt 0 ]; then
    TIME_DIFF=$((CURRENT_TIME - LAST_HANDSHAKE))
    
    # Son el sikisma 3 dakikadan eskiyse uyar
    if [ "$TIME_DIFF" -gt 180 ]; then
        echo "Uyari: Son handshake ${TIME_DIFF} saniye once. Interface: $INTERFACE"
    fi
fi

Sık Karşılaşılan Sorunlar ve Çözümleri

Sorun: DNS değişiyor ama WireGuard bağlanamıyor

WireGuard çözümlediği IP’yi kernel içinde tutar ve wg komutuyla güncellenmesi gerekir. Sadece konfigürasyon dosyasını değiştirip systemctl restart wg-quick@wg0 yapmak bazen yetmez çünkü değişikliklerin kernel’e yazılması gerekir.

Doğru yöntem:

# Interface'i tamamen yeniden baslat
wg-quick down wg0 && wg-quick up wg0

# Ya da sadece peer endpoint'ini guncelle
wg set wg0 peer PUBKEY endpoint YeniIP:51820

Sorun: DDNS güncellemesi çalışıyor ama eski IP’ye bağlanıyor

DNS TTL süresini düşür. DuckDNS varsayılan olarak 60 saniye TTL kullanır, bu genellikle yeterlidir. Cloudflare’de ise minimum TTL 60 saniyedir, bunu kullan.

Sisteminizde DNS önbelleğini kontrol et:

# systemd-resolved kullanan sistemlerde cache temizle
systemd-resolve --flush-caches
systemd-resolve --statistics

# Belirli bir hostname'in nasıl cozumlendigini gör
dig +short vpn.evim.duckdns.org
resolvectl query vpn.evim.duckdns.org

Sorun: PersistentKeepalive değeri ne olmalı?

Çoğu NAT ortamında UDP oturumları 30-60 saniye sonra düşer. PersistentKeepalive değerini 25 saniye olarak ayarlamak genellikle iyi bir başlangıç noktasıdır. Mobil bağlantılarda veya agresif NAT yapılarında 15 saniyeye düşürmek gerekebilir.

Güvenlik Notları

Dinamik DNS kullanırken göz ardı edilmemesi gereken birkaç güvenlik konusu var:

  • API token güvenliği: DDNS güncelleme scriptlerindeki API token’larını konfigürasyon dosyasında saklayın, script içine gömmeyin. /etc/ddns.conf gibi bir dosya oluşturun ve sadece root okuyabilsin.
  • Script izinleri: DDNS scriptleri root çalıştığı için 700 izni olmalı ve root’a ait olmalı.
  • DDNS hostname’ini tahmin ettirme: vpn.adsoyadim.duckdns.org gibi kolayca tahmin edilebilir hostname’ler port taramasına davet çıkarır. Rastgele karakter ekle.
  • Fail2ban: WireGuard UDP üzerinde çalışır ve doğrudan fail2ban ile korunamaz, ama sunucunuzda diğer servislerin güvenliğini sağlayın.

Sonuç

WireGuard ile dinamik DNS’i doğru entegre etmek birkaç katmanlı bir çözüm gerektiriyor: DDNS güncelleme mekanizması, WireGuard tarafında periyodik DNS yenileme ve bağlantı monitoring. Bu üç bileşeni birlikte kurduğunda dinamik IP’li bir ortamda bile WireGuard bağlantın stabil kalır.

Önerim şu: Önce en basit senaryoyla başla. Tek taraf dinamik IP ise sadece DDNS scripti ve systemd timer yeterli. İki taraf da dinamikse akıllı yeniden bağlanma scriptini ve PersistentKeepalive’ı devreye al. Her değişiklikten sonra günlükleri izle, bağlantı kopma sürelerini kaydet ve bu verilere göre timer aralıklarını ayarla.

Dinamik IP ortamlarında sıfır kesinti garanti edilemez, ama doğru araçlarla kesinti sürelerini dakikalardan saniyelere indirebilirsin. Bu da pratikte neredeyse kesintisiz bir VPN bağlantısı anlamına gelir.

Yorum yapın