This commit is contained in:
2025-12-21 00:38:19 +01:00
parent 768c1cb355
commit d2dbdd8567
4 changed files with 123 additions and 0 deletions

15
dockerfile Normal file
View File

@@ -0,0 +1,15 @@
FROM python:3.11-slim
WORKDIR /app
# Abhängigkeiten installieren
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Skript kopieren
COPY main.py .
# Environment Variable für unbuffered Output (wichtig für Docker Logs)
ENV PYTHONUNBUFFERED=1
CMD ["python", "main.py"]

24
dyndns.yaml Normal file
View File

@@ -0,0 +1,24 @@
version: '3.8'
services:
ovh-dyndns:
image: deinuser/ovh-dyndns:latest
deploy:
mode: replicated
replicas: 1
environment:
- OVH_APPLICATION_KEY=a5a8c4d9ca922385
- OVH_APPLICATION_SECRET=00cae21017265da8a6d0d6df0b6b2dfb
- OVH_CONSUMER_KEY=181952cb55cc3ed2d1e39d45b96263a6
# Die Hauptdomain (Zone)
- DOMAIN=alehn.de
# HIER DIE LISTE EINTRAGEN:
# "www" -> www.deinedomain.de
# "vpn" -> vpn.deinedomain.de
# "@" -> deinedomain.de (ohne www, die Hauptdomain selbst)
- SUBDOMAINS= nextcloud, bitwarden, portainer, traefik, gittea
# Check alle 5 Minuten
- INTERVAL=300

82
main.py Normal file
View File

@@ -0,0 +1,82 @@
import os
import time
import ovh
import requests
from datetime import datetime
# --- Konfiguration ---
AK = os.getenv('OVH_APPLICATION_KEY')
AS = os.getenv('OVH_APPLICATION_SECRET')
CK = os.getenv('OVH_CONSUMER_KEY')
DOMAIN = os.getenv('DOMAIN') # Die Hauptdomain, z.B. "meine-domain.de"
INTERVAL = int(os.getenv('INTERVAL', 300))
# Subdomains auslesen und Liste erstellen
# Beispiel Input: "www, vpn, cloud, @"
raw_subs = os.getenv('SUBDOMAINS', '')
SUBDOMAINS = [s.strip() for s in raw_subs.split(',') if s.strip()]
def log(message):
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {message}", flush=True)
def get_public_ip():
try:
return requests.get('https://api.ipify.org', timeout=10).text
except Exception as e:
log(f"Fehler beim Abrufen der IP: {e}")
return None
def update_ovh_dns(current_ip):
client = ovh.Client(endpoint='ovh-eu', application_key=AK, application_secret=AS, consumer_key=CK)
if not SUBDOMAINS:
log("WARNUNG: Keine Subdomains in der Liste 'SUBDOMAINS' gefunden.")
return
for sub in SUBDOMAINS:
# OVH Logik: Leerer String = Root Domain. Wir nutzen '@' als Platzhalter für User-Freundlichkeit
sub_for_api = '' if sub == '@' else sub
fqdn = f"{sub}.{DOMAIN}" if sub != '@' else DOMAIN
try:
# 1. Record ID suchen
records = client.get(f'/domain/zone/{DOMAIN}/record',
fieldType='A',
subDomain=sub_for_api)
if not records:
log(f"Übersprungen: Kein A-Record für '{fqdn}' gefunden.")
continue
for record_id in records:
# 2. Details prüfen
record_details = client.get(f'/domain/zone/{DOMAIN}/record/{record_id}')
if record_details['target'] == current_ip:
log(f"OK: {fqdn} ist aktuell ({current_ip}).")
else:
# 3. Update senden
client.put(f'/domain/zone/{DOMAIN}/record/{record_id}', target=current_ip)
log(f"UPDATE: {fqdn} wurde auf {current_ip} gesetzt.")
# Refresh anstoßen (nur einmal pro Loop eigentlich nötig, aber sicher ist sicher)
client.post(f'/domain/zone/{DOMAIN}/refresh')
except Exception as e:
log(f"Fehler bei {fqdn}: {e}")
if __name__ == "__main__":
log("OVH DynDNS Updater gestartet...")
log(f"Domain: {DOMAIN}")
log(f"Überwachte Subdomains: {SUBDOMAINS}")
if not all([AK, AS, CK, DOMAIN]):
log("CRITICAL: API Keys oder Domain fehlen.")
exit(1)
while True:
public_ip = get_public_ip()
if public_ip:
update_ovh_dns(public_ip)
time.sleep(INTERVAL)

2
requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
ovh
requests