WebRTCとは
WebRTC(Web Real-Time Communication)は、ブラウザ同士でリアルタイムな音声・映像・データ通信を実現するためのオープン技術です。追加のプラグインやソフトウェアを必要とせず、JavaScriptのAPIだけでP2P通信を可能にする仕組みとして、Googleをはじめとした各社によって標準化が進められています。
WebRTCは、以下の3つの主要なコンポーネントから構成されます:
- getUserMedia:カメラやマイクなどのデバイスから音声・映像を取得するAPI。
- RTCPeerConnection:ピア同士の通信を確立し、メディアやデータをやり取りするコアAPI。
- RTCDataChannel:ファイル送信やチャットなどに利用可能なデータチャネル。
これらのAPIにより、ビデオ通話、音声会議、ファイル共有など多くのリアルタイムアプリケーションを開発可能です。しかしながら、実際の通信ではNAT越えやファイアウォールの問題があるため、STUN/TURN/TURNSといったNATトラバーサル技術の理解と導入が不可欠です。
STUN・TURN・TURNS の違いと役割
WebRTCで安定したピアツーピア接続を実現するには、NAT越え(NAT traversal)の仕組みが不可欠です。ここでは代表的な技術であるSTUN、TURN、およびTURNSについて、その技術的な違いや使用シーン、メリット・デメリットを詳しく解説します。
STUNは主にNAT環境下で自分の外部アドレスを知るためのプロトコルであり、TURNは直接接続ができない場合に中継サーバとして機能するプロトコルです。一方TURNSは、TURN通信をTLSで暗号化しHTTPSと同じ443番ポートで行う方式で、企業ネットワークなど厳しいファイアウォール下での通信を可能にします。
それぞれの特性を理解し、適切に使い分けることでWebRTC通信の成功率と品質を高めることができます。
STUN (UDP) の役割と特徴
STUN(Session Traversal Utilities for NAT)は、クライアントの外部IPアドレスとポートを知るためのシンプルなプロトコルです。例えばPCがNAT配下にある場合、自分自身ではグローバルIPを知りませんが、STUNサーバに問い合わせることで「外部から見た自分のIP:ポート」を取得できます。
STUNサーバは言わば鏡のような役割で、受け取ったリクエストの送信元情報をそのまま返信します。その結果、クライアントは自身のグローバルIPアドレスとNATによって割り当てられたポート番号(Server Reflexive候補)を知ることができます。
STUNの通信は通常UDPで行われ、デフォルトポートは3478番(UDP/3478)です。UDPでの軽量な単発通信で済むため、オーバーヘッドが小さく低遅延であり、サーバ側の負荷もほとんどありません。したがってUDP通信が許可されている環境では、まずSTUNによるNAT越えが試みられます。
STUNの使用シーン
自宅ネットワークやモバイル回線など、NAT越えは必要だがUDP通信自体はブロックされていない環境で有効です。STUNでお互いの外部IP:ポートを取得できれば、クライアント同士が直接(ピアツーピア)通信を確立できます。通信経路が直接になる分、遅延が少なく品質も高く維持できます。またサーバはIP情報のやり取りを手助けするだけなので、コストも非常に低く抑えられます。例えばオンラインゲームやビデオ通話で、双方のデバイスが比較的オープンなNATにいる場合、STUNで十分にピアツーピア接続が可能です。
STUNの限界とデメリット
STUNはあくまで「自分の外部アドレスを知る」ための手段であり、NATタイプやファイアウォールの制約によってはこれだけでは接続できません。特にシンメトリックNAT(対称型NAT)や厳格なファイアウォール環境では、STUNで得たアドレスでは相手からのパケットが届かず通信できないことがあります。
また企業ネットワークではUDP通信そのものがブロックされている場合もあり、その場合STUNリクエスト自体が届きません。要するに、STUNは「直接通信が可能かを判断する」ための仕組みであり、直接通信が物理的に不可能な環境では機能しません。そのためSTUNはICE(後述)において第一段階の候補取得に使われ、STUNで十分でない場合には後述するTURNへフォールバックする設計になっています。
TURN (UDP) の役割と特徴
TURN(Traversal Using Relays around NAT)は、STUNで直接通信ができない場合に中継リレーとして動作するプロトコルです。TURNサーバはグローバルにアクセス可能な中継ポイントとして、通信相手との間に入ってパケットを転送します。クライアントはTURNサーバに対して接続を行い、Relay候補と呼ばれる中継用のIPアドレスとポートを取得します。以後、そのTURNサーバ経由で相手とのメディアやデータのやり取りを行います。
TURNも通常はUDPで通信するため、UDPさえ通れば直接通信と近い形でメディアパケットを中継できます。デフォルトではSTUNと同じ3478番ポート(UDP)でTURNプロトコルを受け付けます。もしファイアウォールのポリシーでUDPのポート番号が限定されている場合でも、UDP/443のように許可されたポート上でTURNを動作させることもできます。UDPさえ使えれば、TCPよりもリアルタイム性の高い中継が可能です。
TURNの使用シーン
相手との直接接続がどうしても確立できない場合にTURNは不可欠です。例えば一方または双方が企業の厳格なファイアウォール内にいる場合や、シンメトリックNAT同士でUDPホールパンチが失敗する場合です。このような環境ではTURNサーバを介したリレーなしに通信を行うことはできないため、TURNはいわば最後の砦として機能します。
WebRTCでは全てのピアが直接通信できることを目指しますが、それが叶わない場合でもTURNにフォールバックすることで通信自体は継続可能となります。実際の運用では、まずSTUNで直接接続を試み、失敗した時のみTURNリレーに切り替えるのが一般的な戦略です。例えば社内ネットワーク越しのビデオ会議で、お互いが直接通信できない場合に自動的にTURNサーバ経由の通信に切り替わり、ユーザは意識せずとも会話を続行できるようになります。
TURNのメリット
最大の利点は確実性です。どんなNATやファイアウォール環境でも、クライアントからTURNサーバへの通信さえ確立できれば最終的にピア間通信を実現できます。またTURNはプロトコル上STUNの拡張でもあるため、単一のサーバ実装(後述のcoturnなど)でSTUNリクエストとTURNリクエストの両方を処理可能です。一度接続が確立してしまえば、以降のメディアはストリームとして中継されるため、利用者から見れば多少の遅延を除きシームレスな通信が行えます。
TURNのデメリット
最大の欠点はリソース消費と遅延です。TURNでは音声や映像データすべてがサーバを経由するため、サーバ側で多大な帯域と処理能力が必要になります。例えば1対1のビデオ通話で片方向1Mbpsの帯域を消費すると仮定すると、1000ユーザが同時利用すれば単純計算で1Gbpsもの中継帯域が必要になります。このためTURNサーバの運用コストは高く、大規模サービスでは多数のTURN中継サーバを用意しスケールさせる必要があります。
また通信経路が遠回りになることで遅延が増加し、映像・音声のタイムラグや品質低下を招きます。さらに、STUNによるピアツーピア通信に比べてTURN経由は厳密にはピアツーピアではなくなるため、機密性の観点でも若干劣ります(※とはいえTURNサーバでは通常暗号化されていないRTP/データグラムを中継するだけで内容を解釈しません)。
総じて、TURNは必要な場合に限り使うべき手段です。実際、多くのWebRTC通信はSTUNで直接接続できており、Googleの統計では全体の約86%の通話がリレー不要(ピアツーピア)で成立していると報告されています。残りの約14%のみがTURNを必要とするケースですが、その14%のためにTURNインフラを用意しておくことが重要です。
TURNS (TLS over TCP/443) の役割と特徴
TURNSとは「TURN over TLS」の略称で、TURNプロトコルでの中継通信をさらにTLS(Transport Layer Security)で暗号化したものです。平たく言えばTLS(HTTPS)で保護されたTURN通信であり、多くの場合TCPの443番ポート上でサービスします。ポート443はHTTPSと同じポート番号であるため企業のファイアウォールでも通過させてもらいやすく、プロキシや検閲を回避しやすいという利点があります.
例えば社内ネットワークでは外部への通信は80番と443番しか許可されていないことがありますが、その場合でも443番でTLS通信を行うTURNサーバであれば通過できる可能性が高いです。加えてTLS暗号化されているため、通信内容は第三者から傍受されにくくセキュアです。
WebRTCでは設定上"urls": "turns:ターンサーバ:443"
のようにURIスキームにturns:
を指定することで、このTLS暗号化されたTURNサーバを利用できます。
TURNSの使用シーン
企業内ネットワークなど厳しい制限下でのWebRTC通信において、他の手段がすべてブロックされてしまう場合にTURNSが活躍します。UDPのすべてやTCPの一般ポートが封鎖されている環境でも、HTTPS通信と同様の扱いであれば許可するという方針は多いため、TLS 443ポート上のTURNは事実上最後の手段として有効です。
また、公衆無線LAN等で特定のポートが閉じている状況や、クライアント側でどうしてもTLS通信しか行えない場合にも利用されます。要するに「まずUDP、それがだめならTCP、それもだめならTLSで443へ」という段階的なフォールバックの最終段として位置付けられます。
TURNSのメリット
ファイアウォール耐性の高さが最大の利点です。TLSの暗号化通信は一般的なHTTPSと区別が付きにくいため、厳格なフィルタでも通過できる可能性が高まります。特にWeb会議システムを企業導入する場合、社内ネットワークから外部への接続を許可してもらう必要がありますが、TCP/443でのTLS通信であればセキュリティポリシー上受け入れられやすいです。また暗号化されているため、中継サーバへの通信自体の秘匿性も確保できます(※ただし映像等のコンテンツそのものは多くの場合WebRTCレイヤで既に暗号化されています)。
TURNSのデメリット
最大の欠点はパフォーマンス面のペナルティです。TURN自体の遅延・負荷に加えて、TLSとTCPのオーバーヘッドが加算されます。TCPは信頼性輸送のためパケットロス時に再送機構が働きますが、リアルタイムメディアには不向きで、ロスが発生すると映像・音声がスムーズに再生されなくなる可能性があります。
またTCPはパケット順序制御のためにヘッドオブラインブロッキングが起こりやすく、UDPと比べてジッタ(ゆらぎ)も増大します。さらにTLS暗号化・復号処理によるCPU負荷も加わります。その結果、実測で50ms以上の追加遅延が発生し、ユーザにも体感できるラグが生じると報告されています。特にビデオ会議ではこの遅延増加により会話のテンポが悪くなったり、タイミングのズレが顕著になることがあります。
このようにTURNSは品質面では「最終手段」と言える手法ですが、通信を成立させるためには背に腹は代えられない状況で頼りになる命綱でもあります。
なお、近年ではUDP 443番で動作しTLSの代わりにDTLS/QUICなどを使った新しいアプローチ(TURN over QUIC)も検討されていますが、標準化途上であり一般的ではありません。
UDP STUN が使えない場合の通信フロー
UDPによるSTUNが利用できないケースでWebRTCのICE処理がどのように進むかを、ステップごとに解説します。企業ネットワークなどでUDPが全面的にブロックされている状況を想定し、ICEネゴシエーションがどのようにフォールバックするかを追ってみましょう。
- クライアントがSTUNサーバへ外部IP問い合わせ(UDP/3478)を送信:
WebRTCクライアント(ブラウザ)はiceServers
で指定されたSTUNサーバに対し、UDPポート3478経由でBinding Request(外部アドレス確認の要求)を送ります。これはICE候補収集の最初の段階で行われ、成功すればサーバから自身のグローバルIPアドレスとポート番号が返され、Server Reflexive Candidate(srflx候補)として候補リストに追加されます。 - UDPパケットがファイアウォールで遮断され応答なし:
このケースではネットワークのファイアウォール設定によりUDP通信が外部まで届きません。そのため、STUNサーバへのリクエストはサーバに届かないか、あるいは返答がクライアントまで戻ってきません。結果としてクライアントはSTUN応答を受信できず、外部IPアドレスを知ることができません。ICEエージェントは一定時間応答を待機しますが、タイムアウトを迎えます。ユーザから見れば、この時点ではまだ接続処理中であり特にエラー表示は出ませんが、実際には候補収集に失敗しつつあります。 - Server Reflexive候補が得られないためICEの直接接続チェックが失敗:
通常、STUNが成功していればクライアントはHost候補(自分のローカルIP)に加えてServer Reflexive候補(自分のグローバルIP)を持ち、遠端ピアの同種の候補と組み合わせて接続チェックを行います。しかしSTUN失敗によりグローバルIP候補が無い場合、直接ピア間接続の候補が極端に限定されます。例えば両者ともプライベートIPしか持たない状態では、互いに接続試行しても届きません。結果、ICEは「直通では無理」と判断します。もしICEサーバ(TURN)が設定されていなければ、この段階でICE全体が失敗扱いとなり、WebRTC接続は成立しません(開発者コンソールにはICE failed
und ... undICE connection state: failed
等のエラーが表示されます)。 - TURNリレー候補の取得を試行(TCP/TLS/443経由):
STUNによる直接候補取得が失敗しても、iceServers
にTURNサーバが指定されていればICEエージェントは次の手段に移ります。今回の想定ではUDPが通じないため、クライアントはTURNサーバへの接続をTCPあるいはTLSで試みます(例えばturns:turn.example.com:443
が設定されていればTLSハンドシェイクを開始します)。幸いファイアウォールはTCP 443のHTTPS通信は許可していたため、TLSによるTURN接続は成功します。クライアントはTURNサーバ上に中継用のリレーアドレスを確保し、Relay Candidate(relay候補)を取得します。これは「TURNサーバ経由で通信するための仮想的な候補先」です。一方、通信相手側(リモート側)も同様にリレー候補を取得するか、そもそも問題ないネットワークであれば直接候補やSTUN候補を持っているでしょう。いずれにせよ、少なくとも片側がリレー候補を持てば相手はそのTURNサーバに向けて接続を試みることができます。 - リレー経由のICE接続確立(または最終的な失敗):
両ピアが利用可能な候補(この例では一方または双方のrelay候補)を入手すると、ICEはそれらを用いて接続チェックを行います。TURNサーバ経由の通信は一旦サーバとの間で確立すれば中継が可能なので、ピア間で直接UDPが通らなくてもメディアチャネルが開通します。これによりユーザ同士の映像・音声通信が開始されます。接続確立後はTLS上のTCPというオーバーヘッドはあるものの、会話自体は可能となります。逆に、もしここでも失敗する(例えば企業プロキシが非HTTPのTLS通信を検知して遮断した、TURNサーバの認証に失敗した等)場合、残念ながらICE総合失敗(ICE failed)となり接続は断念されます。アプリケーション側ではこの状況を検知し、ユーザに「接続できませんでした」などと通知する必要があります。
以上が、UDPが使えない厳しい環境下におけるICEネゴシエーションの流れです。要約すれば、「ホスト→STUN→TURN」の順に候補を試し、それでもダメなら接続失敗となります。開発者はこの挙動を理解した上で、最低でもTURN/TURNSサーバをICEサーバリストに入れておくことで、最悪のケースでも通信が成立する可能性を残すことが重要です。また、ユーザから問い合わせを受けた際には「ICE failedと出る」といった情報からネットワーク環境の問題(UDP遮断など)を推測し、TURNサーバの設定漏れがないか確認する、といったトラブルシューティングが求められます。
coturnを使ったSTUN/TURN/TURNSサーバの構築と設定
自前でSTUN/TURNサーバを立てる場合、オープンソース実装である coturn(コターン)を使用するのが一般的です。coturnはSTUNとTURNの両方に対応したサーバ実装で、設定次第でTURNS (TLS)にも対応できます。ここではLinuxサーバ上にcoturnをインストールし、STUN/TURN/TURNSを提供するサーバを構築する手順と設定ポイントを解説します。また、代表的な設定ファイル(turnserver.conf
)の例も示します。
インストールと基本設定
Installieren
UbuntuやDebianの場合、apt
からcoturnパッケージをインストールできます。例えば以下のコマンドでインストールと自動起動設定を行います。
# Ubuntu/Debianの場合
sudo apt-get install coturn
sudo sed -i 's/#TURNSERVER_ENABLED=1/TURNSERVER_ENABLED=1/' /etc/default/coturn
sudo systemctl enable --now coturn
上記によりcoturnサーバがデーモンとして起動します。デフォルトでは設定ファイル /etc/turnserver.conf
を読み込みますので、続いてこれを編集していきます(念のためバックアップを取ってから編集しましょう)。
基本設定
turnserver.conf
では以下のような項目を設定します。
- realm(レルム)とserver-name: TURNサーバのドメイン名や識別名です。WebRTCクライアントの認証時に利用される場合がありますが、基本的には任意の文字列で構いません。例:
realm=example.com
,server-name=example.com
. - listening-port: TURNおよびSTUNで待ち受けるUDPポート番号です。デフォルトは3478番です。
listening-ip
で特定のNICにバインドもできますが、通常は0.0.0.0
で全て受け付けます。 - tls-listening-port: TLS用(TURNS用)に待ち受けるTCPポート番号です。一般的には443番や5349番を指定します。例:
tls-listening-port=443
. - external-ip: サーバ自身がNATの内側にいる場合、自身のグローバルIPを指定します(これにより内部IPと外部IPのマッピングを認識させます)。直接グローバルIPを持つサーバなら不要です。
- 認証方式: WebRTCのTURN利用には長期認証(Long-Term Credential)が使われるため、
lt-cred-mech
(Long Term Credential Mechanism)を有効にします。その上でuser=username:password
の形式でユーザ名とパスワードを設定するか、use-auth-secret
を用いて動的な認証を行います(後者はトークンベース認証で、セキュリティ向上に有効ですがここではシンプルな静的ユーザ認証を例示します)。 - ログ設定: トラブルシュートのため
log-file
でログファイルパスを指定し、verbose
で詳細ログを有効にするとよいでしょう。
ファイアウォール設定
サーバ側ではSTUN/TURN用にUDPポート3478、およびTURN/TLS用にTCPポート443(または5349)を開放する必要があります。さらにTURN中継ではデフォルトでUDP 10000-20000番の範囲を使用するため、このポート範囲もサーバで開放します(必要に応じてmin-port
undmax-port
でレンジ変更可能です)。
以下に、上記の基本設定を反映した/etc/turnserver.conf
の一例を示します。
# TURNサーバの名称とレルム(ドメイン)
realm=example.com
server-name=example.com
# ネットワーク設定
listening-ip=0.0.0.0 # すべてのIPアドレスで待受
external-ip=203.0.113.10 # サーバのグローバルIP(必要な場合)
# ポート設定
listening-port=3478 # STUN/TURN用 UDPポート
tls-listening-port=443 # TLS用 TCPポート (443番)
min-port=10000 # 中継に使用するポート範囲(下限)
max-port=20000 # 中継に使用するポート範囲(上限)
# ログ設定
log-file=/var/log/turnserver.log
verbose # 詳細ログを有効化
fingerprint # パケットにfingerprint属性を付与
# 認証設定(長期認証方式)
lt-cred-mech # 長期認証を有効化
user=webrtcuser:secretpass123 # ユーザ名:パスワード を設定
# TLS/SSL証明書の指定
cert=/etc/letsencrypt/live/example.com/fullchain.pem # サーバ証明書
pkey=/etc/letsencrypt/live/example.com/privkey.pem # 秘密鍵
上記では、ドメインexample.com
でLet’s Encryptの証明書を取得してTLS設定に利用しています。lt-cred-mech
で長期認証を有効にし、user
により単純なユーザ名・パスワード認証を設定しています。実運用ではuse-auth-secret
undstatic-auth-secret
を使い、トークン方式で一時的なクレデンシャルを発行する方法が推奨されますが、ここでは割愛します。
TLS利用時の注意
Coturnを443番ポートで動作させる場合、Linux環境ではポート権限に注意が必要です。1024番未満のポートは特権ポートと呼ばれ通常はroot権限でないと開けません。Ubuntuのcoturnパッケージではデフォルトでturnserver
ユーザで実行されるため、そのままでは443番をバインドできません。対処方法として、/etc/default/coturn
で実行ユーザをrootに変更するか、setcap
コマンドでturnserver
実行ファイルにcap_net_bind_service
権限を与える方法があります。例えば後者の場合、sudo setcap cap_net_bind_service=+ep /usr/bin/turnserver
を実行することで非rootでも低番号ポートをバインドできるようになります。また、証明書ファイル(cert/pkey)は正しいパスを指定し、ファイル権限もcoturnユーザが読めるように設定してください。設定変更後はsudo systemctl restart coturn
でサービスを再起動し、ログにエラーが出ていないか確認しましょう。
動作確認
Coturnサーバを起動したら、動作確認としてSTUNクライアントを使ったテストや、実際にブラウザのWebRTCアプリからICE接続を試みてみます。Linuxならstunclient
コマンド(apt-get install stun-client
で導入可能)でstunclient <サーバIP> 3478
のように実行すると、自分の外部IPが取得できるか試せます。またブラウザでは、開発者ツールのログにICE候補が列挙されるので、srflx
(Server Reflexive)候補やrelay
候補が得られているか確認してください。万一うまくいかない場合、以下の点をトラブルシュートします。
- サーバのファイアウォール設定(iptablesやクラウドのセキュリティグループ)で必要なポートが開放されているか。
- クライアント側のICEサーバ設定(後述)で正しいURI、ポート、認証情報が設定されているか。
turnserver.conf
vonrealm
設定がクライアントの認証と一致しているか(ブラウザ版WebRTCでは自動的にrealmを付与する実装になっているため通常問題になりませんが、カスタム実装の場合注意)。- coturnのログ (
/var/log/turnserver.log
) を確認し、認証エラーが出ていないか(WRONG USER
等のエラーがある場合はusername/passwordの不一致)。
以上の設定が適切であれば、自前のSTUN/TURN/TURNSサーバが稼働し、様々なネットワーク環境下でWebRTC接続をサポートできるようになります。
WebRTCクライアントでのICEサーバ設定例(JavaScript)
実際にWebRTCアプリケーション(ブラウザ)の側で、先ほど構築したSTUN/TURNサーバを利用するには、ICEサーバ(ICE Servers)設定を行います。JavaScriptのWebRTC APIでは、RTCPeerConnection
を生成する際にSTUN/TURNサーバのリストを指定できます。次に、STUN/TURN/TURNS全てを指定した具体的なコード例を示し、その意味を解説します。
まず、ICEサーバ用の設定オブジェクトを作成します。自前サーバのドメイン名をturn.example.com
(適宜置き換え)とし、STUNは認証不要なのでURIだけ、TURN/TURNSは認証が必要なのでユーザ名とパスワードも含めて指定します。
const iceConfig = {
iceServers: [
// 1. STUNサーバ(UDP/3478)
{ urls: 'stun:turn.example.com:3478' },
// 2. TURNサーバ(UDP/443経由)
{ urls: 'turn:turn.example.com:443?transport=udp', username: 'webrtcuser', credential: 'secretpass123' },
// 3. TURNサーバ(TCP/443 + TLS = TURNS)
{ urls: 'turns:turn.example.com:443', username: 'webrtcuser', credential: 'secretpass123' }
]
};
const pc = new RTCPeerConnection(iceConfig);
上記のiceServers
配列には3つのエントリを指定しています。
- STUN:
stun:turn.example.com:3478
自前のSTUNサーバのアドレスを指定しています(ポート省略時は3478が使われます)。STUNはNAT越え判定と候補取得のために使われ、ブラウザはまずこのサーバにUDPで問い合わせてServer Reflexive候補を取得しようとします。 - TURN (UDP):
turn:turn.example.com:443?transport=udp
自前のTURNサーバをUDPの443番ポートで利用する設定です。認証情報として先ほどcoturnに設定したユーザ名webrtcuser
とパスワードsecretpass123
を指定しています。クエリパラメータ?transport=udp
を付与することで、UDPでTURN接続を試みます(未指定の場合、ブラウザはまずUDPを試行し、失敗したらTCPも試す実装になっています)。この設定により、もし通常のSTUNによる直通が失敗しても、UDPの443番ポートでTURNリレーを行う候補(relay候補)が得られます。 - TURN (TLS/TCP):
turns:turn.example.com:443
TLSを用いたTURN、すなわちTURNSサーバの設定です。こちらも同じくユーザ名とパスワードを指定しています。ブラウザはこのエントリに対しTCP 443番でTLS接続を行い、TURNリレー候補を取得します。これは最終手段の中継候補であり、UDPによる通信が一切できない場合でもこの候補があれば通信確立の望みがあります。
RTCPeerConnection
を生成すると、これらで指定したICEサーバに対して順次接続を試み、候補を収集します。ICEエージェントはまずSTUN候補(srflx)を取得し、次にTURN候補(relay)も並行して取得します。あとはICEのアルゴリズムがこれらの候補同士を組み合わせて接続チェックを行い、最適な経路を選択してくれます。開発者は特にこれ以上の手続きを意識する必要はありません。
ポイント: 上記のように複数の候補を用意することが重要です。例えばstun:
だけしか指定しなかった場合、UDPがブロックされた環境では一切候補が得られず接続失敗となってしまいます。同様にTURN (UDP)だけではTCPしか通らない環境で失敗します。したがって、できればturn:
undturns:
の両方をICEサーバに含めておくことで、あらゆる環境で少なくとも一つは有効な候補が見つかるように冗長化します(もちろんTURNサーバ側でもUDPとTCP/TLSの両方をサポートしている必要があります)。クライアント(ブラウザ)は自動的に利用可能なパスを選択しますので、リストの順序は大きな問題ではありません。強いて言えば、iceTransportPolicy
vonrelay
にしない限りブラウザは直接接続を優先しますので、STUNエントリを入れておけば無駄にTURNサーバを使わずに済みます。また、ICEサーバのリストに無関係なサーバ(存在しないアドレス等)を入れているとタイムアウト待ちで遅延する可能性があるため、確実に利用可能なものだけを入れることが望ましいです。
最後に、この設定を適用したWebRTCアプリケーションを実行し、接続状況を検証してみましょう。ブラウザの開発者ツールでpeerConnection.getStats()
を使うか、あるいはchrome://webrtc-internals
(Chromeの場合)でICE Candidateや接続状態を確認できます。期待どおりに動作していれば、UDPが使える環境ではdirect(P2P)接続に、難しい環境では自動的にTURN/TLS経由の接続にフォールバックしているはずです。
SFUとTURNの違い
WebRTCにおける中継には大きく分けて「TURN」と「SFU」がありますが、それぞれの役割・構成・用途は大きく異なります。ここではその技術的な違いを整理します。
TURN:ピアツーピアの代替としての中継
TURN(Traversal Using Relays around NAT)は、WebRTCのP2P通信ができない環境で使用される補助的な中継サーバです。主にNATやファイアウォールでSTUNが機能しない場合に、TURNサーバが各ピアの間に入りパケットを中継します。各ピアはそれぞれの通信相手に個別にストリームを送信するため、構成はあくまでメッシュ型であり、TURNは「代打」のような位置づけです。
- Zusammensetzung:各ユーザーが他ユーザーごとに中継経由で送信(実質メッシュ)
- Skalierbarkeit:低い(人数が増えるほど負荷増)
- 中継内容:単純なパケット転送のみ、メディアの解析や最適化は行わない
SFU:多人数通話のための効率的な中継
SFU(Selective Forwarding Unit)は、多人数参加型のWeb会議で利用される知能的な中継サーバです。各クライアントはSFUに対して1本のストリームを送信し、SFUがそれを他の参加者に選択的に転送します。話者検出や画質調整、レイテンシ最適化といった処理も行えるため、スケーラブルでパフォーマンスに優れた中継が可能です。
- Zusammensetzung:各クライアントがSFUと1本接続するスター型
- Skalierbarkeit:高い(人数が増えても送信は1本)
- 中継内容:転送先の制御やメディアの最適化などが可能
TURNとSFUの比較表
特徴 | TURN | SFU |
---|---|---|
用途 | NAT越えできないときの代替手段 | 多人数のリアルタイム通信 |
通信構成 | メッシュ(各相手ごとに送信) | スター型(1本の送信) |
中継機能 | 単なるリレー(透明) | 選択転送・最適化あり |
Skalierbarkeit | 低い | 高い |
メディア制御 | なし | あり(例:話者検出、解像度調整) |
TURNはあくまで「P2P通信が不可能な時に使う最終手段」であり、構成的にはP2Pメッシュを補完する中継です。一方、SFUは多人数通話において初めから効率的な設計を想定して使われる中継アーキテクチャです。両者は役割が根本的に異なるため、混同せずに設計することが重要です。
Zusammenfassung
本記事では、WebRTCの中級〜上級者に向けてSTUN・TURN・TURNSの技術的な違いと使い所、さらにcoturnによるサーバ構築方法とコード例、そして厳しいネットワーク環境でのICE挙動について詳しく解説しました。
STUNは軽量ながらNAT環境での直接通信を可能にし、TURNは困難な状況でも通信を成立させる頼みの綱となります。そしてTURNSを組み合わせることで、企業内など特殊な環境でもWebRTCを活用できる道が開けます。
それぞれメリット・デメリットがあるため、本来は可能な限りSTUNで直接接続し、どうしても必要な場合にのみTURNリレーを使うのが理想です。実際のWebRTCアプリケーション開発では、ICEサーバ設定に今回紹介したような複数経路を用意し、またサーバ側もcoturnの設定と運用を適切に行うことで、様々なネットワーク環境下でも安定したリアルタイム通信を提供できます。
WebRTCはブラウザAPIやネットワーク技術が組み合わさった複雑な領域ですが、STUN/TURNとICEの仕組みを理解することは信頼性の高いアプリケーションを作る上で避けて通れません。
ぜひ本記事の内容を踏まえて、ご自身のプロダクトでNAT越えの課題に挑戦してみてください。そうすれば、ユーザーは意識せずとも裏側で賢く工夫された接続処理によってシームレスに通信を楽しめるようになるでしょう。