Eigene Domain und First-Party-Proxy
Wie du Widget-Dateien, Chat-Verbindung, Offline-Formular und Smart Answer über eine Subdomain deiner Website ausspielst – mit Proxy-Schlüssel, echter Besucheradresse und fertigen Vorlagen für nginx, Apache und Caddy.
Mit einer eigenen Domain läuft der Chat über eine Subdomain deiner Website, zum Beispiel chat.deine-firma.de. Dein Server nimmt die Anfragen des Widgets an und reicht sie als Reverse-Proxy an reactive.chat weiter. Diese Seite richtet sich an die Person, die diesen Server betreibt. Die Kurzfassung für Redakteure steht unter Eigene Domain (First-Party).
Was über die Subdomain läuft
- Widget-Dateien –
loader.js, der nachgeladene Kern (core.<hash>.js) und die übrigen Module. - Chat-Verbindung – der WebSocket unter
/rc_wss/, einschließlich des HTTP-Rückfalls unter/rc_wss/h/und der Datei-Uploads unter/rc_wss/upload/. - Offline-Formular –
POST /api/offline/<SITE_KEY>, wenn keine Chat-Verbindung zustande kommt. - Smart Answer –
/api/suche/, falls du die KI-Antwort in deiner Website-Suche nutzt.
Was du davon hast:
- Keine Anfragen an fremde Domains. Der Browser deiner Besucher spricht für diese Wege nur mit deiner Subdomain.
- Eine Adresse in der Content-Security-Policy. In
script-srcundconnect-srcsteht deine Subdomain statt der Adressen von reactive.chat (Details unter Sicherheit und CSP). - Die echte Besucheradresse kommt an. Dein Proxy meldet sie in einer eigenen Kopfzeile, abgesichert durch einen geheimen Schlüssel. Drosselung und Sperren zählen damit je Besucher und nicht je Proxy.
Was sie nicht ist:
- Kein Selbstbetrieb. Gespräche, Anhänge und Einstellungen verarbeitet und speichert weiterhin reactive.chat.
- Keine Aussage zur Einwilligung. Die eigene Domain ändert nichts daran, wer die Daten verarbeitet.
- Dein Proxy sieht den Verkehr. TLS endet an deinem Proxy; schreibe dort keine Anfragekörper ins Protokoll und halte
/rc_wss/h/aus dem Zugriffsprotokoll heraus (diese Anfragen tragen ein kurzlebiges Verbindungstoken in der Query).
Voraussetzungen
- Ein Server oder Reverse-Proxy, öffentlich per HTTPS auf Port 443 erreichbar, mit ausgehendem HTTPS. Vorlagen gibt es für nginx (mit ssl-Modul), Apache ab 2.4.47 und Caddy 2.
- Bei Apache die Module
mod_ssl,mod_proxy,mod_proxy_http,mod_proxy_wstunnel,mod_headersundmod_setenvif. - Eine eigene Subdomain nur für den Chat. Der Chat braucht den ganzen Host; ein Pfad wie
www.deine-firma.de/chat/funktioniert nicht. Eingetragen wird nur der Name – ohnehttps://, Port oder Pfad. Nicht erlaubt sind IP-Adressen, interne Endungen wie.local,.lan,.internalund Namen unterreactive.chat. - Dieselbe Domain wie die Website. First-Party ist der Chat nur, wenn die Subdomain zur Domain der Website gehört, auf der er eingebunden ist.
- DNS (A und/oder AAAA) mit ausschließlich öffentlichen Adressen.
- Ein TLS-Zertifikat für die Subdomain (Vorlagen für nginx/Apache erwarten die certbot-Pfade, Caddy holt es selbst).
- Das Recht, das Projekt zu bearbeiten.
Einrichtung
- Öffne im Konto das Projekt, Abschnitt Einbindung → Eigene Domain einrichten.
- Trage unter 1. Host den Namen ein, zum Beispiel
chat.deine-firma.de, und speichere. - Klicke unter 2. Proxy-Schlüssel auf Schlüssel erzeugen. Der Schlüssel beginnt mit
rcpx_und wird genau einmal angezeigt; gespeichert wird nur ein Hash. Er gehört ausschließlich in die Proxy-Konfiguration – nie in eine Webseite, ein Browser-Skript oder ein Repository. - Übernimm unter 3. Server-Konfiguration die Vorlage für deinen Server. Direkt nach dem Erzeugen enthält sie den Schlüssel; später steht dort
__RC_PROXY_KEY__. Prüfe die Konfiguration (nginx -tbzw.apachectl configtest) und lade den Server neu. - Klicke unter 5. Prüfen auf Jetzt prüfen (frühestens alle 10 Sekunden). Es entsteht keine Nachricht.
- Erst wenn alle fünf Prüfschritte „in Ordnung“ zeigen, tauschst du den Einbau-Schnipsel gegen den aus 4. Einbau-Schnipsel:
<script src="https://chat.deine-firma.de/loader.js"
data-rc-site-key="SITE_KEY"
data-rc-ws-url="wss://chat.deine-firma.de/rc_wss/"
async></script>
Aus src nimmt das Widget den Ort seiner Dateien, aus data-rc-ws-url die Chat-Verbindung und davon abgeleitet die Adressen von Offline-Formular, Uploads und HTTP-Rückfall. Alle anderen Attribute bleiben, wie sie sind (Script-Tag-Referenz).
Was der Proxy weiterleiten muss
/rc_wss/→ Chat-Serverhttps://ws.reactive.chat/rc_wss/, mit WebSocket-Upgrade, langer Zeitgrenze (Vorlagen: 3600 s), ungepuffert und mit einer Rumpfgrenze von mindestens 32 MB (Uploads)./api/offline/→https://ws.reactive.chat/api/offline/(Rumpf klein, Vorlage: 32 kB, 30 s)./api/suche/→https://ws.reactive.chat/api/suche/, ungepuffert (Antwort ist ein Server-Sent-Events-Strom), Rumpf bis 8 kB, 120 s.- alles andere → Auslieferungsnetz
https://cdn.reactive.chat/.
Für alle Wege gilt:
- Host-Kopf und SNI sind der Name des Ziels, nicht deine Subdomain. Ein fremder Host wird mit HTTP 421 beantwortet.
- Das Zertifikat des Ziels wird geprüft.
- Keine Cookies, keine Anmeldedaten.
CookieundAuthorizationdes Browsers werden nicht weitergereicht,Set-Cookiewird nicht zurückgegeben. - Keine Umleitungen. Ein Zwischenspeicher ist nicht nötig; wenn du einen einrichtest, halte ihn für
loader.jskurz – die Datei trägt keine Versionsnummer im Namen (der Kern schon, siehe Architektur).
Für /rc_wss/, /api/offline/ und /api/suche/ setzt der Proxy bei jeder Anfrage zwei Kopfzeilen:
- X-RC-Proxy-Key – dein Schlüssel
rcpx_…. - X-RC-Client-IP – die Adresse des Besuchers, wie dein Proxy sie sieht.
„Setzen“ heißt: Was ein Browser unter diesen Namen mitschickt, wird überschrieben. Auf dem Weg zum Auslieferungsnetz werden beide geleert.
Hinter einem Load-Balancer oder CDN sieht dein Proxy zunächst dessen Adresse. Richte dann die Übernahme der echten Adresse ein: nginx real_ip (set_real_ip_from, real_ip_header), Apache mod_remoteip (RemoteIPHeader, RemoteIPTrustedProxy), Caddy trusted_proxies und {client_ip} statt {remote_host}. Die Prüfung erkennt diesen Fall nicht – sie sieht nur, dass eine gültige Adresse gesetzt ist.
Vorlage nginx
Die Kontoseite setzt Host, Zieladressen und Schlüssel bereits ein – kopiere die Vorlage am besten von dort. Die Fassung hier dient zum Nachlesen; Platzhalter sind chat.deine-firma.de, SITE_KEY und __RC_PROXY_KEY__. Auf RHEL/CentOS liegt das CA-Bündel unter /etc/pki/tls/certs/ca-bundle.crt.
server {
listen 80;
listen [::]:80;
server_name chat.deine-firma.de;
location /.well-known/acme-challenge/ { root /var/www/html; }
location / { return 301 https://$host$request_uri; }
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name chat.deine-firma.de;
ssl_certificate /etc/letsencrypt/live/chat.deine-firma.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.deine-firma.de/privkey.pem;
# HTTP-Rueckfall (SSE / Long-Polling): Token in der Query, nicht loggen
location /rc_wss/h/ {
access_log off;
proxy_pass https://ws.reactive.chat/rc_wss/h/;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host ws.reactive.chat;
proxy_ssl_server_name on;
proxy_ssl_name ws.reactive.chat;
proxy_ssl_verify on;
proxy_ssl_verify_depth 3;
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
proxy_set_header X-RC-Proxy-Key "__RC_PROXY_KEY__";
proxy_set_header X-RC-Client-IP $remote_addr;
proxy_set_header Cookie "";
proxy_set_header Authorization "";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
proxy_cache off;
}
# Chat-Verbindung (WebSocket) und Uploads
location /rc_wss/ {
proxy_pass https://ws.reactive.chat/rc_wss/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host ws.reactive.chat;
proxy_ssl_server_name on;
proxy_ssl_name ws.reactive.chat;
proxy_ssl_verify on;
proxy_ssl_verify_depth 3;
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
proxy_set_header X-RC-Proxy-Key "__RC_PROXY_KEY__";
proxy_set_header X-RC-Client-IP $remote_addr;
proxy_set_header Cookie "";
proxy_set_header Authorization "";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
proxy_cache off;
client_max_body_size 32m;
proxy_request_buffering off;
}
# Offline-Formular
location /api/offline/ {
proxy_pass https://ws.reactive.chat/api/offline/;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host ws.reactive.chat;
proxy_ssl_server_name on;
proxy_ssl_name ws.reactive.chat;
proxy_ssl_verify on;
proxy_ssl_verify_depth 3;
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
proxy_set_header X-RC-Proxy-Key "__RC_PROXY_KEY__";
proxy_set_header X-RC-Client-IP $remote_addr;
proxy_set_header Cookie "";
proxy_set_header Authorization "";
proxy_hide_header Set-Cookie;
client_max_body_size 32k;
proxy_read_timeout 30s;
}
# Smart Answer (Website-Suche), Antwort als Datenstrom
location /api/suche/ {
proxy_pass https://ws.reactive.chat/api/suche/;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host ws.reactive.chat;
proxy_ssl_server_name on;
proxy_ssl_name ws.reactive.chat;
proxy_ssl_verify on;
proxy_ssl_verify_depth 3;
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
proxy_set_header X-RC-Proxy-Key "__RC_PROXY_KEY__";
proxy_set_header X-RC-Client-IP $remote_addr;
proxy_set_header Cookie "";
proxy_set_header Authorization "";
proxy_hide_header Set-Cookie;
client_max_body_size 8k;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 120s;
}
# Widget-Dateien
location / {
proxy_pass https://cdn.reactive.chat/;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host cdn.reactive.chat;
proxy_ssl_server_name on;
proxy_ssl_name cdn.reactive.chat;
proxy_ssl_verify on;
proxy_ssl_verify_depth 3;
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
proxy_set_header X-RC-Proxy-Key "";
proxy_set_header X-RC-Client-IP "";
proxy_set_header Cookie "";
proxy_set_header Authorization "";
proxy_hide_header Set-Cookie;
}
}
Vorlage Apache (ab 2.4.47)
Nur der VirtualHost für Port 443; Umleitung von Port 80 und Zertifikat richtest du wie für deine übrigen Hosts ein. SSLProxyVerifyDepth 5 ist Pflicht – sonst prüft Apache die Kette des Ziels nur eine Stufe tief und meldet „Certificate Chain too long“.
<VirtualHost *:443>
ServerName chat.deine-firma.de
SetEnvIf Request_URI "^/rc_wss/h/" rc_no_log
CustomLog ${APACHE_LOG_DIR}/chat.deine-firma.de_access.log combined env=!rc_no_log
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/chat.deine-firma.de/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/chat.deine-firma.de/privkey.pem
SSLProxyEngine on
SSLProxyVerify require
SSLProxyVerifyDepth 5
SSLProxyCheckPeerName on
SSLProxyCACertificateFile /etc/ssl/certs/ca-certificates.crt
ProxyRequests Off
ProxyPreserveHost Off
ProxyAddHeaders Off
RequestHeader unset X-RC-Proxy-Key early
RequestHeader unset X-RC-Client-IP early
RequestHeader unset Cookie early
RequestHeader unset Authorization early
ProxyPass "/rc_wss/" "https://ws.reactive.chat/rc_wss/" upgrade=websocket timeout=3600 flushpackets=on
ProxyPass "/api/offline/" "https://ws.reactive.chat/api/offline/" timeout=30
ProxyPass "/api/suche/" "https://ws.reactive.chat/api/suche/" timeout=120 flushpackets=on
ProxyPass "/" "https://cdn.reactive.chat/"
<Location "/rc_wss/">
RequestHeader set X-RC-Proxy-Key "__RC_PROXY_KEY__"
RequestHeader set X-RC-Client-IP "expr=%{REMOTE_ADDR}"
</Location>
<Location "/api/offline/">
RequestHeader set X-RC-Proxy-Key "__RC_PROXY_KEY__"
RequestHeader set X-RC-Client-IP "expr=%{REMOTE_ADDR}"
Header unset Set-Cookie
</Location>
<Location "/api/suche/">
RequestHeader set X-RC-Proxy-Key "__RC_PROXY_KEY__"
RequestHeader set X-RC-Client-IP "expr=%{REMOTE_ADDR}"
Header unset Set-Cookie
</Location>
</VirtualHost>
Apache vor 2.4.47 kennt upgrade=websocket nicht. Ersetze dann die erste ProxyPass-Zeile durch:
RewriteEngine on
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^/rc_wss/(.*) "wss://ws.reactive.chat/rc_wss/$1" [P,L]
ProxyPass "/rc_wss/" "https://ws.reactive.chat/rc_wss/" timeout=3600 flushpackets=on
Vorlage Caddy 2
header_up mit einem Wert ersetzt, was der Browser unter diesem Namen geschickt hat. Wenn du Zugriffsprotokolle einschaltest, nimm /rc_wss/h/* aus (log_skip, vor Caddy 2.8 skip_log).
chat.deine-firma.de {
handle /rc_wss/* {
reverse_proxy https://ws.reactive.chat {
header_up Host ws.reactive.chat
header_up X-RC-Proxy-Key "__RC_PROXY_KEY__"
header_up X-RC-Client-IP {remote_host}
header_up -Cookie
header_up -Authorization
transport http {
tls_server_name ws.reactive.chat
}
flush_interval -1
}
}
handle /api/offline/* {
reverse_proxy https://ws.reactive.chat {
header_up Host ws.reactive.chat
header_up X-RC-Proxy-Key "__RC_PROXY_KEY__"
header_up X-RC-Client-IP {remote_host}
header_up -Cookie
header_up -Authorization
header_down -Set-Cookie
transport http {
tls_server_name ws.reactive.chat
}
}
}
handle /api/suche/* {
reverse_proxy https://ws.reactive.chat {
header_up Host ws.reactive.chat
header_up X-RC-Proxy-Key "__RC_PROXY_KEY__"
header_up X-RC-Client-IP {remote_host}
header_up -Cookie
header_up -Authorization
header_down -Set-Cookie
transport http {
tls_server_name ws.reactive.chat
}
flush_interval -1
}
}
handle {
reverse_proxy https://cdn.reactive.chat {
header_up Host cdn.reactive.chat
header_up -X-RC-Proxy-Key
header_up -X-RC-Client-IP
header_up -Cookie
header_up -Authorization
header_down -Set-Cookie
transport http {
tls_server_name cdn.reactive.chat
}
}
}
}
Die fünf Prüfschritte
Jeder Schritt zeigt „in Ordnung“, „Fehler“, „Hinweis“ oder „nicht geprüft“. Bestanden ist die Prüfung nur mit fünfmal „in Ordnung“. Geprüft wird nur per HTTPS auf Port 443, ohne Umleitungen, je Schritt 5 Sekunden.
- Namensauflösung – A/AAAA vorhanden, alle Adressen öffentlich. Alle folgenden Schritte verbinden sich mit genau dieser Adresse.
- loader.js über deine Domain – die Datei wird geladen und mit unserer verglichen. Ohne Verbindung, Antwort oder gültiges Zertifikat werden die übrigen Schritte übersprungen. Eine Umleitung ist ein Fehler; eine abweichende Datei deutet auf einen Zwischenspeicher oder ein falsches Ziel für
/. - Schlüssel und Besucheradresse – Aufruf von
/rc_wss/eigene-domain-probe. Fehlerbilder:X-RC-Proxy-Keyfehlt; Schlüssel unbekannt (direkt nach dem Erzeugen bis zu 30 Sekunden Verzögerung);X-RC-Client-IPfehlt oder ist ungültig; Schlüssel gehört zu einem anderen Projekt. Hinweis, wenn der Schlüssel gültig, aber für einen anderen Host eingetragen ist. - WebSocket –
wss://chat.deine-firma.de/rc_wss/muss mit HTTP 101 und dem Subprotokollrc.v1antworten. - Offline-Formular –
GET /api/offline/SITE_KEYmuss mit 405 antworten (der Endpunkt nimmt nur POST an; so entsteht keine Nachricht).
Die Prüfadresse aus Schritt 3 kannst du selbst abrufen:
curl -s https://chat.deine-firma.de/rc_wss/eigene-domain-probe
Bei richtiger Einrichtung:
{"rc":"eigene-domain-probe","v":1,"schluessel":"gueltig","client_ip":"gesetzt","site":"SITE_KEY","host":"chat.deine-firma.de"}
- schluessel –
gueltig,unbekanntoderfehlt. - client_ip –
gesetzt,fehltoderungueltig. - site, host – nur bei gültigem Schlüssel. Eine Adresse gibt die Antwort nie zurück.
Der Proxy-Schlüssel
- Rotieren: Neuen Schlüssel erzeugen stellt sofort einen neuen aus; der bisherige gilt noch 24 Stunden. Es gibt höchstens zwei gültige Schlüssel – wer innerhalb der 24 Stunden erneut rotiert, macht den ältesten sofort ungültig.
- Entfernen: Schlüssel entfernen macht ihn sofort ungültig (auch einen alten aus einer laufenden Rotation). Eigene Domain entfernen nimmt Host und Schlüssel zusammen weg – stell vorher den Schnipsel auf deiner Website zurück.
- Fehlender oder falscher Schlüssel: Der Chat läuft weiter, die beiden Kopfzeilen werden aber ignoriert. Alle Besucher erscheinen dann mit der Adresse deines Proxys – und weil die Missbrauchsbremse je Adresse zählt, kann sie deinen ganzen Proxy und damit alle Besucher zugleich bremsen.
- Ein Projekt je Schlüssel: Meldet sich über einen Proxy mit gültigem Schlüssel ein Widget mit dem Site-Key eines anderen Projekts, wird die Verbindung abgewiesen. Für ein weiteres Projekt brauchst du eine eigene Subdomain mit eigenem Schlüssel.
- Schlüssel bekannt geworden: Wer ihn kennt, kann für dein Projekt beliebige Besucheradressen behaupten. Entferne ihn, erzeuge einen neuen, trage ihn ein.
Fehlerbehebung
- HTTP 421 (Misdirected Request): Der Proxy schickt deinen Namen als Host statt des Zielnamens. nginx:
proxy_set_header Hostplusproxy_ssl_server_name on/proxy_ssl_name; Apache:ProxyPreserveHost Off; Caddy:header_up Hostundtls_server_name. - HTTP 502 / TLS-Fehler zum Ziel: Apache ohne
SSLProxyVerifyDepth 5; nginx mit falschem Pfad inproxy_ssl_trusted_certificateoder ohneproxy_ssl_server_name on; ausgehendes HTTPS gesperrt. - HTTP 413 beim Hochladen: nginx nimmt ohne Einstellung nur 1 MB an;
client_max_body_size 32mim Abschnitt/rc_wss/(und mindestens dieselbe Grenze in einem vorgeschalteten Load-Balancer). - Kein WebSocket-Upgrade:
Upgrade/Connectionwerden nicht weitergereicht. Der Chat läuft dann über den HTTP-Rückfall, verbindet sich aber erst nach zwei gescheiterten WebSocket-Versuchen. - 401 beim Offline-Formular: Ein Passwortschutz liegt vor
/api/offline/. - 403 mit Hinweis zur Herkunft: Unter Erlaubte Herkünfte im Projekt fehlt die Domain der Website (nicht die Chat-Subdomain!).
- 403 „Die Antwort kommt nicht von reactive.chat“: Eine Firewall oder Zugriffsregel vor dem Ziel lehnt ab.
- DNS zeigt auf eine private Adresse (
10.0.0.0/8,192.168.0.0/16,100.64.0.0/10,fc00::/7…): Der öffentliche Eintrag muss öffentlich sein.
Weiter: Transport und Protokoll · Sicherheit und CSP
Paskutinį kartą atnaujinta: