Własna domena i proxy first-party
Jak serwować pliki widżetu, połączenie czatu, formularz offline i Smart Answer przez subdomenę twojej strony – z kluczem proxy, prawdziwym adresem odwiedzającego i gotowymi szablonami dla nginx, Apache i Caddy.
Z własną domeną czat działa przez subdomenę twojej strony, na przykład chat.deine-firma.de. Twój serwer przyjmuje żądania widżetu i jako reverse proxy przekazuje je do reactive.chat. Ta strona jest przeznaczona dla osoby, która prowadzi ten serwer. Wersję skróconą dla redaktorów znajdziesz w Własna domena (first-party).
Co przechodzi przez subdomenę
- Pliki widżetu –
loader.js, doładowywany rdzeń (core.<hash>.js) i pozostałe moduły. - Połączenie czatu – WebSocket pod
/rc_wss/, łącznie z trybem awaryjnym HTTP pod/rc_wss/h/i przesyłaniem plików pod/rc_wss/upload/. - Formularz offline –
POST /api/offline/<SITE_KEY>, gdy połączenie czatu nie dochodzi do skutku. - Smart Answer –
/api/suche/, jeśli korzystasz z odpowiedzi AI w wyszukiwarce twojej strony.
Co ci to daje:
- Brak żądań do obcych domen. Na tych drogach przeglądarka twoich odwiedzających rozmawia tylko z twoją subdomeną.
- Jeden adres w Content Security Policy. W
script-srciconnect-srcstoi twoja subdomena zamiast adresów reactive.chat (szczegóły w Bezpieczeństwo i CSP). - Dociera prawdziwy adres odwiedzającego. Twoje proxy przekazuje go w osobnym nagłówku, zabezpieczonym tajnym kluczem. Ograniczanie i blokady liczą wtedy według odwiedzającego, a nie według proxy.
Czym nie jest:
- To nie jest własny hosting. Rozmowy, załączniki i ustawienia nadal przetwarza i przechowuje reactive.chat.
- Żadnej deklaracji co do zgody. Własna domena nie zmienia tego, kto przetwarza dane.
- Twoje proxy widzi ruch. TLS kończy się na twoim proxy; nie zapisuj tam w logach treści żądań i wyłącz
/rc_wss/h/z logu dostępu (te żądania niosą w query krótkotrwały token połączenia).
Wymagania
- Serwer lub reverse proxy, publicznie osiągalny przez HTTPS na porcie 443, z wychodzącym HTTPS. Szablony są dla nginx (z modułem ssl), Apache od 2.4.47 i Caddy 2.
- W Apache moduły
mod_ssl,mod_proxy,mod_proxy_http,mod_proxy_wstunnel,mod_headersimod_setenvif. - Subdomena tylko dla czatu. Czat potrzebuje całego hosta; ścieżka w rodzaju
www.deine-firma.de/chat/nie zadziała. Wpisujesz tylko nazwę – bezhttps://, portu ani ścieżki. Niedozwolone są adresy IP, wewnętrzne końcówki jak.local,.lan,.internaloraz nazwy w domeniereactive.chat. - Ta sama domena co twoja strona. Czat jest first-party tylko wtedy, gdy subdomena należy do domeny strony, na której jest osadzony.
- DNS (A i/lub AAAA) wyłącznie z publicznymi adresami.
- Certyfikat TLS dla subdomeny (szablony dla nginx/Apache zakładają ścieżki certbota, Caddy pobiera go sam).
- Uprawnienie do edycji projektu.
Konfiguracja
- Otwórz w koncie projekt, sekcja Osadzenie → Skonfiguruj własną domenę.
- W 1. Host wpisz nazwę, na przykład
chat.deine-firma.de, i zapisz. - W 2. Klucz proxy kliknij Utwórz klucz. Klucz zaczyna się od
rcpx_i jest pokazywany dokładnie raz; przechowywany jest tylko hash. Należy wyłącznie do konfiguracji proxy – nigdy do strony internetowej, skryptu w przeglądarce ani repozytorium. - W 3. Konfiguracja serwera przejmij szablon dla swojego serwera. Zaraz po utworzeniu klucza zawiera go; później widnieje tam
__RC_PROXY_KEY__. Sprawdź konfigurację (nginx -tlubapachectl configtest) i przeładuj serwer. - W 5. Sprawdź kliknij Sprawdź teraz (najwyżej co 10 sekund). Nie powstaje przy tym żadna wiadomość.
- Dopiero gdy wszystkie pięć kroków testu pokazuje „w porządku”, zamień fragment kodu na ten z 4. Fragment kodu:
<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>
Z src widżet bierze miejsce swoich plików, z data-rc-ws-url połączenie czatu i na tej podstawie adresy formularza offline, przesyłania plików i trybu awaryjnego HTTP. Wszystkie pozostałe atrybuty zostają bez zmian (Tag script – dokumentacja).
Co proxy musi przekazywać
/rc_wss/→ serwer czatuhttps://ws.reactive.chat/rc_wss/, z upgrade WebSocket, długim limitem czasu (szablony: 3600 s), bez buforowania i z limitem treści żądania co najmniej 32 MB (przesyłanie plików)./api/offline/→https://ws.reactive.chat/api/offline/(mała treść, szablon: 32 kB, 30 s)./api/suche/→https://ws.reactive.chat/api/suche/, bez buforowania (odpowiedź to strumień Server-Sent Events), treść do 8 kB, 120 s.- wszystko inne → sieć dostarczania
https://cdn.reactive.chat/.
Dla wszystkich dróg obowiązuje:
- Nagłówek Host i SNI to nazwa celu, a nie twoja subdomena. Na obcy host serwer odpowiada HTTP 421.
- Certyfikat celu jest weryfikowany.
- Bez cookies, bez danych logowania.
CookieiAuthorizationprzeglądarki nie są przekazywane dalej, aSet-Cookienie jest zwracane. - Bez przekierowań. Pamięć podręczna nie jest potrzebna; jeśli ją skonfigurujesz, ustaw dla
loader.jskrótki czas – plik nie ma numeru wersji w nazwie (rdzeń ma, zobacz Architektura).
Dla /rc_wss/, /api/offline/ i /api/suche/ proxy przy każdym żądaniu ustawia dwa nagłówki:
- X-RC-Proxy-Key – twój klucz
rcpx_…. - X-RC-Client-IP – adres odwiedzającego, tak jak widzi go twoje proxy.
„Ustawia” oznacza: to, co przeglądarka wyśle pod tymi nazwami, zostaje nadpisane. Na drodze do sieci dostarczania oba są czyszczone.
Za load balancerem lub CDN twoje proxy widzi najpierw adres tego urządzenia. Skonfiguruj wtedy przejmowanie prawdziwego adresu: nginx real_ip (set_real_ip_from, real_ip_header), Apache mod_remoteip (RemoteIPHeader, RemoteIPTrustedProxy), Caddy trusted_proxies i {client_ip} zamiast {remote_host}. Test nie wykryje tego przypadku – widzi tylko, że ustawiono prawidłowy adres.
Szablon nginx
Strona konta wstawia już host, adresy docelowe i klucz – najlepiej skopiuj szablon stamtąd. Wersja tutaj służy do wglądu; symbole zastępcze to chat.deine-firma.de, SITE_KEY i __RC_PROXY_KEY__. W RHEL/CentOS pakiet CA leży pod /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;
# Tryb awaryjny HTTP (SSE / long polling): token w query, nie logować
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;
}
# Połączenie czatu (WebSocket) i przesyłanie plików
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;
}
# Formularz offline
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 (wyszukiwarka strony), odpowiedź jako strumień danych
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;
}
# Pliki widżetu
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;
}
}
Szablon Apache (od 2.4.47)
Tylko VirtualHost dla portu 443; przekierowanie z portu 80 i certyfikat konfigurujesz tak jak dla pozostałych hostów. SSLProxyVerifyDepth 5 jest obowiązkowe – w przeciwnym razie Apache sprawdza łańcuch celu tylko na jeden poziom w głąb i zgłasza „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 przed 2.4.47 nie zna upgrade=websocket. Zastąp wtedy pierwszą linię ProxyPass przez:
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
Szablon Caddy 2
header_up z wartością zastępuje to, co przeglądarka wysłała pod tą nazwą. Jeśli włączysz logi dostępu, wyłącz z nich /rc_wss/h/* (log_skip, przed 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
}
}
}
}
Pięć kroków testu
Każdy krok pokazuje „w porządku”, „błąd”, „uwaga” lub „nie sprawdzono”. Test jest zaliczony tylko przy pięciu „w porządku”. Sprawdzamy wyłącznie przez HTTPS na porcie 443, bez przekierowań, 5 sekund na krok.
- Rozwiązywanie nazwy – jest A/AAAA, wszystkie adresy są publiczne. Wszystkie kolejne kroki łączą się dokładnie z tym adresem.
- loader.js przez twoją domenę – plik jest pobierany i porównywany z naszym. Bez połączenia, odpowiedzi lub ważnego certyfikatu pozostałe kroki są pomijane. Przekierowanie to błąd; inny plik wskazuje na pamięć podręczną albo zły cel dla
/. - Klucz i adres odwiedzającego – wywołanie
/rc_wss/eigene-domain-probe. Możliwe błędy: brakX-RC-Proxy-Key; nieznany klucz (zaraz po utworzeniu do 30 sekund opóźnienia); brak lub nieprawidłowyX-RC-Client-IP; klucz należy do innego projektu. Uwaga, gdy klucz jest ważny, ale zarejestrowany dla innego hosta. - WebSocket –
wss://chat.deine-firma.de/rc_wss/musi odpowiedzieć HTTP 101 z podprotokołemrc.v1. - Formularz offline –
GET /api/offline/SITE_KEYmusi odpowiedzieć 405 (endpoint przyjmuje tylko POST; dzięki temu nie powstaje żadna wiadomość).
Adres testowy z kroku 3 możesz wywołać sam:
curl -s https://chat.deine-firma.de/rc_wss/eigene-domain-probe
Przy prawidłowej konfiguracji:
{"rc":"eigene-domain-probe","v":1,"schluessel":"gueltig","client_ip":"gesetzt","site":"SITE_KEY","host":"chat.deine-firma.de"}
- schluessel –
gueltig,unbekanntalbofehlt. - client_ip –
gesetzt,fehltalboungueltig. - site, host – tylko przy ważnym kluczu. Odpowiedź nigdy nie zwraca adresu.
Klucz proxy
- Rotacja: Utwórz nowy klucz od razu wydaje nowy; dotychczasowy obowiązuje jeszcze 24 godziny. Ważne mogą być najwyżej dwa klucze – kto w ciągu tych 24 godzin zrotuje ponownie, od razu unieważnia najstarszy.
- Usuwanie: Usuń klucz unieważnia go od razu (także stary z trwającej rotacji). Usuń własną domenę usuwa razem host i klucz – wcześniej przywróć fragment kodu na swojej stronie.
- Brakujący lub zły klucz: czat działa dalej, ale oba nagłówki są ignorowane. Wszyscy odwiedzający pojawiają się wtedy z adresem twojego proxy – a ponieważ hamulec nadużyć liczy według adresu, może przyhamować całe twoje proxy, a tym samym wszystkich odwiedzających naraz.
- Jeden projekt na klucz: jeśli przez proxy z ważnym kluczem zgłosi się widżet z kluczem witryny innego projektu, połączenie zostanie odrzucone. Dla kolejnego projektu potrzebujesz osobnej subdomeny z osobnym kluczem.
- Klucz wyciekł: kto go zna, może dla twojego projektu podawać dowolne adresy odwiedzających. Usuń go, utwórz nowy i wpisz go.
Rozwiązywanie problemów
- HTTP 421 (Misdirected Request): proxy wysyła twoją nazwę jako Host zamiast nazwy celu. nginx:
proxy_set_header Hostplusproxy_ssl_server_name on/proxy_ssl_name; Apache:ProxyPreserveHost Off; Caddy:header_up Hostitls_server_name. - HTTP 502 / błąd TLS do celu: Apache bez
SSLProxyVerifyDepth 5; nginx ze złą ścieżką wproxy_ssl_trusted_certificatealbo bezproxy_ssl_server_name on; zablokowany wychodzący HTTPS. - HTTP 413 przy przesyłaniu plików: nginx bez ustawienia przyjmuje tylko 1 MB;
client_max_body_size 32mw sekcji/rc_wss/(i co najmniej ten sam limit w load balancerze przed nim). - Brak upgrade WebSocket:
Upgrade/Connectionnie są przekazywane. Czat działa wtedy przez tryb awaryjny HTTP, ale łączy się dopiero po dwóch nieudanych próbach WebSocket. - 401 przy formularzu offline: przed
/api/offline/jest ochrona hasłem. - 403 z uwagą dotyczącą pochodzenia: w projekcie w polu Dozwolone źródła brakuje domeny strony (nie subdomeny czatu!).
- 403 „Odpowiedź nie pochodzi od reactive.chat”: firewall lub reguła dostępu przed celem odrzuca żądanie.
- DNS wskazuje na adres prywatny (
10.0.0.0/8,192.168.0.0/16,100.64.0.0/10,fc00::/7…): publiczny wpis musi być publiczny.
Dalej: Transport i protokół · Bezpieczeństwo i CSP
Senest opdateret: