Hvernig aðstoðum við?

Segðu okkur stuttlega um hvað málið snýst – við höfum samband í tölvupósti.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
Á upphafssíðuna

Own domain and first-party proxy

How to serve widget files, chat connection, offline form and Smart Answer through a subdomain of your website – with a proxy key, the real visitor address and ready-made templates for nginx, Apache and Caddy.

With your own domain, the chat runs through a subdomain of your website, for example chat.your-company.com. Your server accepts the widget's requests and passes them on to reactive.chat as a reverse proxy. This page is for the person who runs that server. The short version for editors is under Own domain (first-party).

What runs through the subdomain

What you gain:

What it is not:

Requirements

Setup

  1. In your account, open the project, section Embed → Set up your own domain.
  2. Under 1. Host, enter the name, for example chat.your-company.com, and save.
  3. Under 2. Proxy key, click Create key. The key starts with rcpx_ and is shown exactly once; only a hash is stored. It belongs solely in the proxy configuration – never in a web page, a browser script or a repository.
  4. Under 3. Server configuration, take the template for your server. Right after creating the key, it contains the key; later it shows __RC_PROXY_KEY__. Test the configuration (nginx -t or apachectl configtest) and reload the server.
  5. Under 5. Check, click Check now (at most every 10 seconds). No message is created.
  6. Only when all five check steps show “OK” do you replace the embed snippet with the one from 4. Embed snippet:
<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>

The widget takes the location of its files from src, the chat connection from data-rc-ws-url, and derives from it the addresses of the offline form, uploads and HTTP fallback. All other attributes stay as they are (Script tag reference).

What the proxy must forward

For all routes:

For /rc_wss/, /api/offline/ and /api/suche/, the proxy sets two headers on every request:

“Sets” means: whatever a browser sends under these names is overwritten. On the route to the delivery network, both are cleared.

Behind a load balancer or CDN, your proxy first sees that device's address. In that case, set up taking over the real address: nginx real_ip (set_real_ip_from, real_ip_header), Apache mod_remoteip (RemoteIPHeader, RemoteIPTrustedProxy), Caddy trusted_proxies and {client_ip} instead of {remote_host}. The check does not detect this case – it only sees that a valid address is set.

nginx template

The account page already fills in host, target addresses and key – it is best to copy the template from there. The version here is for reference; the placeholders are chat.your-company.com, SITE_KEY and __RC_PROXY_KEY__. On RHEL/CentOS the CA bundle is at /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 template (2.4.47 or later)

Only the VirtualHost for port 443; set up the redirect from port 80 and the certificate as for your other hosts. SSLProxyVerifyDepth 5 is required – otherwise Apache checks the target's chain only one level deep and reports “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 before 2.4.47 does not know upgrade=websocket. In that case, replace the first ProxyPass line with:

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 template

header_up with a value replaces whatever the browser sent under this name. If you switch on access logs, exclude /rc_wss/h/* (log_skip, before 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
            }
        }
    }
}

The five check steps

Each step shows “OK”, “Error”, “Note” or “not checked”. The check has passed only with five times “OK”. Checks use HTTPS on port 443 only, without redirects, 5 seconds per step.

  1. Name resolution – A/AAAA present, all addresses public. All following steps connect to exactly this address.
  2. loader.js via your domain – the file is loaded and compared with ours. Without a connection, an answer or a valid certificate, the remaining steps are skipped. A redirect is an error; a differing file points to a cache or a wrong target for /.
  3. Key and visitor address – call of /rc_wss/eigene-domain-probe. Possible errors: X-RC-Proxy-Key is missing; key unknown (right after creating it, a delay of up to 30 seconds); X-RC-Client-IP is missing or invalid; the key belongs to another project. A note if the key is valid but registered for a different host.
  4. WebSocket – wss://chat.your-company.com/rc_wss/ must answer with HTTP 101 and the subprotocol rc.v1.
  5. Offline form – GET /api/offline/SITE_KEY must answer with 405 (the endpoint only accepts POST; that way no message is created).

You can call the check address from step 3 yourself:

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

When set up correctly:

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

The proxy key

Troubleshooting

Next: Transport and protocol · Security and CSP

Síðast uppfært: