Власний домен і проксі першої сторони
Як надавати файли віджета, з’єднання чату, офлайн-форму й Smart Answer через піддомен сайту: ключ проксі, справжня адреса відвідувача та готові шаблони nginx, Apache і Caddy.
Із власним доменом чат працює через піддомен вашого сайту, наприклад chat.your-company.com. Ваш сервер приймає запити віджета й передає їх до reactive.chat як зворотний проксі. Ця сторінка — для людини, яка обслуговує цей сервер. Коротка версія для редакторів — Власний домен (перша сторона).
Що проходить через піддомен
- Файли віджета —
loader.js, ядро, що завантажується після нього (core.<hash>.js), та інші модулі. - З’єднання чату — WebSocket за шляхом
/rc_wss/, зокрема резервний канал HTTP у/rc_wss/h/та завантаження файлів у/rc_wss/upload/. - Офлайн-форма —
POST /api/offline/<SITE_KEY>, коли неможливо встановити з’єднання чату. - Smart Answer —
/api/suche/, якщо ви використовуєте відповідь ШІ в пошуку сайту.
Що ви отримуєте:
- Без запитів до сторонніх доменів. Для цих шляхів браузери відвідувачів спілкуються лише з вашим піддоменом.
- Одна адреса в Content Security Policy.
script-srcіconnect-srcмістять піддомен замість адрес reactive.chat (докладніше — Безпека й CSP). - Надходить справжня адреса відвідувача. Проксі повідомляє її в окремому заголовку, захищеному секретним ключем. Обмеження й блокування тоді рахуються за відвідувачем, а не за проксі.
Чим це не є:
- Не самостійний хостинг. Розмови, вкладення й налаштування так само обробляє та зберігає reactive.chat.
- Не визначає згоди. Власний домен не змінює того, хто обробляє дані.
- Проксі бачить трафік. TLS завершується на проксі; не записуйте там тіла запитів і виключіть
/rc_wss/h/із журналу доступу (ці запити містять короткочасний токен з’єднання в рядку запиту).
Вимоги
- Сервер або зворотний проксі, публічно доступний через HTTPS на порту 443 та здатний відкривати вихідні HTTPS-з’єднання. Є шаблони для nginx (із модулем ssl), Apache 2.4.47 або новішого та Caddy 2.
- Для Apache — модулі
mod_ssl,mod_proxy,mod_proxy_http,mod_proxy_wstunnel,mod_headersтаmod_setenvif. - Піддомен лише для чату. Чату потрібен увесь хост; шлях на кшталт
www.your-company.com/chat/не працює. Введіть лише ім’я — безhttps://, порту чи шляху. Заборонені: IP-адреси, внутрішні закінчення на кшталт.local,.lan,.internalта імена в доменіreactive.chat. - Той самий домен, що й у сайту. Чат є першостороннім лише коли піддомен належить домену сайту, де його вбудовано.
- DNS (A та/або AAAA) лише з публічними адресами.
- Сертифікат TLS для піддомену (шаблони nginx/Apache очікують шляхи certbot; Caddy отримує його сам).
- Право редагувати проєкт.
Налаштування
- В обліковому записі відкрийте проєкт, розділ Вбудовування → Налаштувати власний домен.
- У 1. Хост введіть ім’я, наприклад
chat.your-company.com, і збережіть. - У 2. Ключ проксі натисніть Створити ключ. Він починається з
rcpx_і показується рівно один раз; зберігається лише хеш. Йому місце лише в конфігурації проксі — ніколи на вебсторінці, у браузерному скрипті чи репозиторії. - У 3. Конфігурація сервера візьміть шаблон для свого сервера. Одразу після створення він містить ключ; пізніше —
__RC_PROXY_KEY__. Перевірте конфігурацію (nginx -tабоapachectl configtest) і перезавантажте сервер. - У 5. Перевірка натисніть Перевірити зараз (щонайчастіше кожні 10 секунд). Повідомлення не створюється.
- Лише коли всі п’ять кроків показують «OK», замініть фрагмент вбудовування фрагментом із 4. Фрагмент вбудовування:
<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>
Розташування файлів віджет визначає через src, з’єднання чату — через data-rc-ws-url, і з нього виводить адреси офлайн-форми, завантажень та резервного каналу HTTP. Усі інші атрибути не змінюються (Довідник атрибутів тегу скрипту).
Що має пересилати проксі
/rc_wss/→ сервер чатуhttps://ws.reactive.chat/rc_wss/, із переходом на WebSocket, тривалим тайм-аутом (шаблони: 3600 с), без буферизації та лімітом тіла щонайменше 32 МБ (завантаження)./api/offline/→https://ws.reactive.chat/api/offline/(невелике тіло, шаблон: 32 кБ, 30 с)./api/suche/→https://ws.reactive.chat/api/suche/, без буферизації (відповідь — потік Server-Sent Events), тіло до 8 кБ, 120 с.- усе інше → мережа доставки
https://cdn.reactive.chat/.
Для всіх шляхів:
- Заголовок Host і SNI — ім’я цілі, а не піддомен. На невідомий хост відповідь — HTTP 421.
- Сертифікат цілі перевіряється.
- Без cookie й облікових даних.
CookieіAuthorizationбраузера не передаються, аSet-Cookieне повертається. - Без перенаправлень. Кеш не потрібний; якщо налаштуєте, задайте короткий строк для
loader.js— у назві файлу немає номера версії (ядро має, див. Архітектура).
Для /rc_wss/, /api/offline/ і /api/suche/ проксі задає два заголовки в кожному запиті:
- X-RC-Proxy-Key — ваш ключ
rcpx_…. - X-RC-Client-IP — адреса відвідувача, яку бачить проксі.
«Задає» означає, що все надіслане браузером під цими назвами перезаписується. На шляху до мережі доставки обидва очищуються.
За балансувальником навантаження або CDN проксі спочатку бачить адресу цього пристрою. Тоді налаштуйте отримання справжньої адреси: nginx real_ip (set_real_ip_from, real_ip_header), Apache mod_remoteip (RemoteIPHeader, RemoteIPTrustedProxy), Caddy trusted_proxies і {client_ip} замість {remote_host}. Перевірка не виявляє цього випадку — вона бачить лише задану дійсну адресу.
Шаблон nginx
Сторінка облікового запису вже заповнює хост, цільові адреси й ключ — найкраще копіювати шаблон звідти. Ця версія довідкова; заповнювачі — chat.your-company.com, SITE_KEY і __RC_PROXY_KEY__. У RHEL/CentOS пакет CA міститься в /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;
}
}
Шаблон Apache (2.4.47 або новіший)
Лише VirtualHost для порту 443; налаштуйте перенаправлення з порту 80 та сертифікат як для інших хостів. Потрібен SSLProxyVerifyDepth 5 — інакше Apache перевіряє ланцюжок цілі лише на один рівень і повідомляє «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 до 2.4.47 не підтримує upgrade=websocket. Тоді замініть перший рядок 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 2
header_up зі значенням замінює все, що браузер надіслав під цією назвою. Якщо вмикаєте журнали доступу, виключіть /rc_wss/h/* (log_skip, до 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
}
}
}
}
П’ять кроків перевірки
Кожен крок показує «OK», «Помилка», «Примітка» або «не перевірено». Перевірку пройдено лише з п’ятьма «OK». Використовується тільки HTTPS на порту 443, без перенаправлень, 5 секунд на крок.
- Визначення адреси за ім’ям — A/AAAA є, усі адреси публічні. Усі наступні кроки підключаються саме до цієї адреси.
- loader.js через ваш домен — файл завантажується й порівнюється з нашим. Без з’єднання, відповіді чи дійсного сертифіката решта кроків пропускається. Перенаправлення — помилка; відмінний файл указує на кеш або неправильну ціль для
/. - Ключ і адреса відвідувача — виклик
/rc_wss/eigene-domain-probe. Можливі помилки: немаєX-RC-Proxy-Key; ключ невідомий (одразу після створення затримка до 30 секунд);X-RC-Client-IPвідсутній або недійсний; ключ належить іншому проєкту. Примітка — якщо ключ дійсний, але зареєстрований для іншого хоста. - WebSocket —
wss://chat.your-company.com/rc_wss/має відповісти HTTP 101 і підпротоколомrc.v1. - Офлайн-форма —
GET /api/offline/SITE_KEYмає відповісти 405 (кінцева точка приймає лише POST, тому повідомлення не створюється).
Можна самостійно звернутися до адреси перевірки з кроку 3:
curl -s https://chat.your-company.com/rc_wss/eigene-domain-probe
За правильного налаштування:
{"rc":"eigene-domain-probe","v":1,"schluessel":"gueltig","client_ip":"gesetzt","site":"SITE_KEY","host":"chat.your-company.com"}
- schluessel —
gueltig(дійсний),unbekannt(невідомий) абоfehlt(відсутній). - client_ip —
gesetzt(задано),fehlt(відсутній) абоungueltig(недійсний). - site, host — лише з дійсним ключем. Відповідь ніколи не повертає адреси.
Ключ проксі
- Ротація: Створити новий ключ одразу видає новий; попередній залишається дійсним 24 години. Дійсні щонайбільше два ключі — повторна ротація протягом 24 годин негайно робить найстаріший недійсним.
- Видалення: Видалити ключ негайно робить його недійсним (разом зі старим від поточної ротації). Видалити власний домен видаляє хост і ключ разом — спочатку поверніть фрагмент на сайті до попереднього вигляду.
- Ключ відсутній або неправильний: чат працює далі, але два заголовки ігноруються. Усі відвідувачі мають адресу проксі, а оскільки захист від зловживань рахує за адресою, він може обмежити весь проксі й усіх відвідувачів одразу.
- Один проєкт на ключ: якщо через проксі з дійсним ключем підключається віджет із ключем сайту іншого проєкту, з’єднання відхиляється. Для ще одного проєкту потрібен окремий піддомен із власним ключем.
- Ключ розголошено: кожен, хто знає його, може заявляти довільні адреси відвідувачів для проєкту. Видаліть його, створіть новий, додайте його.
Усунення несправностей
- HTTP 421 (Misdirected Request): проксі надсилає ваше ім’я як хост замість імені цілі. nginx:
proxy_set_header Hostплюсproxy_ssl_server_name on/proxy_ssl_name; Apache:ProxyPreserveHost Off; Caddy:header_up Hostіtls_server_name. - HTTP 502 / помилка TLS до цілі: Apache без
SSLProxyVerifyDepth 5; nginx із неправильним шляхомproxy_ssl_trusted_certificateабо безproxy_ssl_server_name on; вихідний HTTPS заблоковано. - HTTP 413 під час завантаження: без налаштування nginx приймає лише 1 МБ;
client_max_body_size 32mу розділі/rc_wss/(і щонайменше такий самий ліміт у балансувальнику перед ним). - Немає переходу на WebSocket:
Upgrade/Connectionне передаються. Чат працює через резервний канал HTTP, але підключається лише після двох невдалих спроб WebSocket. - 401 для офлайн-форми: перед
/api/offline/є захист паролем. - 403 із приміткою про джерело: домену сайту (не піддомену чату!) немає в Дозволених джерелах проєкту.
- 403 «Відповідь не від reactive.chat»: міжмережевий екран або правило доступу перед ціллю відхиляє запит.
- DNS указує на приватну адресу (
10.0.0.0/8,192.168.0.0/16,100.64.0.0/10,fc00::/7…): публічний запис має бути публічним.
Далі: Транспорт і протокол · Безпека й CSP
Оновлено: