Eigene Domain (First-Party)
Widget, Chat-Verbindung und Offline-Formular über eine Subdomain Ihrer Website ausliefern – Voraussetzungen, Einrichtung, Vorlagen für nginx, Apache und Caddy, Fehlerbehebung.
Mit einer eigenen Domain läuft der Chat über eine Subdomain Ihrer Website, zum Beispiel chat.ihre-domain.de. Ihr 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.
Was die eigene Domain leistet
Über Ihre Subdomain laufen:
- die Widget-Dateien (
loader.jsund der nachgeladene Kern), - die Chat-Verbindung (WebSocket), einschließlich der Datei-Anhänge,
- das Offline-Formular, das einspringt, wenn die Chat-Verbindung nicht zustande kommt.
Daraus folgt:
- Keine Anfragen an fremde Domains. Für diese Wege spricht der Browser Ihrer Besucher nur mit Ihrer Subdomain und nicht mit einer Domain von reactive.chat.
- Werbeblocker. Filterlisten, die nach dem Domainnamen sperren, erkennen den Chat nicht mehr an der Domain reactive.chat.
- Eine Adresse für die Content-Security-Policy. In
script-srcundconnect-srcsteht Ihre Subdomain statt der Adressen von reactive.chat.connect-srcbraucht sie zweimal: mitwss://für die Chat-Verbindung und mithttps://für Offline-Formular, Uploads und den HTTP-Rückfall (wenn ein Proxy keinen WebSocket durchlässt). - Die echte Besucheradresse kommt an. Ihr Proxy meldet uns die Adresse des Besuchers in einer eigenen Kopfzeile, abgesichert durch einen geheimen Schlüssel. Der Missbrauchsschutz (Drosselung und Sperren) zählt damit je Besucher und nicht je Proxy, und am Gespräch steht die Adresse des Besuchers.
Was sie nicht ist
- Kein Selbstbetrieb. Ihr Server leitet nur weiter. Gespräche, Anhänge und Einstellungen werden weiterhin von reactive.chat verarbeitet und gespeichert, genau wie ohne eigene Domain.
- Keine Aussage zur Einwilligung. Ob und wofür Sie eine Einwilligung Ihrer Besucher brauchen, beurteilen Sie unabhängig davon. Die eigene Domain ändert nichts daran, wer die Daten verarbeitet. Formulierungen für Ihre Datenschutzerklärung finden Sie im Textbaustein für Ihre Datenschutzerklärung.
- Ihr Server sieht den Verkehr. Die TLS-Verbindung des Besuchers endet an Ihrem Proxy. Nachrichten und Anhänge liegen dort kurz entschlüsselt vor, bevor er sie verschlüsselt an uns weiterreicht. Schreiben Sie auf dem Proxy keine Anfragekörper ins Protokoll.
Voraussetzungen
- Ein eigener Server oder Reverse-Proxy, der aus dem Internet über HTTPS auf Port 443 erreichbar ist und selbst ausgehende HTTPS-Verbindungen aufbauen darf. Vorlagen gibt es für nginx (mit dem ssl-Modul), Apache ab 2.4.47 und Caddy 2.
- Bei Apache die Module mod_ssl, mod_proxy, mod_proxy_http, mod_proxy_wstunnel und mod_headers. Erst ab 2.4.47 kennt Apache
upgrade=websocket; für ältere Fassungen steht am Ende der Vorlage eine Ausweichlösung mit mod_rewrite. - Eine Subdomain nur für den Chat, zum Beispiel
chat.ihre-domain.de. Der Chat braucht den ganzen Host; ein Pfad wiewww.ihre-domain.de/chat/funktioniert nicht. Eingetragen wird nur der Name – ohnehttps://, ohne Port, ohne Pfad. Nicht möglich sind IP-Adressen, interne Endungen wie.local,.lanoder.internalund Namen unter reactive.chat. - Dieselbe Domain wie Ihre Website. First-Party ist der Chat nur, wenn die Subdomain zur Domain der Website gehört, auf der er eingebunden ist. Sonst funktioniert er trotzdem, und die Kontoseite weist auf den Unterschied hin.
- Ein DNS-Eintrag (A und/oder AAAA), der auf Ihren Server zeigt. Alle Adressen des Namens müssen öffentlich sein.
- Ein TLS-Zertifikat für die Subdomain. Die Vorlagen für nginx und Apache erwarten die Pfade von certbot (Let’s Encrypt); Caddy holt sich das Zertifikat selbst.
- Das Recht, das Projekt zu bearbeiten, in Ihrem reactive.chat-Konto.
Hinter einem Load-Balancer oder CDN sieht Ihr Proxy zunächst dessen Adresse statt der des Besuchers. Richten Sie in diesem Fall die Übernahme der echten Besucheradresse ein: bei nginx das Modul real_ip (set_real_ip_from, real_ip_header), bei Apache mod_remoteip (RemoteIPHeader, RemoteIPTrustedProxy), bei Caddy die Option trusted_proxies und den Platzhalter {client_ip} statt {remote_host}. Unsere Prüfung kann diesen Fall nicht erkennen: Sie sieht nur, dass eine gültige Adresse gesetzt ist, nicht welche.
Einrichtung Schritt für Schritt
- Seite öffnen. Öffnen Sie im Konto das Projekt. Im Abschnitt „Einbindung“ steht der Link Eigene Domain einrichten.
- Host eintragen. Tragen Sie unter „1. Host“ den Namen ein, zum Beispiel
chat.ihre-domain.de, und speichern Sie. - Schlüssel erzeugen. Klicken Sie unter „2. Proxy-Schlüssel“ auf Schlüssel erzeugen. Der Schlüssel beginnt mit
rcpx_und wird genau einmal angezeigt; wir speichern nur einen Hash davon. Kopieren Sie ihn sofort. Er ist geheim und gehört ausschließlich in die Konfiguration Ihres Proxys – nie in eine Webseite, ein Skript im Browser oder ein Repository. - Vorlage einsetzen. Unter „3. Server-Konfiguration“ stehen fertige Vorlagen für nginx, Apache und Caddy. Direkt nach dem Erzeugen enthalten sie Ihren Schlüssel bereits; später steht dort
__RC_PROXY_KEY__, den Sie durch den Schlüssel ersetzen. Passen Sie bei Bedarf die Zertifikatspfade an, prüfen Sie die Konfiguration (nginx -tbzw.apachectl configtest) und laden Sie den Server neu. - Prüfen. Klicken Sie unter „5. Prüfen“ auf Jetzt prüfen. Wir rufen Ihre Subdomain von außen auf und prüfen fünf Wege einzeln (siehe unten). Dabei entsteht keine Nachricht. Eine neue Prüfung ist frühestens nach 10 Sekunden möglich.
- Schnipsel austauschen. Erst wenn alle fünf Schritte „in Ordnung“ zeigen, ersetzen Sie den bisherigen Einbau-Schnipsel auf Ihrer Website durch den aus „4. Einbau-Schnipsel“.
Der neue Schnipsel sieht so aus – beide Adressen zeigen auf Ihre Subdomain:
<script src="https://chat.ihre-domain.de/loader.js"
data-rc-site-key="SITE_KEY"
data-rc-ws-url="wss://chat.ihre-domain.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 Adresse des Offline-Formulars. Weitere Angaben wie data-rc-locale bleiben, wie sie sind; sie sind unter Das Widget einbinden beschrieben. Der Schnipsel auf der Kontoseite trägt zusätzlich Ihre Markenfarbe.
Die fünf Prüfschritte
Jeder Schritt zeigt „in Ordnung“, „Fehler“, „Hinweis“ oder „nicht geprüft“. Bestanden ist die Prüfung nur, wenn alle fünf „in Ordnung“ zeigen; ein Hinweis zählt nicht als bestanden. Geprüft wird nur über HTTPS auf Port 443, Umleitungen werden nicht verfolgt, jeder Schritt hat 5 Sekunden Zeit.
- Namensauflösung. Der Name muss einen DNS-Eintrag haben, und alle seine Adressen müssen öffentlich sein. Gemeldet wird, wenn weder ein A- noch ein AAAA-Eintrag gefunden wird oder wenn mindestens eine Adresse privat, lokal oder reserviert ist – solche Adressen prüfen wir nicht. Alle folgenden Schritte verbinden sich mit genau der hier geprüften Adresse.
- loader.js über Ihre Domain. Wir laden
https://chat.ihre-domain.de/loader.jsund vergleichen die Datei mit unserer. Kommt keine Verbindung, keine Antwort oder kein gültiges Zertifikat zustande, werden die übrigen Schritte übersprungen („nicht geprüft“). Antwortet der Proxy mit einer Umleitung statt mit der Datei, ist das ein Fehler. Weicht die Datei von unserer ab, liegt das meist an einem Zwischenspeicher im Proxy oder an einem falschen Ziel für/. - Schlüssel und Besucheradresse. Wir rufen eine Prüfadresse unter
/rc_wss/auf. Unser Server antwortet darauf, ob er einen gültigen Schlüssel und eine gültige Besucheradresse bekommen hat und zu welchem Projekt der Schlüssel gehört. Mögliche Fehler: KopfzeileX-RC-Proxy-Keyfehlt; Schlüssel unbekannt (vertippt, veraltet oder entfernt – direkt nach dem Erzeugen kann es bis zu 30 Sekunden dauern); KopfzeileX-RC-Client-IPfehlt oder enthält keine gültige Adresse; Schlüssel gehört zu einem anderen Projekt. Ein Hinweis erscheint, wenn der Schlüssel gültig, aber für einen anderen Host eingetragen ist. - Chat-Verbindung (WebSocket). Wir bauen eine WebSocket-Verbindung über
wss://chat.ihre-domain.de/rc_wss/auf und erwarten HTTP 101 mit dem Protokollrc.v1. „Kein WebSocket-Upgrade“ heißt: der Proxy reicht die KopfzeilenUpgradeundConnectionnicht weiter. - Offline-Formular. Wir rufen
https://chat.ihre-domain.de/api/offline/SITE_KEYmit GET auf. Unser Endpunkt antwortet darauf mit HTTP 405, weil er nur POST annimmt – daran erkennen wir, dass die Anfrage bei uns ankommt, ohne dass eine Nachricht entsteht. Weitere Ergebnisse: Herkunft abgewiesen (Hinweis, siehe Fehlerbehebung), Projekt nicht aktiv, Ziel verlangt eine Anmeldung (HTTP 401).
In den Schritten 2 bis 5 kann außerdem HTTP 421 gemeldet werden (Host-Kopf, siehe Fehlerbehebung). Meldet Schritt 3 oder 5 „Die Antwort kommt nicht von reactive.chat“, zeigt dieser Pfad im Proxy auf ein falsches Ziel.
Was der Proxy weiterleiten muss
/rc_wss/an den Chat-Server von reactive.chat, mit WebSocket-Upgrade und langer Zeitgrenze (die Vorlagen nehmen 3600 Sekunden). Über denselben Pfad laufen die Datei-Uploads; je nach Tarif sind das bis zu 32 MB je Datei./api/offline/an denselben Server. Darüber sendet das Widget das Offline-Formular.- Alles andere an das Auslieferungsnetz von reactive.chat. Von dort kommen
loader.jsund die übrigen Widget-Dateien.
Für alle drei Wege gilt:
- Host-Kopf und SNI sind der Name des Ziels, nicht Ihre Subdomain. Unser Server beantwortet einen fremden Host mit HTTP 421.
- Das Zertifikat des Ziels wird geprüft.
- Keine Cookies und keine Anmeldedaten. Die Kopfzeilen
CookieundAuthorizationdes Browsers werden nicht weitergereicht. - Keine Umleitungen. Ein Zwischenspeicher ist nicht nötig. Wenn Sie einen einrichten, halten Sie ihn für
loader.jskurz – die Datei trägt keine Versionsnummer im Namen.
Für /rc_wss/ und /api/offline/ setzt der Proxy zusätzlich bei jeder Anfrage zwei Kopfzeilen:
X-RC-Proxy-Key– Ihr Schlüssel.X-RC-Client-IP– die Adresse des Besuchers, wie Ihr Proxy sie sieht.
„Setzen“ heißt: Was ein Browser unter diesen Namen mitschickt, wird überschrieben und erreicht uns nie. Auf dem Weg zum Auslieferungsnetz werden beide Kopfzeilen geleert; der Schlüssel geht nur an den Chat-Server.
HTTP-Rückfall über Ihre Domain
Lässt das Netz eines Besuchers keinen WebSocket durch, wechselt das Widget automatisch auf den HTTP-Rückfall. Er läuft über denselben Pfad /rc_wss/ und braucht keinen weiteren Eintrag im Proxy. Dafür ist zweierlei nötig:
- Ungepuffert weiterreichen. Der Proxy muss Antworten auf
/rc_wss/sofort durchreichen: bei nginxproxy_buffering offundproxy_cache off, bei Apacheflushpackets=on, bei Caddyflush_interval -1. Die Vorlagen unten enthalten das bereits. - HTTPS in der Content-Security-Policy.
connect-srcbraucht Ihre Subdomain mitwss://und mithttps://, zum Beispielconnect-src 'self' wss://chat.ihre-domain.de https://chat.ihre-domain.de.
Die Vorlagen
Die folgenden Vorlagen entsprechen denen der Kontoseite. Die Kontoseite setzt Ihren Host, die für Ihr Konto gültigen Zieladressen und – direkt nach dem Erzeugen – Ihren Schlüssel bereits ein. Kopieren Sie die Vorlage deshalb am besten von dort; die Fassungen hier dienen zum Nachlesen. Platzhalter sind chat.ihre-domain.de, SITE_KEY und __RC_PROXY_KEY__.
nginx
Gehört in den http-Kontext, zum Beispiel als /etc/nginx/conf.d/chat.ihre-domain.de.conf. Auf RHEL und CentOS liegt das CA-Bündel unter /etc/pki/tls/certs/ca-bundle.crt statt /etc/ssl/certs/ca-certificates.crt.
# reactive.chat - own domain (first-party proxy) for site key SITE_KEY
# Host: chat.ihre-domain.de
#
# Needs nginx >= 1.7 with the ssl module. Put this file into the http
# context (e.g. /etc/nginx/conf.d/chat.ihre-domain.de.conf), adjust the certificate
# paths if you do not use certbot, then: nginx -t && systemctl reload nginx
#
# The proxy key is a secret: never put it into a web page or a repository.
# X-RC-Proxy-Key and X-RC-Client-IP are always SET here - whatever a browser
# sends under these names is overwritten.
server {
listen 80;
listen [::]:80;
server_name chat.ihre-domain.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.ihre-domain.de;
ssl_certificate /etc/letsencrypt/live/chat.ihre-domain.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.ihre-domain.de/privkey.pem;
# Chat connection (WebSocket). Host header and SNI must be the upstream
# name - reactive.chat answers 421 to any other host.
# HTTP fallback (Server-Sent Events / long polling): its requests carry a
# short-lived connection token in the query string - EventSource cannot
# send headers. Same settings as /rc_wss/ below, but kept out of the
# access log.
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;
}
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;
# Unbuffered: if a visitor's network blocks WebSockets, the widget
# falls back to Server-Sent Events / long polling on this path.
proxy_buffering off;
proxy_cache off;
# File attachments are uploaded through this path as well (PUT
# /rc_wss/upload/...). nginx allows 1 MB by default; reactive.chat
# accepts up to 32 MB per file depending on the plan.
client_max_body_size 32m;
proxy_request_buffering off;
}
# Offline form fallback (HTTP POST from the widget).
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 for site search (suche.js and the HTTP API). Same rules as
# the offline route: key and visitor address are set here.
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;
# The answer is a stream (Server-Sent Events): pass it on unbuffered.
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 120s;
}
# Widget files (loader.js, core.*.js ...). No caching required; if you
# add a cache, keep it short for loader.js (it is not versioned).
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;
}
}
# On RHEL/CentOS the CA bundle is /etc/pki/tls/certs/ca-bundle.crt.
# Behind a load balancer/CDN, $remote_addr is the balancer: configure the
# real_ip module so that it holds the visitor's address.
Apache
Die Vorlage enthält nur den VirtualHost für Port 443. Die Umleitung von Port 80 und die Ausstellung des Zertifikats richten Sie ein wie für Ihre übrigen Hosts. SSLProxyVerifyDepth 5 ist nötig: Ohne diese Zeile prüft Apache die Zertifikatskette des Ziels nur eine Stufe tief, und die Verbindung scheitert mit „Certificate Chain too long“.
# reactive.chat - own domain (first-party proxy) for site key SITE_KEY
# Host: chat.ihre-domain.de
#
# Needs Apache >= 2.4.47 with mod_ssl, mod_proxy, mod_proxy_http,
# mod_proxy_wstunnel, mod_headers and mod_setenvif:
# a2enmod ssl proxy proxy_http proxy_wstunnel headers setenvif
# Adjust the certificate paths if you do not use certbot, then:
# apachectl configtest && systemctl reload apache2
#
# The proxy key is a secret: never put it into a web page or a repository.
<VirtualHost *:443>
ServerName chat.ihre-domain.de
# HTTP fallback requests (/rc_wss/h/...) carry a short-lived connection
# token in the query string - keep them out of the access log.
SetEnvIf Request_URI "^/rc_wss/h/" rc_no_log
# ${APACHE_LOG_DIR} is set on Debian/Ubuntu; elsewhere e.g. /var/log/httpd.
CustomLog ${APACHE_LOG_DIR}/chat.ihre-domain.de_access.log combined env=!rc_no_log
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/chat.ihre-domain.de/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/chat.ihre-domain.de/privkey.pem
# Upstream TLS: verified, SNI = upstream name (ProxyPreserveHost Off
# sends the upstream name as Host - reactive.chat answers 421 otherwise).
SSLProxyEngine on
SSLProxyVerify require
# Apache checks only ONE certificate deep by default; the upstream chain
# (leaf, intermediate, root) is longer: "Certificate Chain too long".
SSLProxyVerifyDepth 5
SSLProxyCheckPeerName on
SSLProxyCACertificateFile /etc/ssl/certs/ca-certificates.crt
ProxyRequests Off
ProxyPreserveHost Off
ProxyAddHeaders Off
# Whatever the browser sends under these names never reaches upstream.
RequestHeader unset X-RC-Proxy-Key early
RequestHeader unset X-RC-Client-IP early
RequestHeader unset Cookie early
RequestHeader unset Authorization early
# Longest path first. flushpackets=on on /rc_wss/: if a visitor's network
# blocks WebSockets, the widget falls back to Server-Sent Events / long
# polling on this path, and those must not be buffered.
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 < 2.4.47 has no upgrade=websocket. Instead of the first ProxyPass:
# 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
Caddy
Caddy holt das Zertifikat selbst, WebSockets brauchen keine eigene Einstellung. header_up mit einem Wert ersetzt, was der Browser unter diesem Namen geschickt hat.
# reactive.chat - own domain (first-party proxy) for site key SITE_KEY
# Host: chat.ihre-domain.de
#
# Caddy 2 obtains the certificate itself. WebSockets need no extra setting.
# The proxy key is a secret: never put it into a web page or a repository.
# header_up with a value REPLACES what the browser sent under that name.
# If you enable access logging (log directive), skip the HTTP fallback
# requests - they carry a short-lived token in the query string:
# log_skip /rc_wss/h/* (Caddy < 2.8: skip_log /rc_wss/h/*)
chat.ihre-domain.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
}
# The answer is a stream (Server-Sent Events): pass it on unbuffered.
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
}
}
}
}
Der Proxy-Schlüssel
- Rotieren. Neuen Schlüssel erzeugen stellt sofort einen neuen Schlüssel aus. Der bisherige gilt noch 24 Stunden weiter, damit Sie den neuen ohne Unterbrechung eintragen können; prüfen Sie danach erneut. Es gibt höchstens zwei gültige Schlüssel: Wer innerhalb der 24 Stunden noch einmal rotiert, macht den ältesten sofort ungültig.
- Entfernen. Schlüssel entfernen macht den Schlüssel sofort ungültig, ebenso einen noch laufenden alten aus einer Rotation. Eigene Domain entfernen nimmt Host und Schlüssel zusammen weg. Stellen Sie vorher den Schnipsel auf Ihrer Website wieder auf die gewohnte Form um.
- Wenn der Schlüssel fehlt oder falsch ist, funktioniert der Chat weiter: Die beiden Kopfzeilen werden dann einfach nicht ausgewertet. Alle Besucher erscheinen aber mit der Adresse Ihres Proxys. Weil der Missbrauchsschutz Verbindungen und Anfragen je Adresse zählt, kann er dann Ihren ganzen Proxy bremsen oder sperren – und damit alle Besucher zugleich. Das gilt auch für das Offline-Formular.
- Ein Projekt je Schlüssel. Ein Schlüssel gehört zu genau einem Projekt und dessen eingetragenem Host. Meldet sich über einen Proxy mit gültigem Schlüssel ein Widget mit dem Site-Key eines anderen Projekts, wird die Chat-Verbindung abgewiesen. Für ein weiteres Projekt richten Sie eine eigene Subdomain mit eigenem Schlüssel ein.
- Wenn der Schlüssel bekannt geworden ist: Wer ihn kennt, kann für Ihr Projekt beliebige Besucheradressen angeben. Entfernen Sie ihn, erzeugen Sie danach einen neuen und tragen Sie diesen im Proxy ein. Bis dahin läuft der Chat weiter, nur mit der Adresse Ihres Proxys.
Fehlerbehebung
HTTP 421 (Misdirected Request)
Unser Server lehnt den Host-Kopf ab: Der Proxy schickt Ihren eigenen Namen statt des Zielnamens. Host-Kopf und SNI müssen der Name des Ziels sein – bei nginx proxy_set_header Host sowie proxy_ssl_server_name on mit proxy_ssl_name, bei Apache ProxyPreserveHost Off, bei Caddy header_up Host und tls_server_name.
HTTP 502 oder SSL-Fehler auf dem Weg zum Ziel
Der Proxy kann die TLS-Verbindung zu uns nicht aufbauen oder traut dem Zertifikat nicht.
- Apache: Steht im Fehlerprotokoll „Certificate Chain too long“, fehlt
SSLProxyVerifyDepth 5. - nginx: Stimmt der Pfad in
proxy_ssl_trusted_certificate(siehe oben für RHEL und CentOS)? Istproxy_ssl_server_name ongesetzt? - Allgemein: Ihr Server muss ausgehende Verbindungen auf Port 443 aufbauen dürfen.
HTTP 413 beim Hochladen von Anhängen
Uploads laufen über /rc_wss/. nginx nimmt ohne eigene Einstellung nur 1 MB an; die Vorlage setzt deshalb client_max_body_size 32m im Abschnitt für /rc_wss/. Liegt ein Load-Balancer oder CDN vor Ihrem Proxy, braucht er mindestens dieselbe Grenze.
Chat-Verbindung ohne Upgrade
Die Prüfung meldet „Kein WebSocket-Upgrade“ mit dem HTTP-Status, den sie stattdessen bekommen hat. Der Chat läuft dann über den HTTP-Rückfall weiter, verbindet sich aber erst nach zwei gescheiterten WebSocket-Versuchen.
- nginx: Im Abschnitt
/rc_wss/müssenproxy_http_version 1.1,proxy_set_header Upgrade $http_upgradeundproxy_set_header Connection "upgrade"stehen. - Apache: Version ab 2.4.47 mit
upgrade=websocketund aktiviertem mod_proxy_wstunnel; für ältere Fassungen die Ausweichlösung am Ende der Vorlage. - Davor geschaltet: Ein CDN oder Load-Balancer vor Ihrem Proxy muss WebSockets durchlassen.
HTTP 401 oder 403 beim Offline-Formular
- 401: Auf dem Weg verlangt etwas eine Anmeldung, meist ein Passwortschutz auf dem Host Ihres Proxys.
/api/offline/muss ohne Anmeldung erreichbar sein. - 403, als Hinweis zur Herkunft: Die Anfrage erreicht uns, aber die Herkunft passt nicht zum Projekt. Unter „Erlaubte Herkünfte“ im Projekt muss die Domain Ihrer Website stehen – die Domain, auf der der Chat eingebunden ist, nicht die Chat-Subdomain.
- 403 mit „Die Antwort kommt nicht von reactive.chat“: Die Ablehnung kommt von einer Stelle davor, etwa einer Web Application Firewall oder einer Zugriffsregel auf Ihrem Server.
DNS zeigt auf eine private Adresse
Die Prüfung meldet „nicht öffentliche Adresse“, wenn mindestens eine Adresse des Namens privat, lokal oder reserviert ist (zum Beispiel 10.0.0.0/8, 192.168.0.0/16, 100.64.0.0/10 oder fc00::/7). Häufige Ursachen sind ein Eintrag aus dem internen DNS oder ein interner Load-Balancer. Ihre Besucher erreichen solche Adressen ebenfalls nicht; der öffentliche Eintrag muss auf eine öffentliche Adresse zeigen.
Von Hand nachsehen
Die Prüfadresse aus Schritt 3 können Sie selbst abrufen:
curl -s https://chat.ihre-domain.de/rc_wss/eigene-domain-probe
Bei richtiger Einrichtung lautet die Antwort:
{"rc":"eigene-domain-probe","v":1,"schluessel":"gueltig","client_ip":"gesetzt","site":"SITE_KEY","host":"chat.ihre-domain.de"}
schluessel ist gueltig, unbekannt oder fehlt, client_ip ist gesetzt, fehlt oder ungueltig. site und host stehen nur bei einem gültigen Schlüssel darin. Eine Adresse gibt die Antwort nie zurück.
Stand: