Vlastní doména a first-party proxy
Jak poskytovat soubory widgetu, připojení chatu, offline formulář a Smart Answer přes subdoménu svého webu — s klíčem proxy, skutečnou adresou návštěvníka a šablonami pro nginx, Apache a Caddy.
S vlastní doménou běží chat přes subdoménu vašeho webu, například chat.your-company.com. Váš server přijímá požadavky widgetu a jako reverzní proxy je předává reactive.chat. Tato stránka je určena tomu, kdo server provozuje. Krátká verze pro redaktory je pod Vlastní doména (first-party).
Co běží přes subdoménu
- Soubory widgetu –
loader.js, po něm načtené jádro (core.<hash>.js) a další moduly. - Připojení chatu – WebSocket pod
/rc_wss/včetně zálohy přes HTTP pod/rc_wss/h/a nahrávání souborů pod/rc_wss/upload/. - Offline formulář –
POST /api/offline/<SITE_KEY>, když nelze navázat připojení chatu. - Smart Answer –
/api/suche/, pokud používáte odpověď AI ve vyhledávání webu.
Co získáte:
- Žádné požadavky na domény třetích stran. Na těchto cestách prohlížeče návštěvníků komunikují pouze s vaší subdoménou.
- Jedna adresa v Content Security Policy.
script-srcaconnect-srcuvádějí vaši subdoménu místo adres reactive.chat (podrobnosti pod Zabezpečení a CSP). - Doručí se skutečná adresa návštěvníka. Proxy ji hlásí ve vyhrazené hlavičce zabezpečené tajným klíčem. Omezování a blokování pak počítá podle návštěvníka, ne podle proxy.
Co to neznamená:
- Nejde o vlastní hosting. Konverzace, přílohy a nastavení stále zpracovává a ukládá reactive.chat.
- Žádné tvrzení o souhlasu. Vlastní doména nemění to, kdo data zpracovává.
- Proxy vidí provoz. TLS končí na vaší proxy; nezaznamenávejte tam těla požadavků a vylučte
/rc_wss/h/z přístupového protokolu (tyto požadavky nesou krátkodobý token připojení v dotazu).
Požadavky
- Server nebo reverzní proxy veřejně dostupné přes HTTPS na portu 443, schopné odchozích připojení HTTPS. Existují šablony pro nginx (s modulem ssl), Apache 2.4.47 nebo novější a Caddy 2.
- Pro Apache moduly
mod_ssl,mod_proxy,mod_proxy_http,mod_proxy_wstunnel,mod_headersamod_setenvif. - Subdoména pouze pro chat. Chat potřebuje celého hostitele; cesta jako
www.your-company.com/chat/nefunguje. Zadejte jen název — bezhttps://, portu či cesty. Nepovolené jsou IP adresy, interní koncovky jako.local,.lan,.internala názvy podreactive.chat. - Stejná doména jako web. Chat je first-party jen tehdy, pokud subdoména patří k doméně webu, do kterého je vložen.
- DNS (A a/nebo AAAA) pouze s veřejnými adresami.
- Certifikát TLS pro subdoménu (šablony nginx/Apache očekávají cesty certbotu; Caddy si ho získá sám).
- Oprávnění upravovat projekt.
Nastavení
- V účtu otevřete projekt, část Vložení → Nastavit vlastní doménu.
- Pod 1. Hostitel zadejte název, například
chat.your-company.com, a uložte. - Pod 2. Klíč proxy klikněte na Vytvořit klíč. Klíč začíná
rcpx_a zobrazí se právě jednou; ukládá se jen hash. Patří výhradně do konfigurace proxy — nikdy na webovou stránku, do skriptu prohlížeče ani do repozitáře. - Pod 3. Konfigurace serveru převezměte šablonu pro váš server. Ihned po vytvoření klíče ho obsahuje; později ukazuje
__RC_PROXY_KEY__. Otestujte konfiguraci (nginx -tneboapachectl configtest) a znovu načtěte server. - Pod 5. Kontrola klikněte na Zkontrolovat nyní (nejvýše každých 10 sekund). Žádná zpráva se nevytvoří.
- Teprve když všech pět kroků kontroly ukazuje „OK“, nahraďte kód kódem z 4. Vkládací kód:
<script src="https://chat.your-company.com/loader.js"
data-rc-site-key="SITE_KEY"
data-rc-ws-url="wss://chat.your-company.com/rc_wss/"
async></script>
Widget přebírá umístění souborů ze src, připojení chatu z data-rc-ws-url a z něj odvozuje adresy offline formuláře, nahrávání a zálohy přes HTTP. Všechny ostatní atributy zůstávají stejné (Referenční přehled značky script).
Co musí proxy předávat
/rc_wss/→ chatovací serverhttps://ws.reactive.chat/rc_wss/, s upgradem na WebSocket, dlouhým časovým limitem (šablony: 3600 s), bez bufferování a s limitem těla alespoň 32 MB (nahrávání)./api/offline/→https://ws.reactive.chat/api/offline/(malé tělo, šablona: 32 kB, 30 s)./api/suche/→https://ws.reactive.chat/api/suche/, bez bufferování (odpověď je stream Server-Sent Events), tělo do 8 kB, 120 s.- vše ostatní → distribuční síť
https://cdn.reactive.chat/.
Pro všechny cesty:
- Hlavička Host a SNI obsahují název cíle, ne vaši subdoménu. Na neznámého hostitele se odpovídá HTTP 421.
- Certifikát cíle se ověřuje.
- Žádné cookies ani přihlašovací údaje.
CookieaAuthorizationprohlížeče se nepředávají aSet-Cookiese nevrací. - Žádná přesměrování. Mezipaměť není nutná; pokud ji nastavíte, držte ji pro
loader.jskrátkou — soubor nemá v názvu číslo verze (jádro ano, viz Architektura).
Pro /rc_wss/, /api/offline/ a /api/suche/ proxy v každém požadavku nastavuje dvě hlavičky:
- X-RC-Proxy-Key – váš klíč
rcpx_…. - X-RC-Client-IP – adresa návštěvníka tak, jak ji vidí proxy.
„Nastavuje“ znamená: cokoli prohlížeč odešle pod těmito názvy, se přepíše. Na cestě do distribuční sítě se obě mažou.
Za nástrojem pro vyvažování zátěže nebo CDN vidí proxy nejprve adresu tohoto zařízení. Pak nastavte přebírání skutečné adresy: nginx real_ip (set_real_ip_from, real_ip_header), Apache mod_remoteip (RemoteIPHeader, RemoteIPTrustedProxy), Caddy trusted_proxies a {client_ip} místo {remote_host}. Kontrola tento případ nerozpozná — vidí jen, že je nastavena platná adresa.
Šablona nginx
Stránka účtu už vyplňuje hostitele, cílové adresy a klíč — nejlepší je zkopírovat šablonu odtamtud. Zdejší verze slouží jako reference; zástupné hodnoty jsou chat.your-company.com, SITE_KEY a __RC_PROXY_KEY__. Na RHEL/CentOS je sada certifikátů CA v /etc/pki/tls/certs/ca-bundle.crt.
server {
listen 80;
listen [::]:80;
server_name chat.your-company.com;
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.your-company.com;
ssl_certificate /etc/letsencrypt/live/chat.your-company.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.your-company.com/privkey.pem;
# HTTP fallback (SSE / long polling): token in the query, do not 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;
}
# Chat connection (WebSocket) and 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 form
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 search), answer as a stream
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 files
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;
}
}
Šablona Apache (2.4.47 nebo novější)
Pouze VirtualHost pro port 443; přesměrování z portu 80 a certifikát nastavte jako u ostatních hostitelů. SSLProxyVerifyDepth 5 je nutné — jinak Apache ověřuje řetězec cíle jen do jedné úrovně a hlásí „Certificate Chain too long“.
<VirtualHost *:443>
ServerName chat.your-company.com
SetEnvIf Request_URI "^/rc_wss/h/" rc_no_log
CustomLog ${APACHE_LOG_DIR}/chat.your-company.com_access.log combined env=!rc_no_log
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/chat.your-company.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/chat.your-company.com/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 před 2.4.47 nezná upgrade=websocket. V takovém případě nahraďte první řádek ProxyPass tímto:
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
Šablona Caddy 2
header_up s hodnotou nahrazuje cokoli, co prohlížeč odeslal pod tímto názvem. Pokud zapnete přístupové protokoly, vylučte /rc_wss/h/* (log_skip, před Caddy 2.8 skip_log).
chat.your-company.com {
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
}
}
}
}
Pět kroků kontroly
Každý krok ukazuje „OK“, „Chyba“, „Upozornění“ nebo „neověřeno“. Kontrola je úspěšná pouze s pěti „OK“. Kontroly používají jen HTTPS na portu 443, bez přesměrování, 5 sekund na krok.
- Překlad názvu – A/AAAA existuje, všechny adresy veřejné. Všechny další kroky se připojují právě k této adrese.
- loader.js přes vaši doménu – soubor se načte a porovná s naším. Bez připojení, odpovědi nebo platného certifikátu se zbytek kroků přeskočí. Přesměrování je chyba; odlišný soubor ukazuje na mezipaměť nebo nesprávný cíl pro
/. - Klíč a adresa návštěvníka – volání
/rc_wss/eigene-domain-probe. Možné chyby: chybíX-RC-Proxy-Key; neznámý klíč (hned po vytvoření prodleva až 30 sekund); chybí nebo je neplatnáX-RC-Client-IP; klíč patří jinému projektu. Upozornění, pokud je klíč platný, ale registrovaný pro jiného hostitele. - WebSocket –
wss://chat.your-company.com/rc_wss/musí odpovědět HTTP 101 a subprotokolemrc.v1. - Offline formulář –
GET /api/offline/SITE_KEYmusí odpovědět 405 (endpoint přijímá pouze POST; tak se nevytvoří zpráva).
Kontrolní adresu z kroku 3 můžete zavolat sami:
curl -s https://chat.your-company.com/rc_wss/eigene-domain-probe
Při správném nastavení:
{"rc":"eigene-domain-probe","v":1,"schluessel":"gueltig","client_ip":"gesetzt","site":"SITE_KEY","host":"chat.your-company.com"}
- schluessel –
gueltig(platný),unbekannt(neznámý) nebofehlt(chybí). - client_ip –
gesetzt(nastaveno),fehlt(chybí) neboungueltig(neplatné). - site, host – pouze s platným klíčem. Odpověď nikdy nevrací adresu.
Klíč proxy
- Rotace: Vytvořit nový klíč ihned vydá nový; předchozí zůstává platný 24 hodin. Platné jsou nejvýše dva klíče — další rotace během 24 hodin nejstarší klíč okamžitě zneplatní.
- Odstranění: Odebrat klíč ho ihned zneplatní (včetně starého z probíhající rotace). Odebrat vlastní doménu odstraní hostitele i klíč — nejprve přepněte kód na webu zpět.
- Chybějící nebo nesprávný klíč: chat běží dál, ale obě hlavičky se ignorují. Všichni návštěvníci se pak zobrazují s adresou proxy — a protože ochrana proti zneužití počítá podle adresy, může omezit celou proxy a všechny návštěvníky najednou.
- Jeden projekt na klíč: pokud se přes proxy s platným klíčem připojí widget s klíčem webu jiného projektu, připojení se odmítne. Pro další projekt potřebujete samostatnou subdoménu s vlastním klíčem.
- Uniklý klíč: kdokoli, kdo ho zná, může tvrdit libovolné adresy návštěvníků vašeho projektu. Odeberte ho, vytvořte nový a zadejte ho.
Řešení problémů
- HTTP 421 (Misdirected Request): proxy posílá jako hostitele váš název místo cílového. nginx:
proxy_set_header Hostplusproxy_ssl_server_name on/proxy_ssl_name; Apache:ProxyPreserveHost Off; Caddy:header_up Hostatls_server_name. - HTTP 502 / chyba TLS směrem k cíli: Apache bez
SSLProxyVerifyDepth 5; nginx s chybnou cestou vproxy_ssl_trusted_certificatenebo bezproxy_ssl_server_name on; blokované odchozí HTTPS. - HTTP 413 při nahrávání: bez nastavení nginx přijímá jen 1 MB;
client_max_body_size 32mv části/rc_wss/(a alespoň stejný limit v předřazeném nástroji pro vyvažování zátěže). - Chybí upgrade na WebSocket:
Upgrade/Connectionse nepředávají. Chat pak běží přes zálohu přes HTTP, ale připojí se až po dvou neúspěšných pokusech o WebSocket. - 401 u offline formuláře: před
/api/offline/stojí ochrana heslem. - 403 s upozorněním na origin: pod Povolené originy v projektu chybí doména webu (ne subdoména chatu!).
- 403 „Odpověď nepochází z reactive.chat“: firewall nebo přístupové pravidlo před cílem odmítá požadavek.
- DNS směřuje na soukromou adresu (
10.0.0.0/8,192.168.0.0/16,100.64.0.0/10,fc00::/7…): veřejný záznam musí být veřejný.
সর্বশেষ হালনাগাদ: