Como podemos axudarlle?

Cóntenos brevemente de que se trata; responderémoslle por correo electrónico.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
Ir á páxina de inicio

Egen domän (förstapart)

Leverera widget, chattanslutning och offlineformulär från en underdomän till din webbplats – krav, konfiguration, mallar för nginx, Apache och Caddy samt felsökning.

Med egen domän körs chatten via en underdomän till din webbplats, till exempel chat.your-domain.com. Din server tar emot widgetens anrop och vidarebefordrar dem till reactive.chat som en omvänd proxy. Den här sidan är skriven för den som driver servern.

Vad egen domän gör

Det här går via din underdomän:

Det innebär:

Vad det inte är

Krav

Bakom en lastbalanserare eller ett CDN ser proxyn först den enhetens adress i stället för besökarens. Konfigurera då övertagande av den verkliga besökaradressen: i nginx modulen real_ip (set_real_ip_from, real_ip_header), i Apache mod_remoteip (RemoteIPHeader, RemoteIPTrustedProxy), i Caddy alternativet trusted_proxies och platshållaren {client_ip} i stället för {remote_host}. Vår kontroll kan inte upptäcka detta fall: den ser bara att en giltig adress anges, inte vilken.

Konfiguration steg för steg

  1. Öppna sidan. Öppna projektet i kontot. I avsnittet ”Inbäddning” finns länken Konfigurera egen domän.
  2. Ange värden. Under ”1. Värd” anger du namnet, till exempel chat.your-domain.com, och sparar.
  3. Skapa nyckeln. Under ”2. Proxynyckel” klickar du på Skapa nyckel. Nyckeln börjar med rcpx_ och visas exakt en gång; vi lagrar bara en hash av den. Kopiera den direkt. Den är hemlig och hör bara hemma i proxykonfigurationen – aldrig på en webbsida, i ett webbläsarskript eller i ett kodarkiv.
  4. Infoga mallen. Under ”3. Serverkonfiguration” finns färdiga mallar för nginx, Apache och Caddy. Direkt efter att du skapat nyckeln innehåller de den redan; senare visar de __RC_PROXY_KEY__, som du ersätter med nyckeln. Justera vid behov certifikatsökvägarna, testa konfigurationen (nginx -t eller apachectl configtest) och ladda om servern.
  5. Kontrollera. Under ”5. Kontroll” klickar du på Kontrollera nu. Vi anropar underdomänen utifrån och kontrollerar fem vägar separat (se nedan). Inget meddelande skapas. En ny kontroll är möjlig tidigast efter 10 sekunder.
  6. Byt ut inbäddningskoden. Först när alla fem steg visar ”OK” ersätter du den nuvarande koden på webbplatsen med den från ”4. Inbäddningskod”.

Den nya koden ser ut så här – båda adresserna pekar på din underdomän:

<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>

Widgeten hämtar filernas plats från src och chattanslutningen från data-rc-ws-url – och härleder offlineformulärets adress därifrån. Andra attribut som data-rc-locale förblir som de är; de beskrivs under Bädda in widgeten. Koden på kontosidan innehåller också profilfärgen.

De fem kontrollstegen

Varje steg visar ”OK”, ”Fel”, ”Information” eller ”inte kontrollerat”. Kontrollen är godkänd först när alla fem visar ”OK”; information räknas inte som godkänt. Kontrollerna använder bara HTTPS på port 443, följer inte omdirigeringar och varje steg har 5 sekunder.

  1. Namnuppslagning. Namnet måste ha en DNS-post och alla adresser måste vara publika. Det rapporteras om varken en A- eller AAAA-post hittas eller om minst en adress är privat, lokal eller reserverad – sådana adresser kontrollerar vi inte. Alla efterföljande steg ansluter till exakt den adress som kontrollerades här.
  2. loader.js via din domän. Vi hämtar https://chat.your-domain.com/loader.js och jämför filen med vår. Om ingen anslutning, inget svar eller inget giltigt certifikat erhålls hoppas återstående steg över (”inte kontrollerat”). Om proxyn svarar med en omdirigering i stället för filen är det ett fel. Om filen skiljer sig från vår är orsaken oftast en cache i proxyn eller fel mål för /.
  3. Nyckel och besökaradress. Vi anropar en kontrolladress under /rc_wss/. Vår server svarar om den fick en giltig nyckel och en giltig besökaradress samt vilket projekt nyckeln tillhör. Möjliga fel: huvudet X-RC-Proxy-Key saknas; nyckeln är okänd (felskriven, inaktuell eller borttagen – direkt efter att den skapats kan det ta upp till 30 sekunder); huvudet X-RC-Client-IP saknas eller innehåller ingen giltig adress; nyckeln tillhör ett annat projekt. Information visas om nyckeln är giltig men registrerad för en annan värd.
  4. Chattanslutning (WebSocket). Vi öppnar en WebSocket-anslutning via wss://chat.your-domain.com/rc_wss/ och förväntar oss HTTP 101 med protokollet rc.v1. ”Ingen WebSocket-uppgradering” betyder att proxyn inte vidarebefordrar huvudena Upgrade och Connection.
  5. Offlineformulär. Vi anropar https://chat.your-domain.com/api/offline/SITE_KEY med GET. Vår slutpunkt svarar med HTTP 405 eftersom den bara accepterar POST – det visar att anropet når oss utan att skapa ett meddelande. Andra resultat: ursprung avvisat (information, se felsökning), projektet inte aktivt, målet kräver autentisering (HTTP 401).

Steg 2 till 5 kan också rapportera HTTP 421 (Host-huvud, se felsökning). Om steg 3 eller 5 rapporterar ”Svaret kommer inte från reactive.chat” pekar sökvägen på fel mål i din proxy.

Vad proxyn måste vidarebefordra

För alla tre vägarna:

För /rc_wss/ och /api/offline/ sätter proxyn dessutom två huvuden på varje anrop:

”Sätter” betyder att allt en webbläsare skickar under dessa namn skrivs över och aldrig når oss. På vägen till leveransnätverket tas båda huvudena bort; nyckeln skickas bara till chattservern.

HTTP-reserv via din domän

Om besökarens nätverk inte släpper igenom WebSocket byter widgeten automatiskt till HTTP-reserven. Den använder samma sökväg /rc_wss/ och behöver ingen ytterligare post i proxyn. Två saker krävs:

Mallarna

Mallarna nedan motsvarar dem på kontosidan. Kontosidan fyller redan i värd, måladresser som gäller för ditt konto och – direkt efter att nyckeln skapats – nyckeln. Kopiera därför helst mallen därifrån; versionerna här är referens. Platshållare är chat.your-domain.com, SITE_KEY och __RC_PROXY_KEY__.

nginx

Hör hemma i http-kontexten, till exempel som /etc/nginx/conf.d/chat.your-domain.com.conf. På RHEL och CentOS finns CA-paketet på /etc/pki/tls/certs/ca-bundle.crt i stället för /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

Mallen innehåller bara VirtualHost för port 443. Konfigurera omdirigeringen från port 80 och certifikatet som för dina andra värdar. SSLProxyVerifyDepth 5 krävs: utan den kontrollerar Apache målets certifikatkedja bara ett steg djupt och anslutningen misslyckas med ”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 hämtar certifikatet själv; WebSocket behöver ingen extra inställning. header_up med ett värde ersätter allt webbläsaren skickade under det namnet.

# 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
            }
        }
    }
}

Proxynyckeln

Felsökning

HTTP 421 (Misdirected Request)

Vår server avvisar Host-huvudet: proxyn skickar ditt eget namn i stället för målets. Host-huvud och SNI måste vara målets namn – i nginx proxy_set_header Host plus proxy_ssl_server_name on med proxy_ssl_name, i Apache ProxyPreserveHost Off, i Caddy header_up Host och tls_server_name.

HTTP 502 eller SSL-fel mot målet

Proxyn kan inte upprätta TLS-anslutningen till oss eller litar inte på certifikatet.

HTTP 413 vid uppladdning av bilagor

Uppladdningar går via /rc_wss/. Utan egen inställning accepterar nginx bara 1 MB; mallen sätter därför client_max_body_size 32m i avsnittet /rc_wss/. Om en lastbalanserare eller ett CDN står framför proxyn behöver den minst samma gräns.

Chattanslutning utan uppgradering

Kontrollen rapporterar ”Ingen WebSocket-uppgradering” med den HTTP-status som kom i stället. Chatten fortsätter då via HTTP-reserven, men ansluter först efter två misslyckade WebSocket-försök.

HTTP 401 eller 403 för offlineformuläret

DNS pekar på en privat adress

Kontrollen rapporterar en icke-publik adress om minst en adress för namnet är privat, lokal eller reserverad (till exempel 10.0.0.0/8, 192.168.0.0/16, 100.64.0.0/10 eller fc00::/7). Vanliga orsaker är en post från intern DNS eller en intern lastbalanserare. Besökarna kan inte heller nå sådana adresser; den publika posten måste peka på en publik adress.

Kontrollera manuellt

Du kan själv anropa kontrolladressen från steg 3:

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

Med rätt konfiguration blir svaret:

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

Värdena är tyska ord: schluessel (nyckel) är gueltig (giltig), unbekannt (okänd) eller fehlt (saknas); client_ip är gesetzt (satt), fehlt (saknas) eller ungueltig (ogiltig). site och host ingår bara med giltig nyckel. Svaret innehåller aldrig en adress.

Läs mer i dokumentationen

På djupet: Egen domän och förstapartsproxy. Alla kapitel finns i dokumentationen.

Última actualización: