独自ドメイン(ファーストパーティー)
Webサイトのサブドメインからウィジェット、チャット接続、オフラインフォームを配信します。要件、設定、nginx・Apache・Caddy用テンプレート、問題の解決方法を説明します。
独自ドメインでは、chat.your-domain.comなど、Webサイトのサブドメインを通してチャットを運用します。運営側のサーバーがウィジェットのリクエストを受け、リバースプロキシとしてreactive.chatに転送します。このページは、そのサーバーの管理者向けです。
独自ドメインでできること
次の通信がサブドメインを経由します。
- ウィジェットのファイル(
loader.jsと、その後に読み込むコア) - 添付ファイルを含むチャット接続(WebSocket)
- チャット接続を確立できない場合に使うオフラインフォーム
その結果、次のようになります。
- 第三者のドメインへのリクエストがありません。 これらの経路では、訪問者のブラウザーはreactive.chatのドメインではなく、運営側のサブドメインとだけ通信します。
- 広告ブロッカー。 ドメイン名でブロックするフィルターリストが、reactive.chatのドメインを基にチャットを識別できなくなります。
- Content Security Policyのアドレスを1つにできます。
script-srcとconnect-srcには、reactive.chatのアドレスの代わりに運営側のサブドメインを指定します。connect-srcには、チャット接続用のwss://と、オフラインフォーム、アップロード、HTTPフォールバック(プロキシがWebSocketをブロックした場合)用のhttps://の2つの形式が必要です。 - 実際の訪問者のアドレスが届きます。 プロキシは、秘密のキーで保護した専用ヘッダーで訪問者のアドレスを当社に伝えます。不正利用対策(頻度制限とブロック)は、プロキシ単位ではなく訪問者単位で数え、会話には訪問者のアドレスが表示されます。
独自ドメインで変わらないこと
- セルフホスティングではありません。 運営側のサーバーは転送するだけです。会話、添付ファイル、設定は、独自ドメインを使わない場合とまったく同じように、reactive.chatで処理・保存します。
- 同意の要否を示すものではありません。 訪問者の同意が必要か、何に必要かは別の問題です。独自ドメインでも、データの処理者は変わりません。プライバシーポリシー用の文言は、プライバシーポリシー用の文例にあります。
- 運営側のサーバーから通信内容が見えます。 訪問者のTLS接続はプロキシで終端します。メッセージと添付ファイルはそこで一時的に復号され、再暗号化して当社に転送されます。プロキシでリクエスト本文をログに記録しないでください。
要件
- 独自のサーバーまたはリバースプロキシがあり、インターネットからポート443のHTTPSで到達でき、外向きのHTTPS接続も開始できること。nginx(sslモジュール付き)、Apache 2.4.47以降、Caddy 2用のテンプレートがあります。
- Apacheの場合: mod_ssl、mod_proxy、mod_proxy_http、mod_proxy_wstunnel、mod_headersの各モジュール。Apacheが
upgrade=websocketに対応するのは2.4.47以降です。それ以前のバージョンには、テンプレート末尾にmod_rewriteを使う代替方法があります。 - チャット専用のサブドメイン(
chat.your-domain.comなど)。チャットにはホスト全体が必要で、www.your-domain.com/chat/のようなパスは使えません。名前だけを入力し、https://, ポート、パスは付けません。IPアドレス、.local、.lan、.internalなどの内部用の末尾、reactive.chat配下の名前は使えません。 - Webサイトと同じドメインであること。 埋め込み先のWebサイトと同じドメインに属するサブドメインの場合だけ、チャットはファーストパーティーになります。それ以外でも動作しますが、アカウントページに違いが表示されます。
- DNSレコード(A、AAAAのいずれか、または両方)がサーバーを指していること。その名前のすべてのアドレスが公開アドレスである必要があります。
- サブドメインのTLS証明書。nginxとApacheのテンプレートはcertbot(Let’s Encrypt)のパスを想定し、Caddyは自動で証明書を取得します。
- reactive.chatアカウントでプロジェクトを編集する権限があること。
ロードバランサーやCDNの背後では、プロキシに最初に見えるのは訪問者ではなく、その機器のアドレスです。その場合は、実際の訪問者のアドレスを引き継ぐように設定します。nginxではreal_ipモジュール(set_real_ip_from、real_ip_header)、Apacheではmod_remoteip(RemoteIPHeader、RemoteIPTrustedProxy)、Caddyではtrusted_proxiesオプションと、{remote_host}の代わりに{client_ip}プレースホルダーを使います。当社の確認では、この状況を検出できません。有効なアドレスが設定されているかは分かりますが、どのアドレスかまでは分かりません。
設定手順
- ページを開きます。 アカウントでプロジェクトを開きます。「埋め込み」セクションに独自ドメインを設定リンクがあります。
- ホストを入力します。 「1. ホスト」に
chat.your-domain.comなどの名前を入力し、保存します。 - キーを作成します。 「2. プロキシキー」でキーを作成をクリックします。キーは
rcpx_で始まり、表示されるのは1回だけです。当社はハッシュだけを保存します。すぐにコピーしてください。秘密情報であり、プロキシの設定だけに置きます。Webページ、ブラウザーのスクリプト、リポジトリには絶対に含めないでください。 - テンプレートを挿入します。 「3. サーバー設定」に、nginx、Apache、Caddy用のテンプレートがあります。キーの作成直後には実際のキーが入り、その後は
__RC_PROXY_KEY__が表示されるので、キーに置き換えます。必要なら証明書のパスを調整し、設定をテストして(nginx -tまたはapachectl configtest)、サーバーを再読み込みします。 - 確認します。 「5. 確認」で今すぐ確認をクリックします。当社が外部からサブドメインを呼び出し、5つの経路を個別に確認します(下記参照)。メッセージは作成しません。再確認は、早くても10秒後に可能です。
- スニペットを置き換えます。 5つのステップがすべて「OK」になってから、Webサイトの既存の埋め込みスニペットを、「4. 埋め込みスニペット」のものに置き換えます。
新しいスニペットは次のようになり、両方のアドレスがサブドメインを指します。
<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>
ウィジェットはsrcからファイルの場所を、data-rc-ws-urlからチャット接続先を取得し、そこからオフラインフォームのアドレスを導きます。data-rc-localeなどの他の属性はそのままで、ウィジェットの埋め込みで説明しています。アカウントページのスニペットには、ブランドの色も含まれています。
5つの確認ステップ
各ステップには「OK」「エラー」「注意」「未確認」が表示されます。5つすべてが「OK」の場合だけ合格です。注意は合格にはなりません。確認はポート443のHTTPSだけを使用し、リダイレクトを追跡せず、各ステップの制限時間は5秒です。
- 名前解決。 DNSレコードが存在し、すべてのアドレスが公開アドレスである必要があります。AもAAAAも見つからない場合や、1つでもプライベート、ローカル、予約済みのアドレスがある場合は報告します。そのようなアドレスは確認しません。以降のすべてのステップは、ここで確認したアドレスに正確に接続します。
- 独自ドメイン経由のloader.js。
https://chat.your-domain.com/loader.jsを読み込み、当社のファイルと比較します。接続、応答、有効な証明書のいずれかが得られない場合は、残りをスキップします(「未確認」)。プロキシがファイルではなくリダイレクトを返した場合はエラーです。当社のファイルと異なる場合は、プロキシのキャッシュや/の転送先の誤りが一般的な原因です。 - キーと訪問者のアドレス。
/rc_wss/配下の確認用アドレスを呼び出します。当社のサーバーは、有効なキーと訪問者のアドレスを受信したか、キーがどのプロジェクトに属するかを返します。考えられるエラーは、X-RC-Proxy-Keyヘッダーがない、キーが不明(入力ミス、古い、削除済み。作成直後は最大30秒かかる場合があります)、X-RC-Client-IPヘッダーがない、または有効なアドレスを含まない、キーが別のプロジェクトに属する、というものです。キーは有効でも別のホストに登録されている場合は、注意が表示されます。 - チャット接続(WebSocket)。
wss://chat.your-domain.com/rc_wss/経由でWebSocket接続を開き、rc.v1プロトコルでHTTP 101が返ることを期待します。「WebSocketへのアップグレードなし」は、プロキシがUpgradeヘッダーとConnectionヘッダーを転送していないことを意味します。 - オフラインフォーム。
https://chat.your-domain.com/api/offline/SITE_KEYをGETで呼び出します。エンドポイントはPOSTだけを受け付けるため、HTTP 405で応答します。これにより、メッセージを作成せずに到達を確認できます。他の結果には、オリジンの拒否(注意。トラブルシューティング参照)、プロジェクトが無効、転送先が認証を要求(HTTP 401)があります。
ステップ2~5では、HTTP 421も返ることがあります(Hostヘッダー。トラブルシューティング参照)。ステップ3または5で「reactive.chatからの応答ではありません」と表示された場合は、プロキシのそのパスが誤った転送先を指しています。
プロキシが転送する必要のある内容
/rc_wss/をreactive.chatのチャットサーバーへ転送し、WebSocketへのアップグレードと長いタイムアウトを設定します(テンプレートは3,600秒)。ファイルのアップロードも同じパスを使い、プランに応じて1ファイル最大32 MBです。/api/offline/を同じサーバーへ転送します。ウィジェットはこの経路でオフラインフォームを送信します。- その他はすべてreactive.chatの配信ネットワークへ転送します。
loader.jsなどのウィジェットファイルはそこから配信します。
3つの経路すべてに、次を適用します。
- HostヘッダーとSNIには転送先の名前を指定します。 運営側のサブドメインではありません。当社のサーバーは不明なホストにHTTP 421を返します。
- 転送先の証明書を検証します。
- Cookieや認証情報を転送しません。 ブラウザーの
CookieヘッダーとAuthorizationヘッダーを転送しません。 - リダイレクトしません。 キャッシュは不要です。追加する場合は、ファイル名にバージョン番号がない
loader.jsのキャッシュ期間を短くしてください。
/rc_wss/と/api/offline/では、プロキシが各リクエストに2つのヘッダーを設定します。
X-RC-Proxy-Key– 運営側のキー。X-RC-Client-IP– プロキシから見た訪問者のアドレス。
「設定する」とは、ブラウザーがこれらの名前で送った値を上書きし、当社には一切届かないようにすることです。配信ネットワークへの経路では、両方のヘッダーを削除します。キーを送るのはチャットサーバーだけです。
独自ドメイン経由のHTTPフォールバック
訪問者のネットワークがWebSocketを通さない場合、ウィジェットは自動的にHTTPフォールバックに切り替えます。同じ/rc_wss/パスを使うため、プロキシに追加の項目は不要です。次の2点が必要です。
- 応答をバッファリングせずに転送します。 プロキシは
/rc_wss/の応答を直ちに転送する必要があります。nginxではproxy_buffering offとproxy_cache off、Apacheではflushpackets=on、Caddyではflush_interval -1を設定します。下のテンプレートには含まれています。 - Content Security PolicyでHTTPSを許可します。
connect-srcにはサブドメインをwss://とhttps://, 両方の形式で指定します。たとえばconnect-src 'self' wss://chat.your-domain.com https://chat.your-domain.com.
テンプレート
以下のテンプレートは、アカウントページのものと対応しています。アカウントページでは、ホスト、アカウントで有効な転送先アドレス、キーの作成直後であればキーも入力済みです。そのため、そちらからコピーすることをお勧めします。 ここに掲載するものは参照用です。プレースホルダーはchat.your-domain.com、SITE_KEY、__RC_PROXY_KEY__です。
nginx
httpコンテキストに配置します。たとえば/etc/nginx/conf.d/chat.your-domain.com.confです。RHELとCentOSのCAバンドルは、/etc/ssl/certs/ca-certificates.crtではなく/etc/pki/tls/certs/ca-bundle.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
テンプレートに含まれるのは、ポート443のVirtualHostだけです。ポート80からのリダイレクトと証明書は、他のホストと同じように設定してください。SSLProxyVerifyDepth 5が必要です。指定しないと、Apacheは転送先の証明書チェーンを1段階しか検証せず、「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は証明書を自動で取得し、WebSocketに追加設定は不要です。値付きのheader_upは、ブラウザーが同じ名前で送った内容を置き換えます。
# 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
}
}
}
}
プロキシキー
- ローテーション。 新しいキーを作成は、直ちに新しいキーを発行します。以前のキーは24時間有効なので、中断せずに新しいキーへ置き換えられます。その後、再確認してください。有効なキーは最大2つです。24時間以内に再度ローテーションすると、最も古いキーは直ちに無効になります。
- 削除。 キーを削除は、キーと、ローテーション後にまだ有効な古いキーを直ちに無効にします。独自ドメインを削除は、ホストとキーをまとめて削除します。先にWebサイトのスニペットを通常の形式に戻してください。
- キーがない、または誤っている場合も、チャットは動作し続けます。2つのヘッダーを評価しなくなるだけです。ただし、すべての訪問者がプロキシのアドレスで表示されます。不正利用対策はアドレスごとに接続とリクエストを数えるため、プロキシ全体が頻度制限やブロックの対象となり、すべての訪問者に同時に影響する場合があります。オフラインフォームにも同じことが当てはまります。
- 1つのキーに1つのプロジェクト。 キーは、厳密に1つのプロジェクトと登録済みホストに属します。有効なキーを持つプロキシを通して、別のプロジェクトのサイトキーを持つウィジェットが接続すると、チャット接続は拒否されます。別のプロジェクトには、独自のサブドメインとキーを設定してください。
- キーが漏えいした場合: キーを知る人は、運営側のプロジェクトで任意の訪問者アドレスを指定できます。キーを削除し、新しいキーを作成してプロキシに設定してください。それまでもチャットは動作し続けますが、プロキシのアドレスで表示されます。
トラブルシューティング
HTTP 421(Misdirected Request)
当社のサーバーがHostヘッダーを拒否しています。プロキシが転送先ではなく、自身の名前を送っています。HostヘッダーとSNIには、転送先の名前が必要です。nginxではproxy_set_header Hostと、proxy_ssl_nameを指定したproxy_ssl_server_name on、ApacheではProxyPreserveHost Off、Caddyではheader_up Hostとtls_server_nameを使います。
転送先とのHTTP 502またはSSLエラー
プロキシが当社とのTLS接続を確立できないか、証明書を信頼していません。
- Apache: エラーログに「Certificate Chain too long」とある場合は、
SSLProxyVerifyDepth 5がありません。 - nginx:
proxy_ssl_trusted_certificateのパスは正しいですか(RHELとCentOSは上記参照)。proxy_ssl_server_name onは設定されていますか。 - 共通: サーバーでポート443への外向き接続が許可されている必要があります。
添付ファイルのアップロードでHTTP 413
アップロードは/rc_wss/を経由します。個別に設定しないとnginxは1 MBしか受け付けないため、テンプレートでは/rc_wss/セクションにclient_max_body_size 32mを設定しています。プロキシの前にロードバランサーやCDNがある場合は、少なくとも同じ上限が必要です。
アップグレードされないチャット接続
確認で「WebSocketへのアップグレードなし」と、代わりに受信したHTTPステータスが表示されます。この場合、チャットはHTTPフォールバックで続行しますが、WebSocketが2回失敗してから接続します。
- nginx:
/rc_wss/セクションにproxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade"が必要です。 - Apache: 2.4.47以降で
upgrade=websocketを指定し、mod_proxy_wstunnelを有効にします。古いバージョンでは、テンプレート末尾の代替方法を使います。 - 手前の機器: プロキシの前にあるCDNやロードバランサーも、WebSocketを通す必要があります。
オフラインフォームでHTTP 401または403
- 401: 経路上の何かが認証を求めています。通常は、プロキシのホストに設定したパスワード保護です。
/api/offline/は認証なしで到達できる必要があります。 - 403、オリジンに関する注意: リクエストは当社に届いていますが、オリジンがプロジェクトと一致しません。プロジェクトの「許可するオリジン」には、チャットのサブドメインではなく、チャットを埋め込むWebサイトのドメインを含めてください。
- 403と「reactive.chatからの応答ではありません」: Webアプリケーションファイアウォールやサーバーのアクセスルールなど、手前の何かが拒否しています。
DNSがプライベートアドレスを指す
その名前のアドレスに1つでもプライベート、ローカル、予約済みのアドレス(10.0.0.0/8、192.168.0.0/16、100.64.0.0/10、fc00::/7など)があると、非公開アドレスとして報告します。内部DNSのレコードや内部ロードバランサーが一般的な原因です。訪問者もそのようなアドレスには到達できません。公開レコードは公開アドレスを指す必要があります。
手動で確認する
ステップ3の確認用アドレスを自分で呼び出すこともできます。
curl -s https://chat.your-domain.com/rc_wss/eigene-domain-probe
正しく設定されていれば、次の応答が返ります。
{"rc":"eigene-domain-probe","v":1,"schluessel":"gueltig","client_ip":"gesetzt","site":"SITE_KEY","host":"chat.your-domain.com"}
値はドイツ語です。schluessel(キー)はgueltig(有効)、unbekannt(不明)、fehlt(なし)のいずれかです。client_ipはgesetzt(設定済み)、fehlt(なし)、ungueltig(無効)のいずれかです。siteとhostは、キーが有効な場合だけ含まれます。応答にアドレスが含まれることはありません。
ドキュメントの関連項目
詳しくは、独自ドメインとファーストパーティープロキシをご覧ください。すべての章はドキュメントにあります。
最終更新: