VPN altyapınızı kurdunuz, kullanıcılar bağlanıyor, tünel çalışıyor. Peki kim ne kadar bant genişliği kullanıyor? Hangi saat diliminde trafik zirvesi yaşanıyor? Bir kullanıcı aniden 50GB veri indirirse bunu fark edebiliyor musunuz? Bu sorulara cevap veremiyorsanız, OpenVPN kurulumunuz yarım kalmış demektir.
Bant genişliği izleme, sysadmin işinin en çok ertelenen ama en kritik parçalarından biridir. “Şimdilik çalışıyor” mantığıyla kurulan sistemler, kapasite planlaması yapılmadığı için bir gün aniden çöker ya da faturalar patlar. Bu yazıda OpenVPN ortamında bant genişliği izlemeyi ve raporlamayı uçtan uca ele alacağız.
OpenVPN’in Yerleşik İstatistik Mekanizması
OpenVPN, kurulu geldiğinde bile temel istatistik bilgilerini sunabiliyor. Ancak bu mekanizmayı aktif hale getirmek gerekiyor.
Status Dosyası ile Anlık İzleme
/etc/openvpn/server.conf dosyanıza şu satırları ekleyin:
status /var/log/openvpn/openvpn-status.log 30
status-version 2
log-append /var/log/openvpn/openvpn.log
verb 3
Burada status direktifi 30 saniyede bir /var/log/openvpn/openvpn-status.log dosyasını güncelliyor. status-version 2 ile daha ayrıntılı çıktı alıyoruz.
Servis yeniden başlatıldıktan sonra status dosyasına bakın:
sudo systemctl restart openvpn@server
cat /var/log/openvpn/openvpn-status.log
Çıktı şuna benzer bir şey gösterecek:
TITLE,OpenVPN 2.5.9 x86_64-pc-linux-gnu
TIME,2024-01-15 14:23:11,1705321391
HEADER,CLIENT_LIST,Common Name,Real Address,Virtual Address,Virtual IPv6 Address,Bytes Received,Bytes Sent,Connected Since,Connected Since (time_t),Username,Client ID,Peer ID
CLIENT_LIST,ahmet.yilmaz,192.168.1.45:51234,10.8.0.2,,1048576,2097152,2024-01-15 13:00:00,1705316400,ahmet.yilmaz,1,0
CLIENT_LIST,mehmet.kaya,85.24.33.12:44821,10.8.0.6,,524288,1048576,2024-01-15 14:10:00,1705320600,mehmet.kaya,2,1
HEADER,ROUTING_TABLE,Virtual Address,Common Name,Real Address,Last Ref,Last Ref (time_t)
ROUTING_TABLE,10.8.0.2,ahmet.yilmaz,192.168.1.45:51234,2024-01-15 14:23:05,1705321385
GLOBAL_STATS,Max bcast/mcast queue length,0
END
Bu dosyayı parse eden basit bir bash scripti yazalım:
#!/bin/bash
# /usr/local/bin/vpn-bandwidth-check.sh
STATUS_FILE="/var/log/openvpn/openvpn-status.log"
LOG_FILE="/var/log/openvpn/bandwidth-history.csv"
# CSV başlığı yoksa oluştur
if [ ! -f "$LOG_FILE" ]; then
echo "timestamp,username,real_ip,virtual_ip,bytes_received,bytes_sent,connected_since" > "$LOG_FILE"
fi
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
grep "^CLIENT_LIST," "$STATUS_FILE" | while IFS=',' read -r header cn real_addr virt_addr virt_ipv6 bytes_rx bytes_tx connected_since rest; do
echo "$TIMESTAMP,$cn,$real_addr,$virt_addr,$bytes_rx,$bytes_tx,$connected_since" >> "$LOG_FILE"
done
echo "[$TIMESTAMP] Bandwidth snapshot alindi." >> /var/log/openvpn/vpn-monitor.log
Bu scripti her 5 dakikada bir çalıştırmak için cron’a ekleyin:
chmod +x /usr/local/bin/vpn-bandwidth-check.sh
crontab -e
# Şu satırı ekleyin:
# */5 * * * * /usr/local/bin/vpn-bandwidth-check.sh
Management Interface ile Gerçek Zamanlı İzleme
OpenVPN’in management arayüzü, anlık veri almak için çok daha güçlü bir yöntem. Önce server.conf dosyasına management direktifini ekleyelim:
management 127.0.0.1 7505
management-hold
Güvenlik açısından management arayüzünü sadece localhost’a bağlamak kritik. Şimdi telnet ya da netcat ile bağlanıp anlık veri çekelim:
# Bağlantı testi
echo "status 2" | nc -q 1 127.0.0.1 7505
# Daha kullanışlı bir komut:
(echo "status 2"; sleep 1; echo "quit") | nc 127.0.0.1 7505
Bu management interface’i kullanan bir Python scripti çok daha işlevsel olacak:
#!/usr/bin/env python3
# /usr/local/bin/vpn_monitor.py
import socket
import time
import json
import datetime
import os
MGMT_HOST = '127.0.0.1'
MGMT_PORT = 7505
OUTPUT_JSON = '/var/log/openvpn/vpn_stats.json'
def get_vpn_status():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((MGMT_HOST, MGMT_PORT))
s.settimeout(5)
# Karşılama mesajını oku
data = b""
while True:
try:
chunk = s.recv(4096)
if not chunk:
break
data += chunk
if b">" in chunk:
break
except socket.timeout:
break
# Status komutunu gönder
s.send(b"status 2n")
time.sleep(0.5)
response = b""
while True:
try:
chunk = s.recv(4096)
if not chunk:
break
response += chunk
if b"END" in chunk:
break
except socket.timeout:
break
s.send(b"quitn")
s.close()
return parse_status(response.decode('utf-8', errors='replace'))
except Exception as e:
print(f"Hata: {e}")
return None
def parse_status(raw):
clients = []
lines = raw.strip().split('n')
for line in lines:
if line.startswith('CLIENT_LIST,'):
parts = line.split(',')
if len(parts) >= 9:
client = {
'username': parts[1],
'real_address': parts[2],
'virtual_address': parts[3],
'bytes_received': int(parts[5]) if parts[5].isdigit() else 0,
'bytes_sent': int(parts[6]) if parts[6].isdigit() else 0,
'connected_since': parts[7],
'bytes_received_mb': round(int(parts[5]) / 1024 / 1024, 2) if parts[5].isdigit() else 0,
'bytes_sent_mb': round(int(parts[6]) / 1024 / 1024, 2) if parts[6].isdigit() else 0,
}
clients.append(client)
return {
'timestamp': datetime.datetime.now().isoformat(),
'active_clients': len(clients),
'clients': clients,
'total_rx_mb': round(sum(c['bytes_received_mb'] for c in clients), 2),
'total_tx_mb': round(sum(c['bytes_sent_mb'] for c in clients), 2),
}
if __name__ == '__main__':
stats = get_vpn_status()
if stats:
with open(OUTPUT_JSON, 'w') as f:
json.dump(stats, f, indent=2, ensure_ascii=False)
print(json.dumps(stats, indent=2, ensure_ascii=False))
else:
print("VPN istatistikleri alinamadi.")
Scripti çalıştırıp test edin:
chmod +x /usr/local/bin/vpn_monitor.py
python3 /usr/local/bin/vpn_monitor.py
iftop ve vnstat ile Arayüz Bazlı İzleme
OpenVPN tüneli bir ağ arayüzü olarak görünür (tun0 ya da tun1 gibi). Bu arayüzü doğrudan izlemek çok değerli veriler verir.
vnstat ile kalıcı bant genişliği kaydı tutmak için:
# vnstat kurulumu
apt install vnstat -y # Debian/Ubuntu
yum install vnstat -y # CentOS/RHEL
# tun0 arayüzünü izlemeye başla
vnstat -i tun0 --add
systemctl restart vnstat
# Günlük rapor
vnstat -i tun0 -d
# Saatlik rapor
vnstat -i tun0 -h
# Aylık özet
vnstat -i tun0 -m
# Canlı trafik izleme
vnstat -i tun0 -l
vnstat verilerini bir bash scriptiyle günlük e-posta raporuna çevirebilirsiniz:
#!/bin/bash
# /usr/local/bin/vpn-daily-report.sh
REPORT_DATE=$(date '+%Y-%m-%d')
REPORT_FILE="/tmp/vpn-report-${REPORT_DATE}.txt"
ADMIN_MAIL="[email protected]"
VPN_IFACE="tun0"
cat > "$REPORT_FILE" << EOF
OpenVPN Gunluk Bant Genisligi Raporu
Tarih: $REPORT_DATE
Sunucu: $(hostname)
======================================
=== ARAYUZ ISTATISTIKLERI (vnstat) ===
$(vnstat -i $VPN_IFACE -d 2>/dev/null || echo "vnstat verisi bulunamadi")
=== AKTIF KULLANICILAR ===
$(cat /var/log/openvpn/vpn_stats.json 2>/dev/null | python3 -c "
import json, sys
try:
data = json.load(sys.stdin)
print(f'Aktif kullanici sayisi: {data["active_clients"]}')
print(f'Toplam indirilen: {data["total_rx_mb"]} MB')
print(f'Toplam yuklenen: {data["total_tx_mb"]} MB')
print()
for c in data['clients']:
print(f' {c["username"]:30} IN: {c["bytes_received_mb"]:8.2f} MB OUT: {c["bytes_sent_mb"]:8.2f} MB')
except:
print('JSON parse hatasi')
")
=== SON 24 SAAT LOG OZETI ===
Toplam baglanti sayisi: $(grep "$(date '+%Y-%m-%d')" /var/log/openvpn/openvpn.log 2>/dev/null | grep -c "Peer Connection Initiated" || echo "0")
Basarili kimlik dogrulama: $(grep "$(date '+%Y-%m-%d')" /var/log/openvpn/openvpn.log 2>/dev/null | grep -c "Authenticated" || echo "0")
EOF
# Mail gönder (mailutils kurulu olmalı)
if command -v mail &> /dev/null; then
mail -s "OpenVPN Gunluk Raporu - $REPORT_DATE" "$ADMIN_MAIL" < "$REPORT_FILE"
echo "Rapor gonderildi: $ADMIN_MAIL"
else
cat "$REPORT_FILE"
fi
# Raporu arşivle
cp "$REPORT_FILE" "/var/log/openvpn/reports/"
Kullanıcı Bazlı Kota Sistemi Kurma
Gerçek dünyada bir müşterinin ya da çalışanın bant genişliğini sınırlamak gerekebilir. OpenVPN’in kendi kota sistemi yok ama bu işi script ve tc (traffic control) ile halledebiliriz.
#!/bin/bash
# /usr/local/bin/vpn-quota-check.sh
# Bu script client-connect hook olarak çalışır
# OpenVPN client-connect script'i için server.conf'a ekleyin:
# script-security 2
# client-connect /usr/local/bin/vpn-quota-check.sh
USERNAME="$common_name"
QUOTA_FILE="/etc/openvpn/quotas/${USERNAME}.quota"
USAGE_FILE="/var/log/openvpn/usage/${USERNAME}.usage"
MONTHLY_LIMIT_GB=50 # Varsayılan limit: 50GB
# Kullanıcıya özel limit varsa oku
if [ -f "$QUOTA_FILE" ]; then
MONTHLY_LIMIT_GB=$(cat "$QUOTA_FILE")
fi
# Bu ayın kullanımını hesapla
CURRENT_MONTH=$(date '+%Y-%m')
CURRENT_USAGE_GB=0
if [ -f "$USAGE_FILE" ]; then
CURRENT_USAGE_GB=$(grep "^$CURRENT_MONTH" "$USAGE_FILE" | awk -F',' '{sum += $2} END {print sum/1024/1024/1024}')
fi
# Kota kontrolü
if (( $(echo "$CURRENT_USAGE_GB >= $MONTHLY_LIMIT_GB" | bc -l) )); then
echo "KOTA ASIMI: $USERNAME kullanicisi $MONTHLY_LIMIT_GB GB limitini asti. Baglanti reddediliyor."
>> /var/log/openvpn/quota-violations.log
exit 1 # Bağlantıyı reddet
fi
echo "Baglanti izni verildi: $USERNAME (Kullanim: ${CURRENT_USAGE_GB}GB / ${MONTHLY_LIMIT_GB}GB)"
>> /var/log/openvpn/quota-check.log
exit 0
Kota dizinlerini hazırlayın:
mkdir -p /etc/openvpn/quotas
mkdir -p /var/log/openvpn/usage
mkdir -p /var/log/openvpn/reports
# Örnek kullanıcı kotası (20GB limit)
echo "20" > /etc/openvpn/quotas/ahmet.yilmaz.quota
Grafana ve InfluxDB ile Görsel Dashboard
Sayıları ekrana basmak yetmez, görsel dashboard olmadan uzun vadeli trend analizi yapılamaz. InfluxDB ve Grafana kombinasyonu bu iş için biçilmiş kaftan.
Önce InfluxDB’ye veri gönderen bir script yazalım:
#!/bin/bash
# /usr/local/bin/vpn-metrics-to-influx.sh
INFLUX_URL="http://localhost:8086"
INFLUX_DB="openvpn_metrics"
INFLUX_TOKEN="your-influxdb-token-here" # InfluxDB v2 için
STATUS_FILE="/var/log/openvpn/openvpn-status.log"
TIMESTAMP=$(date +%s%N)
# InfluxDB v2 kullanıyorsanız:
send_metric() {
local measurement=$1
local tags=$2
local fields=$3
curl -s -X POST
"${INFLUX_URL}/api/v2/write?org=myorg&bucket=${INFLUX_DB}&precision=ns"
-H "Authorization: Token ${INFLUX_TOKEN}"
-H "Content-Type: text/plain; charset=utf-8"
--data-binary "${measurement},${tags} ${fields} ${TIMESTAMP}"
}
# Aktif bağlantı sayısı
ACTIVE_CLIENTS=$(grep -c "^CLIENT_LIST," "$STATUS_FILE" 2>/dev/null || echo "0")
send_metric "vpn_connections" "server=vpn01" "active_clients=${ACTIVE_CLIENTS}i"
# Kullanıcı bazlı metrikler
grep "^CLIENT_LIST," "$STATUS_FILE" | while IFS=',' read -r header cn real_addr virt_addr virt_ipv6 bytes_rx bytes_tx rest; do
CLEAN_CN=$(echo "$cn" | tr -d ' ' | tr '.' '_')
send_metric "vpn_user_bandwidth"
"server=vpn01,username=${CLEAN_CN}"
"bytes_received=${bytes_rx}i,bytes_sent=${bytes_tx}i"
done
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Metrikler InfluxDB'ye gonderildi." >> /var/log/openvpn/metrics.log
Bu scripti cron’a ekleyin:
*/1 * * * * /usr/local/bin/vpn-metrics-to-influx.sh
Grafana tarafında InfluxDB datasource ekledikten sonra şu sorgu ile dashboard oluşturabilirsiniz:
from(bucket: "openvpn_metrics")
|> range(start: -24h)
|> filter(fn: (r) => r._measurement == "vpn_user_bandwidth")
|> filter(fn: (r) => r._field == "bytes_received" or r._field == "bytes_sent")
|> aggregateWindow(every: 5m, fn: mean)
|> yield(name: "mean")
Otomatik Uyarı Sistemi
Bant genişliği eşiklerini aştığında otomatik uyarı almak için şu scripti kullanabilirsiniz:
#!/bin/bash
# /usr/local/bin/vpn-alert-check.sh
STATS_JSON="/var/log/openvpn/vpn_stats.json"
ALERT_LOG="/var/log/openvpn/alerts.log"
ADMIN_MAIL="[email protected]"
SLACK_WEBHOOK="https://hooks.slack.com/services/XXXX/YYYY/ZZZZ"
# Eşik değerleri
MAX_SINGLE_USER_MB=1024 # Tek kullanıcı için 1GB/bağlantı uyarısı
MAX_TOTAL_MB=10240 # Toplam 10GB uyarısı
MAX_CONCURRENT_USERS=50 # Maksimum eşzamanlı kullanıcı
send_slack_alert() {
local message=$1
curl -s -X POST -H 'Content-type: application/json'
--data "{"text":"*VPN UYARISI*: ${message}"}"
"$SLACK_WEBHOOK" > /dev/null 2>&1
}
send_email_alert() {
local subject=$1
local body=$2
echo "$body" | mail -s "$subject" "$ADMIN_MAIL" 2>/dev/null
}
if [ ! -f "$STATS_JSON" ]; then
echo "Stats dosyasi bulunamadi: $STATS_JSON" >&2
exit 1
fi
# Python ile JSON analizi
python3 << PYEOF
import json, sys, subprocess
from datetime import datetime
with open('$STATS_JSON', 'r') as f:
data = json.load(f)
alerts = []
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# Eşzamanlı kullanıcı kontrolü
if data['active_clients'] > $MAX_CONCURRENT_USERS:
msg = f"Cok fazla esit zamanli kullanici: {data['active_clients']} (Limit: $MAX_CONCURRENT_USERS)"
alerts.append(msg)
# Toplam bant genişliği kontrolü
if data['total_rx_mb'] > $MAX_TOTAL_MB:
msg = f"Toplam indirme limiti asildi: {data['total_rx_mb']} MB (Limit: $MAX_TOTAL_MB MB)"
alerts.append(msg)
# Kullanıcı bazlı kontrol
for client in data['clients']:
if client['bytes_received_mb'] > $MAX_SINGLE_USER_MB:
msg = f"Yuksek kullanim: {client['username']} - {client['bytes_received_mb']} MB indirdi (IP: {client['real_address']})"
alerts.append(msg)
if alerts:
for alert in alerts:
print(f"[{timestamp}] UYARI: {alert}")
with open('$ALERT_LOG', 'a') as log:
log.write(f"[{timestamp}] {alert}n")
subprocess.run(['bash', '-c', f'/usr/local/bin/vpn-alert-check.sh slack_notify "{alert}"'])
else:
print(f"[{timestamp}] Tum kontroller normal.")
sys.exit(1 if alerts else 0)
PYEOF
Logrotate ile Log Yönetimi
Bu kadar log üretince bunları yönetmek de önemli hale geliyor:
# /etc/logrotate.d/openvpn-custom
/var/log/openvpn/bandwidth-history.csv
/var/log/openvpn/vpn_stats.json
/var/log/openvpn/alerts.log
/var/log/openvpn/metrics.log {
daily
rotate 90
compress
delaycompress
missingok
notifempty
dateext
dateformat -%Y%m%d
postrotate
systemctl reload openvpn@server > /dev/null 2>&1 || true
endscript
}
Gerçek Dünya Senaryosu: Kurumsal Ortamda Kota Uyarısı
Bir yazılım şirketinde, 30 remote çalışan var ve hepsi ofis VPN’i üzerinden iç sistemlere bağlanıyor. Aylık 1TB bant genişliği limitiniz var ve ay sonuna 5 gün kala 900GB’a ulaştınız. Bu durumda ne yaparsınız?
Önce kim ne kullanmış bakalım:
# Son 30 günün CSV'sinden en çok tüketen kullanıcıları bul
awk -F',' '
NR>1 {
users[$2] += ($5 + $6)
}
END {
for (u in users) {
printf "%.2f GBt%sn", users[u]/1024/1024/1024, u
}
}
' /var/log/openvpn/bandwidth-history.csv | sort -rn | head -10
Bu komutun çıktısı size doğrudan “şüpheli” kullanıcıları gösterecek. Belki birisi backup scriptini VPN üzerinden çalıştırıyor, belki biri video stream yapıyor. Veriyi gördükten sonra ilgili kişiyle konuşmak ya da split tunneling politikasını gözden geçirmek çok daha kolay.
Split tunneling konfigürasyonunu server.conf üzerinde kontrol altına alarak yalnızca iç ağ trafiğinin VPN’den geçmesini sağlayabilirsiniz:
# server.conf - Sadece iç ağ trafiğini VPN'e yönlendir
push "route 10.0.0.0 255.255.0.0"
push "route 172.16.0.0 255.255.0.0"
# push "redirect-gateway def1" satırını KALDIRIN veya yorum yapın
Bu değişiklik tek başına bant genişliği kullanımını dramatik biçimde düşürebilir.
Sonuç
OpenVPN bant genişliği izleme, “kurar ve unutursun” değil aktif yönetim gerektiren bir konu. Status dosyasıyla başlayıp management interface’e geçmek, oradan InfluxDB ve Grafana ile görselleştirmeye ulaşmak kademeli bir süreç. Her şeyi bir gecede kurmaya çalışmayın.
En az yapmanız gerekenler şunlar: status dosyasını aktifleştirin, 5 dakikada bir snapshot alan scripti cron’a ekleyin, vnstat ile arayüz bazlı günlük takibi başlatın. Bu üç adım bile sizi “kör uçuş” durumundan kurtarır.
Orta vadede management interface üzerinden Python scriptiyle JSON çıktısı almak ve bunu Grafana’ya beslemek en iyi yatırım. Bir kez kurduğunuzda tüm VPN trafiğini cam arkasından izler gibi görmeye başlarsınız. Kapasite planlaması, kullanıcı bazlı sorun tespiti ve güvenlik analizlerini veriye dayalı yapabilmek, sysadmin’i reaktif değil proaktif kılar. Bu fark, sabah 3’te telefon çalıp çalmaması arasındaki farktır.