Zum Inhalt springen

Konfiguration

Die Instanz wird über Umgebungsvariablen konfiguriert. Ein Teil der Einstellungen lässt sich zusätzlich im Admin-Panel pflegen — dort gilt: eine gesetzte Umgebungsvariable gewinnt immer und die Oberfläche zeigt den Wert schreibgeschützt an (gedacht für Cluster-Deployments, wo die Konfiguration von außen kommt).

VariableVorgabeBedeutung
DNSE_LISTEN127.0.0.1:8422Adresse und Port
DNSE_ENCRYPTION_KEY—Pflicht. 32 Byte als Hex oder Base64
DNSE_ADMIN_USERadminBenutzername des Bootstrap-Kontos
DNSE_ADMIN_PASSWORD—Passwort beim allerersten Start (danach wirkungslos)
DNSE_SERVE_UIonoff liefert nur die API aus
DNSE_SECURE_COOKIESoffSecure für die kurzlebigen SSO-Handschlag-Cookies (EE) — die Anmeldung selbst benutzt keine Cookies mehr
DNSE_TRUSTED_PROXIES—Proxy-IPs/CIDRs, deren X-Forwarded-For gilt
DNSE_TLS_CERT—Zertifikatskette (PEM) — der Dienst spricht dann selbst HTTPS
DNSE_TLS_KEY—Passender privater Schlüssel (PEM); nur zusammen mit DNSE_TLS_CERT
DNSE_DEMOoffon registriert den Demo-Provider und legt Beispieldaten an
DNSE_UPDATE_FEEDIndex auf repo.techeve.deURL des APT-Paketindex für den Update-Hinweis im Admin-Bereich; off schaltet die Abfrage ab
VariableVorgabeBedeutung
DNSE_BACKUP_DIR—Ablage der nächtlichen Organisations-Sicherung (leer = aus)
DNSE_DB./dnseditor.dbPfad der SQLite-Datei
DNSE_DB_DSN—PostgreSQL-DSN; ersetzt DNSE_DB
DNSE_DB_YBoffon = DNSE_DB_DSN zeigt auf einen YugabyteDB-Cluster (YSQL)

Details in Datenbank und Schlüssel.

VariableVorgabeBedeutung
DNSE_VALKEY_ADDR—host:port eines gemeinsamen Valkey; mehrere Adressen (Komma) = Cluster
DNSE_VALKEY_PASSWORD—AUTH-Passwort, falls gesetzt
DNSE_SESSION_TTL12hGültigkeit einer Anmeldung ab der letzten Benutzung
DNSE_SESSION_TOUCH_INTERVAL—Mindestabstand zwischen zwei Auffrischungen; leer = jede Anfrage frischt auf

Ohne DNSE_VALKEY_ADDR liegen Sessions im Arbeitsspeicher des Prozesses — für eine einzelne Instanz genau richtig. Sobald mehrere Knoten hinter einem Loadbalancer laufen, gehört ein gemeinsamer Valkey dazu: Eine Anmeldung auf Knoten 1 gilt dann auf allen Knoten, und ein Logout wirkt überall.

DNSE_SESSION_TOUCH_INTERVAL bremst das Fortschreiben der Gültigkeit. Ohne Angabe schreibt jede Anfrage in den Sitzungsspeicher — bei einer einzelnen Instanz belanglos, bei einem geteilten Valkey unnötige Dauerlast für eine Angabe, die niemand auf die Minute genau braucht. 5m ist ein brauchbarer Wert; die Anmeldung läuft dadurch nicht früher ab, sie wird nur seltener verlängert.

VariableVorgabeBedeutung
DNSE_ACME_EMAIL—Konto-E-Mail; erst damit ist die Ausstellung aktiv
DNSE_ACME_DIRECTORYLet’s Encrypt (Produktion)Abweichendes ACME-Verzeichnis
DNSE_ACME_PROPAGATION—Feste Wartezeit statt Prüfung der autoritativen NS, z. B. 90s

DNSE_ACME_PROPAGATION braucht man in Split-DNS-Umgebungen, in denen die Vorabprüfung von lego am internen Resolver scheitert.

Diese Werte stehen unter Administration → Kern-Einstellungen und lassen sich alternativ per Umgebungsvariable vorgeben:

EinstellungVariableWofür
Öffentliche AdresseDNSE_INSTANCE_URLBasis für Links in ausgehenden Mails
DynDNS-HostnameDNSE_DYNDNS_HOSTNAMEUpdate-Adresse für Router
DynDNS-Hostname (nur IPv4)DNSE_DYNDNS_HOSTNAME4erzwingt A-Auflösung
DynDNS-Hostname (nur IPv6)DNSE_DYNDNS_HOSTNAME6erzwingt AAAA-Auflösung
SMTP-ServerDNSE_SMTP_HOSTPostausgang
SMTP-PortDNSE_SMTP_PORTPostausgang
AbsenderDNSE_SMTP_FROMAbsenderadresse
SMTP-BenutzerDNSE_SMTP_USERNAMEAuthentifizierung
SMTP-PasswortDNSE_SMTP_PASSWORDverschlüsselt gespeichert, wird nie zurückgegeben
ALTCHA-DienstDNSE_ALTCHA_URLRechenaufgabe vor den öffentlichen Formularen; leer = aus
ALTCHA-TokenDNSE_ALTCHA_TOKENverschlüsselt gespeichert, wird nie zurückgegeben

Ohne konfigurierten Postausgang funktionieren Einladungen, Passwort-Resets und Ablauf-Erinnerungen nicht — die Oberfläche zeigt in dem Fall generierte Passwörter direkt an, damit man sie manuell übergeben kann.

Sind DNSE_ALTCHA_URL und DNSE_ALTCHA_TOKEN gesetzt, bekommen die drei öffentlichen Formulare — Anmeldung, Registrierung, „Passwort vergessen” — eine kleine Rechenaufgabe vorgeschaltet (Proof-of-Work, ohne Cookies, ohne Bilderraten). Der Server prüft jede Einreichung beim Dienst; ohne bestandene Aufgabe wird das Formular gar nicht erst bearbeitet.

Drei Eigenschaften, die man kennen sollte:

  • Fail closed. Antwortet der Dienst nicht, gilt die Einreichung als ungültig. Ohne ihn hätte der Besucher ohnehin keine Aufgabe bekommen, und ein stiller Durchlass hebelte den Schutz bei jeder Störung aus.
  • Jede Lösung gilt genau einmal. Der Dienst merkt sich eingereichte Lösungen; die Oberfläche rechnet nach jedem Versuch eine neue.
  • Auch der zweite Anmeldeschritt (Zwei-Faktor-Code, Organisationswahl) verlangt eine Lösung — sonst genügte ein mitgeschickter Code, um am Riegel vorbei Passwörter durchzuprobieren.

Die Adresse der Website muss beim Dienst als Herkunft eingetragen sein (ALTCHA_ORIGINS), sonst verweigert er die Aufgabe. Ist nichts konfiguriert, bleibt alles wie bisher.

[Unit]
Description=DNS-Editor
After=network-online.target
[Service]
User=dnseditor
Environment=DNSE_LISTEN=127.0.0.1:8422
Environment=DNSE_DB_DSN=postgres://dnseditor:…@localhost:5432/dnseditor
Environment=DNSE_SECURE_COOKIES=on
Environment=DNSE_INSTANCE_URL=https://dns.example.com
EnvironmentFile=/etc/dnseditor/secrets.env
ExecStart=/usr/local/bin/dnseditor
Restart=on-failure
[Install]
WantedBy=multi-user.target

Der Verschlüsselungsschlüssel und das SMTP-Passwort gehören in die EnvironmentFile mit restriktiven Rechten, nicht in die Unit selbst.

server {
listen 443 ssl;
server_name dns.example.com;
ssl_certificate /etc/ssl/dns.example.com.pem;
ssl_certificate_key /etc/ssl/dns.example.com.key;
location / {
proxy_pass http://127.0.0.1:8422;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}

Dazu passend auf der Instanz:

Terminal-Fenster
DNSE_SECURE_COOKIES=on
DNSE_TRUSTED_PROXIES=127.0.0.1
DNSE_INSTANCE_URL=https://dns.example.com

DNSE_TRUSTED_PROXIES nennt die Adresse, von der aus der Proxy die Anfragen weiterreicht — nur deren X-Forwarded-For wird geglaubt. Ohne diese Angabe würde DynDNS die Proxy-Adresse statt der Router-IP eintragen.

Ein Hinweis zur Wirkung: Gilt eine Quelle als Proxy, zählt nur noch der Header. Ein Router, der ohne X-Forwarded-For direkt auf den Port geht, bekommt dann 911 statt eines Updates. Die Liste also eng halten und nicht auf 0.0.0.0/0 stellen.

Wenn der Proxy seinen Upstream per HTTPS anspricht

Abschnitt betitelt „Wenn der Proxy seinen Upstream per HTTPS anspricht“

Normalfall ist der obige: TLS endet im Proxy, dahinter läuft Klartext. Manche Proxys sind aber grundsätzlich auf proxy_pass https://… konfiguriert (oft zusammen mit proxy_ssl_verify off). Dann muss der Dienst selbst ein Zertifikat halten — sonst antwortet er auf den TLS-Handshake mit einem HTTP-400 und der Proxy meldet 502:

Terminal-Fenster
DNSE_TLS_CERT=/etc/dnseditor/tls/cert.pem
DNSE_TLS_KEY=/etc/dnseditor/tls/key.pem

Beide gehören zusammen — ist nur eines gesetzt, startet der Dienst nicht (stillschweigend Klartext zu sprechen, wo TLS gemeint war, wäre die gefährlichere Antwort). Prüft der Proxy das Zertifikat nicht, genügt ein selbstsigniertes:

Terminal-Fenster
openssl req -x509 -newkey rsa:2048 -nodes -days 3650 -keyout key.pem -out cert.pem -subj "/CN=dns.example.com"

Der Schlüssel gehört der Dienstgruppe und bleibt bei 0640.

Die Oberfläche liefert eine Content-Security-Policy aus, die Skripte auf die eigene Herkunft beschränkt. Das ist kein Beiwerk: Seit die Anmeldung als Token im Browser-Speicher liegt (statt in einem HttpOnly-Cookie), könnte eingeschleustes JavaScript sie lesen. Die Richtlinie verhindert, dass fremdes Skript überhaupt zur Ausführung kommt.

Praktische Folge für den Betrieb: Ein Proxy, der eigene Skripte einfügt — Analytics, Consent-Banner, Fehler-Tracker — wird vom Browser blockiert. Wer so etwas braucht, muss den Header im Proxy bewusst ersetzen und weiß dann, welchen Schutz er dafür aufgibt.

Stile dürfen inline sein (die Komponenten setzen sie zur Laufzeit), Skripte ausdrücklich nicht — genau dort liegt die Gefahr.