Paano kami makakatulong?

Sabihin sa amin nang maikli kung tungkol saan ito—babalikan ka namin sa email.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
Pumunta sa panimulang page

Domaine personnalisé (première partie)

Distribuer le widget, la connexion du chat et le formulaire hors ligne depuis un sous-domaine de votre site : prérequis, configuration, modèles nginx, Apache et Caddy, dépannage.

Avec un domaine personnalisé, le chat passe par un sous-domaine de votre site, par exemple chat.your-domain.com. Votre serveur reçoit les requêtes du widget et les transmet à reactive.chat comme proxy inverse. Cette page s’adresse à la personne qui administre ce serveur.

Ce qu’apporte un domaine personnalisé

Les éléments suivants passent par votre sous-domaine :

Conséquences :

Ce que ce n’est pas

Prérequis

Derrière un répartiteur de charge ou un CDN, votre proxy voit d’abord l’adresse de cet équipement au lieu de celle du visiteur. Configurez alors la récupération de l’adresse réelle : module real_ip de nginx (set_real_ip_from, real_ip_header), mod_remoteip d’Apache (RemoteIPHeader, RemoteIPTrustedProxy), option trusted_proxies de Caddy et variable {client_ip} à la place de {remote_host}. Notre vérification ne peut pas détecter ce cas : elle voit seulement qu’une adresse valide est définie, pas de quelle adresse il s’agit.

Configuration étape par étape

  1. Ouvrir la page. Ouvrez le projet dans votre compte. Dans la section « Intégration », vous trouverez le lien Configurer un domaine personnalisé.
  2. Saisir l’hôte. Sous « 1. Hôte », saisissez le nom, par exemple chat.your-domain.com, puis enregistrez.
  3. Créer la clé. Sous « 2. Clé du proxy », cliquez sur Créer une clé. La clé commence par rcpx_ et n’est affichée qu’une seule fois ; nous n’en conservons qu’un hachage. Copiez-la immédiatement. Elle est secrète et doit figurer uniquement dans la configuration du proxy, jamais dans une page web, un script de navigateur ou un dépôt.
  4. Insérer le modèle. Sous « 3. Configuration du serveur », vous trouverez des modèles prêts à l’emploi pour nginx, Apache et Caddy. Juste après la création de la clé, ils la contiennent déjà ; ensuite, ils affichent __RC_PROXY_KEY__, à remplacer par la clé. Adaptez les chemins des certificats si nécessaire, testez la configuration (nginx -t ou apachectl configtest) et rechargez le serveur.
  5. Vérifier. Sous « 5. Vérifier », cliquez sur Vérifier maintenant. Nous appelons votre sous-domaine depuis l’extérieur et vérifions séparément cinq voies (voir ci-dessous). Aucun message n’est créé. Il faut attendre au moins 10 secondes avant une nouvelle vérification.
  6. Remplacer le code. Uniquement lorsque les cinq étapes indiquent « OK », remplacez le code d’intégration actuel de votre site par celui de « 4. Code d’intégration ».

Le nouveau code se présente ainsi : les deux adresses pointent vers votre sous-domaine.

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

Le widget déduit l’emplacement de ses fichiers de src et la connexion du chat de data-rc-ws-url, puis en déduit l’adresse du formulaire hors ligne. Les autres attributs, comme data-rc-locale, restent inchangés ; ils sont décrits sous Intégrer le widget. Le code de la page du compte contient aussi votre couleur de marque.

Les cinq étapes de vérification

Chaque étape indique « OK », « Erreur », « Remarque » ou « non vérifié ». La vérification n’est réussie que si les cinq indiquent « OK » ; une remarque ne vaut pas réussite. Les contrôles utilisent uniquement HTTPS sur le port 443, ne suivent pas les redirections et disposent de 5 secondes chacun.

  1. Résolution de nom. Le nom doit posséder un enregistrement DNS et toutes ses adresses doivent être publiques. L’absence d’enregistrements A et AAAA est signalée, de même que toute adresse privée, locale ou réservée : nous ne vérifions pas ces adresses. Toutes les étapes suivantes se connectent exactement à l’adresse vérifiée ici.
  2. loader.js via votre domaine. Nous chargeons https://chat.your-domain.com/loader.js et comparons le fichier au nôtre. En l’absence de connexion, de réponse ou de certificat valide, les étapes restantes sont ignorées (« non vérifié »). Une redirection renvoyée à la place du fichier est une erreur. Si le fichier diffère du nôtre, la cause est généralement un cache du proxy ou une mauvaise cible pour /.
  3. Clé et adresse du visiteur. Nous appelons une adresse de vérification sous /rc_wss/. Notre serveur indique s’il a reçu une clé et une adresse de visiteur valides, et à quel projet appartient la clé. Erreurs possibles : en-tête X-RC-Proxy-Key absent ; clé inconnue (erreur de saisie, clé obsolète ou supprimée ; juste après sa création, la prise en compte peut prendre jusqu’à 30 secondes) ; en-tête X-RC-Client-IP absent ou sans adresse valide ; clé appartenant à un autre projet. Une remarque apparaît si la clé est valide mais enregistrée pour un autre hôte.
  4. Connexion du chat (WebSocket). Nous ouvrons une connexion WebSocket via wss://chat.your-domain.com/rc_wss/ et attendons HTTP 101 avec le protocole rc.v1. « Pas de mise à niveau WebSocket » signifie que le proxy ne transmet pas les en-têtes Upgrade et Connection.
  5. Formulaire hors ligne. Nous appelons https://chat.your-domain.com/api/offline/SITE_KEY avec GET. Notre point de terminaison répond HTTP 405, car il n’accepte que POST : cela confirme que la requête nous parvient, sans créer de message. Autres résultats : origine rejetée (remarque, voir dépannage), projet inactif, cible exigeant une authentification (HTTP 401).

Les étapes 2 à 5 peuvent aussi signaler HTTP 421 (en-tête Host, voir dépannage). Si l’étape 3 ou 5 indique « La réponse ne vient pas de reactive.chat », ce chemin pointe vers une mauvaise cible dans votre proxy.

Ce que le proxy doit transmettre

Pour les trois voies :

Pour /rc_wss/ et /api/offline/, le proxy définit aussi deux en-têtes sur chaque requête :

« Définit » signifie que tout ce qu’un navigateur envoie sous ces noms est écrasé et ne nous parvient jamais. Sur la voie du réseau de distribution, les deux en-têtes sont vidés ; la clé ne va qu’au serveur de chat.

Repli HTTP via votre domaine

Si le réseau d’un visiteur ne laisse pas passer WebSocket, le widget passe automatiquement au repli HTTP. Il utilise le même chemin /rc_wss/ et ne nécessite aucune entrée supplémentaire dans le proxy. Deux conditions sont nécessaires :

Les modèles

Les modèles ci-dessous correspondent à ceux de la page du compte. Celle-ci renseigne déjà votre hôte, les adresses cibles valides pour votre compte et, juste après sa création, votre clé. Il est donc préférable de copier le modèle depuis cette page ; les versions ci-dessous servent de référence. Les valeurs à remplacer sont chat.your-domain.com, SITE_KEY et __RC_PROXY_KEY__.

nginx

À placer dans le contexte http, par exemple sous /etc/nginx/conf.d/chat.your-domain.com.conf. Sur RHEL et CentOS, le bundle d’autorités de certification se trouve dans /etc/pki/tls/certs/ca-bundle.crt au lieu de /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

Le modèle contient uniquement le VirtualHost du port 443. Configurez la redirection du port 80 et le certificat comme pour vos autres hôtes. SSLProxyVerifyDepth 5 est nécessaire : sans ce réglage, Apache ne vérifie qu’un niveau de la chaîne de certificats de la cible et la connexion échoue avec « 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 obtient lui-même le certificat ; WebSocket ne nécessite aucun réglage supplémentaire. header_up avec une valeur remplace ce que le navigateur a envoyé sous ce nom.

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

La clé du proxy

Dépannage

HTTP 421 (Misdirected Request)

Notre serveur rejette l’en-tête Host : votre proxy envoie votre propre nom au lieu du nom de la cible. L’en-tête Host et le SNI doivent correspondre au nom de la cible : dans nginx, proxy_set_header Host et proxy_ssl_server_name on avec proxy_ssl_name ; dans Apache, ProxyPreserveHost Off ; dans Caddy, header_up Host et tls_server_name.

HTTP 502 ou erreurs SSL vers la cible

Le proxy ne peut pas établir la connexion TLS à nos serveurs ou ne fait pas confiance au certificat.

HTTP 413 lors de l’envoi de pièces jointes

Les envois passent par /rc_wss/. Sans réglage spécifique, nginx n’accepte que 1 Mo ; le modèle définit donc client_max_body_size 32m dans la section /rc_wss/. Si un répartiteur de charge ou un CDN précède votre proxy, sa limite doit être au moins aussi élevée.

Connexion du chat sans mise à niveau

La vérification signale « Pas de mise à niveau WebSocket » avec l’état HTTP reçu à la place. Le chat continue alors via le repli HTTP, mais ne se connecte qu’après deux tentatives WebSocket échouées.

HTTP 401 ou 403 sur le formulaire hors ligne

Le DNS pointe vers une adresse privée

La vérification signale une adresse non publique si au moins une adresse du nom est privée, locale ou réservée (par exemple 10.0.0.0/8, 192.168.0.0/16, 100.64.0.0/10 ou fc00::/7). Les causes courantes sont un enregistrement DNS interne ou un répartiteur de charge interne. Vos visiteurs ne peuvent pas non plus accéder à ces adresses ; l’enregistrement public doit pointer vers une adresse publique.

Vérifier manuellement

Vous pouvez appeler vous-même l’adresse de vérification de l’étape 3 :

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

Avec une configuration correcte, la réponse est :

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

Les valeurs sont des mots allemands : schluessel (clé) vaut gueltig (valide), unbekannt (inconnue) ou fehlt (absente) ; client_ip vaut gesetzt (définie), fehlt (absente) ou ungueltig (invalide). site et host ne sont présents qu’avec une clé valide. La réponse ne contient jamais d’adresse.

Pour en savoir plus dans la documentation

Pour approfondir : Domaine personnalisé et proxy de première partie. Retrouvez tous les chapitres dans la documentation.

Huling na-update: