panda's tech note

WebRTC のための TURN サーバ

WebRTCのNAT越えにはSTUN/TURNを利用します。STUNはポートを空けるためにサーバを使い,実際の通信は空けたポートでSTUNサーバを介さずに行います。そのため,パブリックなSTUNサーバが提供されています。一方,ファイヤウォールなどにより,STUNではポートが空けられなかったり空けたポートで通信できないこともあります。このときに使われるのが,TURNというプロトコルなのです。STUNと違い,TURNでは通信がTURNサーバ経由になります。これにより,STUNで外部からの通信を受け付けることができない端末も他の端末と(TURNサーバがプロキシしているのでP2Pと言って良いのかは疑問ですが)P2P通信ができるようになります。ただし,TURNサーバは通信を中継するため,パブリックなサーバがありません。そのため,今回は自分でTURNサーバをインストールして使用します。

TURNサーバのインストール

Ubuntu 18.04 LTS に TURN サーバである coturn をインストールします。 apt パッケージにあるので単純に

$ sudo apt install coturn

でインストールできます。

coturn の設定ファイルの変更前に,まず coturn のデーモンのオプション設定で以下のように変更することで TURN を有効にします。

/etc/default/coturn

TURNSERVER_ENABLED=1

と記述します(デフォルトではコメントアウトされていると思うので,コメントを外します)。

Let's Encrypt による証明書の設定

TURN サーバの設定をする前に,TLS 対応のためにサーバ証明書を準備します。今回は Let's Encrypt を使います。Let's Encrypt の証明書は certbot を使用して手動でも更新できますが,Web サーバと連携すると自動で更新できるので今回は Apache で自動更新をするために以下のコマンドで証明書を作成します。 turn.example.com は TURN サーバのドメイン名にしてください。

$ sudo certbot --apache -d turn.example.com

作成した証明書は /etc/letsencrypt/live/turn.example.com/fullchain.pem に配置されます。また,秘密鍵は /etc/letsencrypt/live/turn.example.com/privkey.pem に配置されます。

COTURN の設定

Ubuntu 18.04 の apt でインストールすると coturn の設定ファイルは /etc/turnserver.conf に配置されます。すべての設定がコメントアウトされているので,以下のように必要な項目を設定していきます。

# TURN のメッセージに fingerprint を使うための設定で,WebRTC では必須となります。
fingerprint

# Long-term credential 機構を有効にします。こちらも WebRTC では必須です。
lt-cred-mech

# REALM となるドメイン名を指定します
realm=turn.example.com

# STUN/TURN で使用する TLS 証明書と秘密鍵のパスを設定します。
cert=/etc/letsencrypt/live/turn.example.com/fullchain.pem
pkey=/etc/letsencrypt/live/turn.example.com/privkey.pem

# TLS で使う暗号スイートを設定します。
cipher-list="ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS"

# TLS の DH 鍵のビット長を 2066 にします
dh2066

# ログの出力先を設定します
log-file=/var/log/turn.log

# 上述の log-file で指定したファイルにログを書き込みます。これを指定しない場合、プロセス番号等に基づき毎回異なるファイル名でログが作成されます。
simple-log

# TLS1.0, 1.1 を無効にします(TLS1.2, TLS1.3を使用します)
no-tlsv1
no-tlsv1_1

この設定が終わったら以下のコマンドで coturn サーバを再起動して設定を有効化します。

$ sudo systemctl restart coturn

TURN ユーザの追加と動作確認

coturn の設定が完了したら https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ の ICE servers に上記の例では stun:turn.example.com:5349 を指定することで STUN の動作確認ができます。

TURN はクレデンシャル(ユーザ名とパスワード)を設定する必要があります。 coturn は内部にデータベースを持っているので,そちらを使ってテストをするのが最も簡単です。MySQL や Redis など外部のデータベース連携も可能なので,本運用の際はそちらのデータベースを使用することをお勧めします。

内部データベースにクレデンシャルを追加するには turnadmin コマンドを使います。例えば,ユーザ名 test,パスワード 2a6f543d28359bd929ce7b141fb12a4360 を以下のコマンドで追加出来ます。

$ sudo turnadmin -a -u test -r turn.example.com -p 2a6f543d28359bd929ce7b141fb12a4360

これを追加したら,先ほどのリンクのサイトに

  • STUN or TURN URI: turn:turn.example.com:5349
  • TURN username: test
  • TURN password: 2a6f543d28359bd929ce7b141fb12a4360 を TURN servers に追加することで確認できます。

TURN サーバ側では /var/log/turn.log を確認することで,認証が成功したかなどを確認できます。

認証に成功した場合は以下のようなメッセージがログに残ります。

50245: session 001000000000000004: new, realm=<turn.example.com>, username=<test>, lifetime=600
50245: session 001000000000000004: realm <turn.example.com> user <test>: incoming packet ALLOCATE processed, success
50245: session 001000000000000004: refreshed, realm=<turn.example.com>, username=<test>, lifetime=0
50245: session 001000000000000004: realm <turn.example.com> user <test>: incoming packet REFRESH processed, success

一方,認証が失敗した場合は,

50341: check_stun_auth: Cannot find credentials of user <test>
50341: session 001000000000000005: realm <turn.example.com> user <test>: incoming packet message processed, error 401: Unauthorized

のようにユーザ test に対する 401: Unauthorized エラーが残ります。上記サイトでも ICE candidates に Authentication failed? というメッセージが残ります。