hetzner-ddns-update.py
· 1.9 KiB · Python
Raw
import requests
import logging
from datetime import datetime
from hcloud import Client
from hcloud.zones.domain import ZoneRecord
# --- KONFIGURATION ---
TOKEN = "DEIN_HETZNER_API_TOKEN"
DOMAIN = "domain.de"
SUBDOMAINS = ["forms", "api", "cloud"] # Hier einfach erweitern
LOG_FILE = "/home/ddns_update.log"
# --- LOGGING SETUP ---
logging.basicConfig(
filename=LOG_FILE,
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
def update_ddns():
try:
client = Client(token=TOKEN)
# 1. Aktuelle öffentliche IP abrufen
try:
current_ip = requests.get('https://api.ipify.org', timeout=10).text.strip()
except Exception as e:
logging.error(f"Konnte öffentliche IP nicht abrufen: {e}")
return
# 2. Zone laden
zone = client.zones.get(DOMAIN)
# 3. Alle Subdomains durchgehen
for sub in SUBDOMAINS:
try:
rrset = client.zones.get_rrset(zone, name=sub, type="A")
existing_ip = rrset.records[0].value if rrset.records else None
if current_ip != existing_ip:
client.zones.set_rrset_records(rrset, records=[ZoneRecord(value=current_ip)])
logging.info(f"UPDATE: {sub}.{DOMAIN} von {existing_ip} auf {current_ip} geändert.")
else:
# Optional: Loggen, dass alles okay ist (kann man auch weglassen, um Log klein zu halten)
logging.info(f"OK: {sub}.{DOMAIN} ist aktuell ({current_ip}).")
except Exception as e:
logging.error(f"Fehler bei Subdomain {sub}: {e}")
except Exception as e:
logging.critical(f"Kritischer Fehler im Hauptprozess: {e}")
if __name__ == "__main__":
update_ddns()
| 1 | import requests |
| 2 | import logging |
| 3 | from datetime import datetime |
| 4 | from hcloud import Client |
| 5 | from hcloud.zones.domain import ZoneRecord |
| 6 | |
| 7 | # --- KONFIGURATION --- |
| 8 | TOKEN = "DEIN_HETZNER_API_TOKEN" |
| 9 | DOMAIN = "domain.de" |
| 10 | SUBDOMAINS = ["forms", "api", "cloud"] # Hier einfach erweitern |
| 11 | LOG_FILE = "/home/ddns_update.log" |
| 12 | |
| 13 | # --- LOGGING SETUP --- |
| 14 | logging.basicConfig( |
| 15 | filename=LOG_FILE, |
| 16 | level=logging.INFO, |
| 17 | format='%(asctime)s - %(levelname)s - %(message)s', |
| 18 | datefmt='%Y-%m-%d %H:%M:%S' |
| 19 | ) |
| 20 | |
| 21 | def update_ddns(): |
| 22 | try: |
| 23 | client = Client(token=TOKEN) |
| 24 | |
| 25 | # 1. Aktuelle öffentliche IP abrufen |
| 26 | try: |
| 27 | current_ip = requests.get('https://api.ipify.org', timeout=10).text.strip() |
| 28 | except Exception as e: |
| 29 | logging.error(f"Konnte öffentliche IP nicht abrufen: {e}") |
| 30 | return |
| 31 | |
| 32 | # 2. Zone laden |
| 33 | zone = client.zones.get(DOMAIN) |
| 34 | |
| 35 | # 3. Alle Subdomains durchgehen |
| 36 | for sub in SUBDOMAINS: |
| 37 | try: |
| 38 | rrset = client.zones.get_rrset(zone, name=sub, type="A") |
| 39 | existing_ip = rrset.records[0].value if rrset.records else None |
| 40 | |
| 41 | if current_ip != existing_ip: |
| 42 | client.zones.set_rrset_records(rrset, records=[ZoneRecord(value=current_ip)]) |
| 43 | logging.info(f"UPDATE: {sub}.{DOMAIN} von {existing_ip} auf {current_ip} geändert.") |
| 44 | else: |
| 45 | # Optional: Loggen, dass alles okay ist (kann man auch weglassen, um Log klein zu halten) |
| 46 | logging.info(f"OK: {sub}.{DOMAIN} ist aktuell ({current_ip}).") |
| 47 | |
| 48 | except Exception as e: |
| 49 | logging.error(f"Fehler bei Subdomain {sub}: {e}") |
| 50 | |
| 51 | except Exception as e: |
| 52 | logging.critical(f"Kritischer Fehler im Hauptprozess: {e}") |
| 53 | |
| 54 | if __name__ == "__main__": |
| 55 | update_ddns() |