# 本番稼働に向けて

この資料はチュートリアルで Sora をなんとなく体験したあとに、
本番環境に向けてどのような準備が必要なのか、どの機能を使っていけばいいのかをまとめたものです。

> **重要**
>
> 不明点などはサポートまでお問い合わせください。

## 優先順位

Sora で外部から指定する値には優先順位があります。

上から順に優先度が高く、同じ優先度の場合は後から指定した値が優先されます。

1. セッション生成時の払い出しで指定した値
2. 認証成功時の払い出しで指定した値
3. シグナリング接続時に指定した値
4. sora.conf で設定した値

- sora.conf で設定した値は、シグナリング接続時の値で上書きできます
- シグナリング接続時の値は、認証成功時の払い出しで上書きできます
- 認証成功時の払い出しは、セッション生成時の払い出しで上書きできます

本番環境ではシグナリング接続時の値を利用するのは避けて、
認証成功時やセッション生成時の値を利用するようにしてください。

## IPv4 アドレスの固定

`sora.conf` の [ipv4_address](SORA_CONF.html#04becc) にサーバーの IP アドレスを指定してください。

```ini
ipv4_address = 192.0.2.10
```

## IPv6 アドレスの利用について

Safari は IPv6 環境での動作が不安定なため、
Safari をターゲットデバイスに含んでいる場合は `sora.conf` の IPv6 設定を無効にする `ipv6 = false` を推奨しています。

ファイアーウォールを利用される場合は IPv6 向け設定もご確認ください。

## sora.conf の turn_fqdn を設定する

iOS の場合は TURN は FQDN を利用しないと接続ができない場合があるため、
TURN-UDP / TURN-TCP で利用するドメインを指定してください。

`sora.conf` の `ipv4_address` に指定した IP アドレスを設定してある FQDN を指定してください。

```ini
turn_fqdn = sora-turn.example.com
```

## ウェブフックなどで利用する CA 証明書のインストール

もしウェブフックなどで HTTPS サーバへのアクセスを行う場合に、
自前で CA 証明書を設定しない場合、信頼された CA 証明書のインストールを行ってください。

- Ubuntu は `apt install ca-certificates` でインストールされる証明書を利用します
- RHEL (または CentOS) は `dnf install ca-certificates` でインストールされる証明書を利用します

### 影響を受ける機能

- 認証ウェブフック
- セッションウェブフック
- イベントウェブフック
- 統計ウェブフック
- 音声ストリーミング機能

ただし、以下の設定で自前で CA 証明書を指定している場合は、この影響を受けません。

- [webhook_tls_verify_cacert_file](SORA_CONF.html#7036dc)
- [audio_streaming_tls_verify_cacert_file](SORA_CONF.html#feef99)

## HTTP API のループバックアドレスからのみのアクセス

> **重要**
>
> この設定を導入することを強く推奨します

Sora の HTTP API は TLS を利用したセキュアな通信機能や認証機能を持ち合わせていません。

そのため、本番環境では `sora.conf` の [api_loopback_address_only](SORA_CONF.html#9d6140) の値を `true` にしてください。
こうすることでループバックアドレスからのみ HTTP API が叩けるようになります。

アプリケーションからの HTTP API へのアクセスは Nginx などのリバースプロキシ経由で利用してください。

## シグナリングのループバックアドレスからのみのアクセス

> **重要**
>
> この設定を導入することを強く推奨します

Sora の WebSocket は TLS を利用したセキュアな通信機能を持ち合わせていません。

そのため、本番環境では `sora.conf` の [signaling_loopback_address_only](SORA_CONF.html#e22105) の値を `true` にしてください。
こうすることでループバックアドレスからのみシグナリングが叩けるようになります。

WebRTC クライアントからシグナリングへのアクセスは Nginx などのリバースプロキシ経由で利用してください。

## ファイルディスクリプタ数の設定

Sora は 1 接続で少なくとも 2 つ以上のファイルディスクリプタを利用します。
また、ウェブフックやログの書き込みでも追加でファイルディスクリプタを利用します。
同時接続数が 100 の場合は Linux のデフォルト値である 1024 でも足りるとは思いますが、
ある程度大きめのファイルディスクリプタ数に変更してください。

## systemd の適用

> **重要**
>
> この仕組みを導入することを強く推奨します

Sora の起動/停止に `bin/sora daemon` を利用するのではなく systemd を適用してください。

デーモン化せずに Sora を動かすには `bin/sora foreground` を利用します。

詳細は [systemd](SYSTEMD.html) をご確認ください。


## TURN-TLS、TURN-TCP、シグナリングで 443 番ポートを使用する

> **重要**
>
> この仕組みを導入することを強く推奨します。
> この設定は Sora 2021.1 以降に最適化されています。

> **注意**
>
> NGINX および systemd の設定に関する質問については Sora のサポート範囲外となります。

**この設定はある程度の NGINX や証明書の知識が必要になります**

NGINX のバージョンは 1.11.5 以降が必須です。

TURN-TLS、TURN-TCP、シグナリング（HTTPS）を 443 番ポートのみで受信する場合は次の設定を追加してください。

> **注意**
>
> NGINX の停止に QUIT シグナルを使用している場合は、nginx 起動時に作成された UNIX domain socket のソケットファイルは削除されないため、nginx の再起動に失敗します。
> そのため、サービス停止を QUIT シグナルではなく TERM シグナルを使用するように変更するか、または、daemon off で起動することをお勧めします。
> systemd を使用している場合も、ドロップインファイル等を作成して、nginx 停止時のシグナルを QUIT シグナルから TERM シグナルへ変更するか、daemon off による管理へ変更することをお勧めします。

### NGINX のストリーム機能と ssl_preread 機能を利用する


> **ヒント**
>
> Ubuntu 24.04 では NGINX のストリーム機能は `apt install libnginx-mod-stream` で明示的にインストールする必要があります。

NGINX の機能を利用して、同一ポートの待受で複数のプロトコルを扱えるようにします。

その機能を利用した NGINX の参考設定です。証明書には Let's Encrypt を利用している想定です。

利用する証明書はマルチドメイン (SANs) またはワイルドカード証明書が前提となります。

- sora.example.com- シグナリングの WebSocket over TLS で利用するドメイン
- sora-turn.example.com- TURN-TLS で利用するドメイン

```nginx
stream {
    # SNI のサーバー名が取得できない場合、または、該当するサーバー名が指定されていない場合は TURN-TCP へ
    # 該当するサーバー名が指定されている場合は TURN-TLS または シグナリングへ
    map $ssl_preread_server_name $upstream {
        default sora-turn.example.com;
        "sora-turn.example.com" unix:/tmp/tls.sock;
        "sora.example.com" unix:/tmp/https.sock;
    }

    # Sora の TURN-TCP へ転送
    upstream sora-turn.example.com {
        # Sora の TURN-TCP へ
        # ここの IP アドレスは Sora の ipv4_address に指定した値を指定してください
        # ここを 127.0.0.1 にすると Firefox で繋がらなくなることを確認しています
        server 192.0.2.1:3478;
    }


    # TURN-TCP, TURN-TLS, シグナリングを TCP で待ち受け
    server {
        listen 443;
        # IPv6 を利用している場合は下記を有効にしてください
        # listen [::]:443;

        proxy_pass $upstream;
        proxy_protocol on;

        ssl_preread on;
    }

    # TURN-TLS, シグナリングの TLS 終端し TURN-TCP へ転送
    server {
        listen unix:/tmp/tls.sock ssl proxy_protocol;

        # SNI を見て TURN-TLS の場合は TURN-TCP へ転送
        # シグナリング（HTTPS）の場合は HTTP へ転送
        proxy_pass $ssl_server_name;
        proxy_protocol on;

        ssl_certificate /etc/letsencrypt/live/sora.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/sora.example.com/privkey.pem;

        ssl_protocols TLSv1.2;
        ssl_prefer_server_ciphers on;

        ssl_handshake_timeout 10s;

        ssl_session_cache off;
        ssl_session_tickets off;
    }
}

http {
    include mime.types;
    default_type application/octet-stream;
    sendfile on;
    keepalive_timeout 65;
    gzip on;

    # $proxy_protocol_addr を利用することでクライアントの IP が保持できるようになる
    log_format proxy '$proxy_protocol_addr - $remote_user [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent"';

    # 定義した proxy を利用する
    access_log /var/log/nginx/access.log proxy;

    server {
        listen unix:/tmp/https.sock ssl proxy_protocol;

        root /var/www/html;

        index index.html index.htm;

        ssl_certificate /etc/letsencrypt/live/sora.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/sora.example.com/privkey.pem;

        ssl_protocols TLSv1.2;

        ssl_prefer_server_ciphers on;

        ssl_session_cache off;
        ssl_session_tickets off;

        real_ip_header proxy_protocol;

        server_name sora.example.com;

        # シグナリングを Sora に Proxy します
        location = /signaling {
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_pass http://127.0.0.1:5000/signaling;

                proxy_set_header X-Real-IP       $proxy_protocol_addr;
                proxy_set_header X-Forwarded-For $proxy_protocol_addr;
        }

        # Sora の HTTP API に Proxy します
        # 本番環境では認証などの機能を利用してください
        location /api {
                proxy_http_version 1.1;
                proxy_pass http://127.0.0.1:3000/;
        }

        # OBS (WHIP/WHEP) 向けのシグナリングを Sora に Proxy します
        location ~ ^/(whip|whip-session|whep|whep-session)/ {
                proxy_pass http://127.0.0.1:5000;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Authorization $http_authorization;
        }

        # Sora のヘルスチェックに Proxy します
        # 公開するかどうかは検討してください
        location /.ok {
                proxy_http_version 1.1;
                proxy_pass http://127.0.0.1:5000;
        }
    }
}
```

TURN-TCP、 TURN-TLS、シグナリングを 443 番で使用する場合の sora.conf の設定は以下になります。

turn_tcp_port, turn_tls_port を 443 に変更します。

```ini
## TURN 機能を有効にするかどうかを指定してください
turn = true

## TURN 機能で利用するレルムを指定してください
turn_realm = sora-turn.example.com

## TURN 機能で TURN URL 払い出し機能で利用する FQDN (最後の . なし)を指定してください
turn_fqdn = sora-turn.example.com

## TURN 機能で TURN-TCP を有効にするかどうかを指定してください
turn_tcp = true

## TURN 機能で TURN-TCP を有効にした際に利用するポート番号を指定してください
turn_tcp_listen_port = 3478

## TURN 機能で TURN-TCP URL 払い出し時のポート番号を指定してください
turn_tcp_port = 443

## TURN 機能で TURN-TLS URL 払い出し機能を有効にするかどうかを指定してください
## オプションでデフォルトは false です
turn_tls = true

## TURN 機能で TURN-TLS URL 払い出し機能で利用する FQDN (最後の . なし)を指定してください
## turn_tls_fqdn は turn_fqdn の値を上書きします
turn_tls_fqdn = sora-turn.example.com

## TURN 機能で TURN-TLS URL 払い出し機能を有効にした際に利用するポート番号を指定してください
turn_tls_port = 443
```

### Ubuntu の Nginx で Unix Domain Socket を利用する際の注意点

- SIGTERM を利用するようにしないと、リスタートすることができません
- セキュリティアップデートで強制的に apt upgrade が行われた際、 Unix Domain Socket ファイルが残って Nginx が再起動でき無くなる場合があります

```console
$ sudo vim  /lib/systemd/system/nginx.service
```

```ini
# Stop dance for nginx
# =======================
#
# ExecStop sends SIGSTOP (graceful stop) to the nginx process.
# If, after 5s (--retry QUIT/5) nginx is still running, systemd takes control
# and sends SIGTERM (fast shutdown) to the main process.
# After another 5s (TimeoutStopSec=5), and if nginx is alive, systemd sends
# SIGKILL to all the remaining processes in the process group (KillMode=mixed).
#
# nginx signals reference doc:
# http://nginx.org/en/docs/control.html
#
[Unit]
Description=A high performance web server and a reverse proxy server
Documentation=man:nginx(8)
After=network.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
# 起動前に /tmp/tls.sock を削除する設定を追加
ExecStartPre=/bin/rm -f /tmp/tls.sock
# 起動前に /tmp/https.sock を削除する設定を追加
ExecStartPre=/bin/rm -f /tmp/https.sock   
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
# 変更前の設定
# ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
# 変更後の設定
ExecStop=-/sbin/start-stop-daemon --quiet --stop --signal TERM --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed

[Install]
 WantedBy=multi-user.target
```

- `ExecStartPre=/bin/rm -f /tmp/tls.sock` を追加してください
- `ExecStartPre=/bin/rm -f /tmp/https.sock` を追加してください
- `ExecStop=-/sbin/start-stop-daemon --quiet --stop --signal TERM --pidfile /run/nginx.pid` に変更してください。

その後、以下のコマンドを実行してください。

```console
$ sudo systemctl daemon-reload
$ sudo systemctl restart nginx
```

## カーネルパラメーターの適用

Sora は UDP を利用します。音声や映像の配信では大量の UDP を処理するため Linux のデフォルトの設定だと厳しい場合があります。

そのため、パラメーターの変更を推奨しています。

詳細は [Linux カーネルチューニング](LINUX_KERNEL_TUNING.html) をご確認ください。

## コンテナ環境での利用する場合

### 認識するコア数と利用できるコア数に矛盾がないかの確認

Sora をコンテナ環境で利用する場合、
コンテナが認識するコア数と実際にコンテナが利用できるなコア数が異なる環境があります。

Sora は **コンテナが認識するコア数を想定した挙動** をするため、
Sora の性能劣化が発生する場合があります。

コンテナが認識するコア数とコンテナが利用できるコア数が異なる場合は **必ずサポートまでご連絡ください** 。

コンテナが認識するコア数は以下のコマンドで確認できます。

```bash
$ grep processor /proc/cpuinfo | wc -l
```

- AWS ECS on EC2 利用時にコンテナが認識するコア数と利用できるコア数が異なる事を確認しています

## SDK の利用

Sora へ接続をする場合は弊社がオープンソースとして公開している SDK を利用してください。


これらのライブラリは弊社によって最新版の Sora で動作するようにメンテナンスされています。

導入もとても簡単になっているので、是非利用してください。

> **重要**
>
> SDK に関する質問・要望・バグなどの報告は Discord の利用をお願いします。
> Sora のライセンス契約の有無に関わらず、
> 応答時間と問題の解決を保証しませんのでご了承ください。
>
> ただし、明らかなバグについては優先的に対応しますので、ご安心ください。



SDK の質問や相談については `sora-sdk-faq` を利用してください。

- Sora JavaScript SDK- 投稿時に `sora-js-sdk` タグを指定してください
- Sora iOS SDK- 投稿時に `sora-ios-sdk` タグを指定してください
- Sora Android SDK- 投稿時に `sora-android-sdk` タグを指定してください
- Sora Unity SDK- 投稿時に `sora-unity-sdk` タグを指定してください
- Sora C++ SDK- 投稿時に `sora-cpp-sdk` タグを指定してください
- Sora Python SDK- 投稿時に `sora-python-sdk` タグを指定してください
- Sora C SDK- 投稿時に `sora-c-sdk` タグを指定してください

## やりたいことが 1:1 の双方向配信の場合

配信が 1:1 の双方向の場合はマルチストリーム機能を利用してください。

詳細は [マルチストリーム機能](MULTISTREAM.html) をご確認ください。

## やりたいことが複数人での双方向配信の場合

複数人で双方向の配信を行いたい場合はスポットライト機能を検討してください。

スポットライト機能を利用することで、クライアントとサーバー側の負荷をかなり抑えられるようになります。

詳細は [スポットライト機能](SPOTLIGHT.html) をご確認ください。

## やりたいことが 1:多 の双方向配信の場合

配信が 1:多 の片方向の場合でもマルチストリーム機能を利用してください。

`role` に `sendonly` と `recvonly` を利用してください。

詳細は [マルチストリーム機能](MULTISTREAM.html) をご確認ください。

## やりたいことが 1:多 の片方向配信で、大規模の場合

配信が 1:多 の片方向で大規模な場合は、クラスターリレー機能を利用してください。

クラスターリレー機能を利用することで、1 チャネルで大規模な配信を行うことができます。

詳細は [リレー機能](CLUSTER.html#4b3bf1) をご確認ください。

## やりたいことが OBS からの配信の場合

OBS からの配信を行いたい場合は OBS (WHIP) 対応機能を利用してください。

詳細は [WHIP 機能](WHIP.html) をご確認ください。

## やりたいことが OBS での取り込みの場合

OBS へ取り込みを行いたい場合は OBS (WHEP) 対応機能を利用してください。

詳細は [WHEP 機能](WHEP.html) をご確認ください。

## Edge が機能要件に含まれている場合

最新の Edge であれば、ほとんど Chrome と同じ動きをしますので安心してお使いください。

## Firefox が機能要件に含まれている場合

Firefox の WebRTC 実装はかなり中途半端なため、
できるだけ Firefox は機能要件から外すことをお勧めします。

## 認証を外部の指定した HTTP サーバーで判断したい場合

認証ウェブフック機能を利用してください。この機能は外部の指定した HTTP サーバーで認証を判断できるようになります。

外部の HTTP サーバーの URL 指定は `sora.conf` の [auth_webhook_url](SORA_CONF.html#36a99a) に設定してください。

そうすることで、外部に認証を移譲できます。

詳細は [認証ウェブフック](AUTH_WEBHOOK.html) をご確認ください。

## 接続、切断の検知を外部の指定した HTTP サーバーで利用したい場合

イベントウェブフック機能を利用してください。この機能は外部の指定した HTTP サーバーでクライアント単位での接続、切断を検知できるようになります。

外部の HTTP サーバーの URL 指定は `sora.conf` の [event_webhook_url](SORA_CONF.html#e1a4d2) に設定してください。

そうすることで、外部にイベントをリクエスト送信できます。

詳細は [イベントウェブフック](EVENT_WEBHOOK.html) をご確認ください。

## 配信されている音声や映像を記録したい場合

Sora には録画機能があります。もし利用を検討されている場合はいくつか注意事項があります。

- 録画を終了させる、またはクライアントが切断するまで、録画ファイルは生成されない
- 複数人数が参加する会議の録画ファイルはクライアントごとに生成される- 5 人が会議に参加していれば 5 個ファイルが生成されます

これらを踏まえて録画機能の利用を検討してください。

録画機能の詳細は [録画機能](RECORDING.html) をご確認ください。

## クライアント側で参加してきたユーザーの情報を通知したい場合

Sora では「〜さんが会議に参加しました」や「〜さんが会議から退席しました」というメッセージをクライアント側で流すことができます。

これにはシグナリング通知を利用します。

シグナリング通知機能はシグナリングで利用している WebSocket もしくは DataChannel を経由して、
参加しているチャネルに新しく参加、または退席した状態を通知する機能です。自分が参加したときも自身に参加通知は飛びます。

ただシグナリング通知に含まれる標準の情報はあくまでコネクション ID のみになるため、
そのコネクション ID が誰なのかはどこからか取得する必要があります。

そのコネクション ID が誰なのかを問い合わせる処理が毎回走ってしまうのは無駄なため、
認証ウェブフックの戻り値で、 `signaling_notify_metadata` （シグナリング通知メタデータ）にそのコネクション ID の値のユーザー名を含めてください。
そうすることで、Sora がその参加者のユーザー名を `signaling_notify_metadata` に含めて返すようになります。

この `signaling_notify_metadata` は新しく参加した人には `data` として、
既存の参加している人の `signaling_notify_metadata` が含まれたリストが参加時に通知されるようになっています。

さらに、新しく参加者がいた場合はその参加者の `metadata` が通知されます。もちろん退席者の場合でもその退席者の `metadata` が含まれて通知されます。

`metadata` にユーザー名が含まれるため、サーバーへ問い合わせをしなくても参加者や退席者のユーザー名を取得できます。

シグナリング通知の詳細は [シグナリング通知](SIGNALING_NOTIFY.html) をご確認ください。

シグナリング通知メタデータの詳細は [シグナリング通知メタデータ](SIGNALING_NOTIFY_METADATA.html) をご確認ください。
