Chúng tôi có thể giúp gì?

Cho chúng tôi biết ngắn gọn về vấn đề – chúng tôi sẽ liên hệ lại qua email.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
Về trang chủ

Vlastní doména (first-party)

Poskytujte widget, připojení chatu a offline formulář ze subdomény svého webu: požadavky, nastavení, šablony pro nginx, Apache a Caddy a řešení problémů.

S vlastní doménou běží chat přes subdoménu vašeho webu, například chat.your-domain.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 daný server provozuje.

Co vlastní doména zajišťuje

Přes vaši subdoménu běží:

Výsledkem je:

Co to neznamená

Požadavky

Za nástrojem pro vyvažování zátěže nebo CDN vidí vaše proxy nejprve adresu tohoto zařízení místo adresy návštěvníka. V takovém případě nastavte přebírání skutečné adresy návštěvníka: v nginx modul real_ip (set_real_ip_from, real_ip_header), v Apache mod_remoteip (RemoteIPHeader, RemoteIPTrustedProxy), v Caddy volbu trusted_proxies a zástupný symbol {client_ip} místo {remote_host}. Naše kontrola tento případ nerozpozná: vidí jen, že je nastavena platná adresa, ne která.

Nastavení krok za krokem

  1. Otevřete stránku. Otevřete projekt v účtu. V části „Vložení“ najdete odkaz Nastavit vlastní doménu.
  2. Zadejte hostitele. V části „1. Hostitel“ zadejte název, například chat.your-domain.com, a uložte.
  3. Vytvořte klíč. V části „2. Klíč proxy“ klikněte na Vytvořit klíč. Klíč začíná rcpx_ a zobrazí se právě jednou; ukládáme pouze jeho hash. Ihned ho zkopírujte. Je tajný a patří pouze do konfigurace proxy — nikdy na webovou stránku, do skriptu v prohlížeči ani do repozitáře.
  4. Vložte šablonu. V části „3. Konfigurace serveru“ najdete hotové šablony pro nginx, Apache a Caddy. Ihned po vytvoření klíče ho už obsahují; později zobrazují __RC_PROXY_KEY__, který nahradíte klíčem. Případně upravte cesty k certifikátům, otestujte konfiguraci (nginx -t nebo apachectl configtest) a znovu načtěte server.
  5. Zkontrolujte. V části „5. Kontrola“ klikněte na Zkontrolovat nyní. Zavoláme vaši subdoménu zvenčí a ověříme samostatně pět cest (viz níže). Žádná zpráva se nevytvoří. Další kontrola je možná nejdříve za 10 sekund.
  6. Nahraďte kód. Teprve když všech pět kroků ukazuje „OK“, nahraďte aktuální vkládací kód na webu kódem z části „4. Vkládací kód“.

Nový kód vypadá takto — obě adresy směřují na vaši subdoménu:

<script src="https://chat.your-domain.com/loader.js"
        data-rc-site-key="SITE_KEY"
        data-rc-ws-url="wss://chat.your-domain.com/rc_wss/"
        async></script>

Widget přebírá umístění souborů ze src a připojení chatu z data-rc-ws-url — a z něj odvodí adresu offline formuláře. Ostatní atributy, například data-rc-locale, zůstávají stejné; jsou popsané v části Vložení widgetu. Kód na stránce účtu nese také barvu vaší značky.

Pět kroků kontroly

Každý krok ukazuje „OK“, „Chyba“, „Upozornění“ nebo „neověřeno“. Kontrola je úspěšná, pouze když všech pět ukazuje „OK“; upozornění se za úspěch nepovažuje. Kontroly používají pouze HTTPS na portu 443, nenásledují přesměrování a každý krok má 5 sekund.

  1. Překlad názvu. Název musí mít záznam DNS a všechny jeho adresy musí být veřejné. Hlásí se, pokud není nalezen záznam A ani AAAA nebo pokud je alespoň jedna adresa soukromá, místní či vyhrazená — takové adresy nekontrolujeme. Všechny další kroky se připojují přesně k adrese ověřené zde.
  2. loader.js přes vaši doménu. Načteme https://chat.your-domain.com/loader.js a porovnáme soubor s naším. Pokud se nepodaří připojení, odpověď nebo platný certifikát, zbývající kroky se přeskočí („neověřeno“). Pokud proxy místo souboru odpoví přesměrováním, jde o chybu. Pokud se soubor liší od našeho, příčinou bývá mezipaměť proxy nebo nesprávný cíl pro /.
  3. Klíč a adresa návštěvníka. Zavoláme kontrolní adresu pod /rc_wss/. Náš server odpoví, zda přijal platný klíč a platnou adresu návštěvníka a ke kterému projektu klíč patří. Možné chyby: chybí hlavička X-RC-Proxy-Key; klíč je neznámý (překlep, zastaralý nebo odstraněný — ihned po vytvoření to může trvat až 30 sekund); hlavička X-RC-Client-IP chybí nebo neobsahuje platnou adresu; klíč patří jinému projektu. Upozornění se zobrazí, pokud je klíč platný, ale registrovaný pro jiného hostitele.
  4. Připojení chatu (WebSocket). Otevřeme připojení WebSocket přes wss://chat.your-domain.com/rc_wss/ a očekáváme HTTP 101 s protokolem rc.v1. „Chybí upgrade na WebSocket“ znamená, že proxy nepředává hlavičky Upgrade a Connection.
  5. Offline formulář. Zavoláme https://chat.your-domain.com/api/offline/SITE_KEY metodou GET. Náš endpoint odpoví HTTP 405, protože přijímá pouze POST — tak poznáme, že požadavek došel k nám, aniž bychom vytvořili zprávu. Další výsledky: odmítnutý origin (upozornění, viz řešení problémů), neaktivní projekt, cíl vyžaduje ověření (HTTP 401).

Kroky 2 až 5 mohou hlásit také HTTP 421 (hlavička Host, viz řešení problémů). Pokud krok 3 nebo 5 hlásí „Odpověď nepochází z reactive.chat“, směřuje tato cesta ve vaší proxy na nesprávný cíl.

Co musí proxy předávat

Pro všechny tři cesty:

Pro /rc_wss/ a /api/offline/ proxy navíc v každém požadavku nastavuje dvě hlavičky:

„Nastavuje“ znamená: cokoli prohlížeč pod těmito názvy odešle, se přepíše a nikdy k nám nedojde. Na cestě do distribuční sítě se obě hlavičky mažou; klíč jde pouze na chatovací server.

Záloha přes HTTP přes vaši doménu

Pokud síť návštěvníka nepropustí WebSocket, widget automaticky přepne na zálohu přes HTTP. Používá stejnou cestu /rc_wss/ a nepotřebuje v proxy další položku. Jsou potřeba dvě věci:

Šablony

Šablony níže odpovídají těm na stránce účtu. Stránka účtu už vyplňuje hostitele, cílové adresy platné pro váš účet a — ihned po vytvoření — váš klíč. Nejlepší je proto zkopírovat šablonu odtamtud; zdejší verze slouží jako reference. Zástupné hodnoty jsou chat.your-domain.com, SITE_KEY a __RC_PROXY_KEY__.

nginx

Patří do kontextu http, například jako /etc/nginx/conf.d/chat.your-domain.com.conf. Na RHEL a CentOS je sada certifikátů CA v /etc/pki/tls/certs/ca-bundle.crt namísto /etc/ssl/certs/ca-certificates.crt.

# reactive.chat - own domain (first-party proxy) for site key SITE_KEY
# Host: chat.your-domain.com
#
# Needs nginx >= 1.7 with the ssl module. Put this file into the http
# context (e.g. /etc/nginx/conf.d/chat.your-domain.com.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.your-domain.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-domain.com;

    ssl_certificate     /etc/letsencrypt/live/chat.your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/chat.your-domain.com/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

Šablona obsahuje pouze VirtualHost pro port 443. Přesměrování z portu 80 a certifikát nastavte stejně jako u ostatních hostitelů. SSLProxyVerifyDepth 5 je nutné: bez něj Apache ověřuje řetězec certifikátů cíle pouze do jedné úrovně a připojení selže s „Certificate Chain too long“.

# reactive.chat - own domain (first-party proxy) for site key SITE_KEY
# Host: chat.your-domain.com
#
# 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.your-domain.com

    # 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.your-domain.com_access.log combined env=!rc_no_log

    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/chat.your-domain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/chat.your-domain.com/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 si certifikát získá sám; WebSocket nepotřebuje další nastavení. header_up s hodnotou nahrazuje cokoli, co prohlížeč odeslal pod daným názvem.

# reactive.chat - own domain (first-party proxy) for site key SITE_KEY
# Host: chat.your-domain.com
#
# 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.your-domain.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
            }
            # 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
            }
        }
    }
}

Klíč proxy

Řešení problémů

HTTP 421 (Misdirected Request)

Náš server odmítá hlavičku Host: proxy odesílá váš vlastní název místo názvu cíle. Hlavička Host a SNI musí obsahovat název cíle — v nginx proxy_set_header Host plus proxy_ssl_server_name on s proxy_ssl_name, v Apache ProxyPreserveHost Off, v Caddy header_up Host a tls_server_name.

HTTP 502 nebo chyby SSL směrem k cíli

Proxy nedokáže navázat připojení TLS k nám nebo nedůvěřuje certifikátu.

HTTP 413 při nahrávání příloh

Nahrávání probíhá přes /rc_wss/. Bez vlastního nastavení nginx přijímá pouze 1 MB; šablona proto v části /rc_wss/ nastavuje client_max_body_size 32m. Pokud je před proxy nástroj pro vyvažování zátěže nebo CDN, potřebuje alespoň stejný limit.

Připojení chatu bez upgradu

Kontrola hlásí „Chybí upgrade na WebSocket“ se stavem HTTP, který místo něj přijala. Chat pak pokračuje přes zálohu přes HTTP, ale připojí se až po dvou neúspěšných pokusech o WebSocket.

HTTP 401 nebo 403 u offline formuláře

DNS směřuje na soukromou adresu

Kontrola hlásí neveřejnou adresu, pokud je alespoň jedna adresa názvu soukromá, místní či vyhrazená (například 10.0.0.0/8, 192.168.0.0/16, 100.64.0.0/10 nebo fc00::/7). Častou příčinou je záznam z interního DNS nebo interní nástroj pro vyvažování zátěže. Ani vaši návštěvníci takové adresy nemohou dosáhnout; veřejný záznam musí směřovat na veřejnou adresu.

Ruční kontrola

Kontrolní adresu z kroku 3 můžete zavolat sami:

curl -s https://chat.your-domain.com/rc_wss/eigene-domain-probe

Při správném nastavení je odpověď:

{"rc":"eigene-domain-probe","v":1,"schluessel":"gueltig","client_ip":"gesetzt","site":"SITE_KEY","host":"chat.your-domain.com"}

Hodnoty jsou německá slova: schluessel (klíč) je gueltig (platný), unbekannt (neznámý) nebo fehlt (chybí); client_ip je gesetzt (nastaveno), fehlt (chybí) nebo ungueltig (neplatné). site a host jsou zahrnuté pouze s platným klíčem. Odpověď nikdy neobsahuje adresu.

Více v dokumentaci

Podrobně: Vlastní doména a first-party proxy. Všechny kapitoly jsou v dokumentaci.

Cập nhật lần cuối: