NAT＋VM環境でBigBlueButtonサーバを立ててみた(その3)

#はじめに
ここでは、BigBlueButtonサーバのインストールを説明する。
WebRTCを使うため、SSL証明書を取得するが、インストーラは**標準でLet's Encryptを使う**。
使いたくない人は、別途SSL証明書を取得すること。

※公式サイト: https://github.com/bigbluebutton/bbb-install

その1. [Ubuntu仮想マシンの準備](https://qiita.com/maron2000/items/4ff878c1984f408efb4c)
その2. [フリーのドメインと、ワイルドカードのSSL証明書の取得](https://qiita.com/maron2000/items/834aa44d380f0f1312ce)

20201109更新 STUNサーバの設定で項目を追加

#1.インストーラのダウンロード
```shell
wget https://ubuntu.bigbluebutton.org/bbb-install.sh
```
##インストーラの修正
IPアドレスの取得のところで失敗することがあるので、その場合はget_IP()関数を以下のように修正する。

```shell:bbb-install.sh
get_IP() {
　(略)
  # Check if we can reach the server through it's external IP address
  # if nc -zvw3 $external_ip 443  > /dev/null 2>&1; then <==コメントアウト
     external_ip=$(curl inet-ip.info/ip)  #　<==追加(もしくはIPアドレス直打ち)
     INTERNAL_IP=$IP
     IP=$external_ip
  #fi　<==コメントアウト
  (略)
} 
```

#2.インストールの実行
標準のフロントエンドとして、Greenlightがある。特に理由がなければ一緒にインストールすることをお薦めする。
別途SSL証明書を取得済みの場合は -d オプションで取得手続きを省略する。

```shell
sudo bbb-install.sh -v xenial-22 -s bbb.example.com -e info@example.com -g -d
# -v インストールするバージョン
# -s サーバ名
# -e eメールアドレス(Let's Encrypt設定用)
# -g Greenlightをインストールする
# -d SSL証明書を取得しない(取得済みのものを使う)
```

#3.各種設定
##nginxの設定(SSL証明書をインストーラとは別に取得した場合)
以下を追加または修正(他の部分はいじらなくて良い）。
証明書の場所や名前は適宜修正。
(以下の例はcertbotを使った場合の標準の保存場所)

```shell:/etc/nginx/sites-available/bigbluebutton
server {
  server_name bigbluebutton.hogehoge.com; #自分のサーバ名
  listen 80;
  listen [::]:80;
  listen 443 ssl;
  listen [::]:443 ssl;
  #fullchain.pem: サーバ証明書と中間証明書が結合された証明書
  ssl_certificate /etc/letsencrypt/live/hogehoge.com/fullchain.pem;
  #privkey.pem: 秘密鍵
  ssl_certificate_key /etc/letsencrypt/live/hogehoge.com/privkey.pem;
  ssl_session_cache shared:SSL:10m;
  ssl_session_timeout 10m;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS:!AES256";
  ssl_prefer_server_ciphers on;
  ssl_dhparam /etc/nginx/ssl/dhp-4096.pem;
```

##NAT環境関連の設定
ファイアウォール関連で設定変更が必要。
https://docs.bigbluebutton.org/2.2/configure-firewall.html
インストールスクリプトが大体やってくれているが、IPアドレスが変わると一緒に変更が必要となるので、以下のスクリプトで一括して変更する。
※2020/08/04編集: IPアドレスをSTUNサーバから取得するように変更

```shell:apply-config.sh
#!/bin/bash
DOMAIN_NAME="www.hogehoge.com" #自分のサーバ名に変更
STUN_SERVER="stun.l.google.com"
STUN_PORT="19302"  #Standard port for STUN server: 3478

LOCAL_IP=$(hostname -I | cut -f1 -d' ')
while [ -z $LOCAL_IP ]
do
	LOCAL_IP=$(hostname -I | cut -f1 -d' ')
	sleep 1s
done

sleep 1s
#EXTERNAL_IP=$(curl -s https://ipv4.icanhazip.com/)
#if [ -z $EXTERNAL_IP ]; then
#	sleep 1s
#	echo "EXTERNAL_IP: icanhazip.com failed"	
#	EXTERNAL_IP=$(curl -s https://myexternalip.com/raw)
#elif [ -z $EXTERNAL_IP ]; then
#	sleep 1s
#	echo "EXTERNAL_IP: myexternalip.com failed"	
#	EXTERNAL_IP=$(curl -s https://ipinfo.io/ip)
#elif [ -z $EXTERNAL_IP ]; then 
#	echo "Failed to designate EXTERNAL_IP"
#fi

#20200804修正: STUNサーバからIPアドレスを取得
for i in {1..10} 
do
    STUN_RESULT=$(stun $STUN_SERVER:$STUN_PORT -v 2>&1)
    EXTERNAL_IP=$(echo "$STUN_RESULT" |& grep -m 1 "Mapped" | \
        grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')

    if [ -n "$EXTERNAL_IP" ]; then
        echo "EXTERNAL_IP = $EXTERNAL_IP"
        break   
    fi
    sleep 1s
done
if [ -z $EXTERNAL_IP ]; then 
    echo "Failed to designate EXTERNAL_IP"
    echo "$STUN_RESULT" 
    exit 1
fi

echo `date`

echo "$LOCAL_IP $EXTERNAL_IP"

# refer to https://docs.bigbluebutton.org/2.2/configure-firewall.html for details

sed -i "s/\(name=\"ext-rtp-ip\"\).*/\1 value=\"\$\${external_rtp_ip}\"\/>/g" /opt/freeswitch/etc/freeswitch/sip_profiles/external.xml
sed -i "s/\(name=\"ext-sip-ip\"\).*/\1 value=\"\$\${external_sip_ip}\"\/>/g" /opt/freeswitch/etc/freeswitch/sip_profiles/external.xml

SEARCH_EXT_IP=$(grep $EXTERNAL_IP /opt/freeswitch/etc/freeswitch/vars.xml)
SEARCH_LOCAL_IP=$(grep $LOCAL_IP /opt/freeswitch/etc/freeswitch/vars.xml)
#echo "$SEARCH_EXT_IP $SEARCH_LOCAL_IP";

if [ "$SEARCH_EXT_IP" ] && [ "$SEARCH_LOCAL_IP" ]; then
	echo "IP address not changed";
else
	OLD_IP=$(cat /usr/local/bigbluebutton/bbb-webrtc-sfu/config/default.yml | grep "^ *ip: " - | sed "s/^  *ip: *\(.*\)/\1/g")
        #echo "$SEARCH_EXT_IP $SEARCH_LOCAL_IP";
	echo "IP address changed";
	sed -i "s/proxy_pass http.*/proxy_pass https:\/\/$EXTERNAL_IP:7443;/g" /etc/bigbluebutton/nginx/sip.nginx
	sed -i "s/\(  *ip:\).*/\1 $EXTERNAL_IP/g" /usr/local/bigbluebutton/bbb-webrtc-sfu/config/default.yml
	sed -i "s/\(  *sip_ip:\).*/\1 $LOCAL_IP/g" /usr/local/bigbluebutton/bbb-webrtc-sfu/config/default.yml
        # 20200720 修正 EXTERNAL_IP → LOCAL_IP
	sed -i "s/\(localIpAddress:\).*/\1 $LOCAL_IP/g" /usr/local/bigbluebutton/bbb-webrtc-sfu/config/default.yml
	sed -i "s/\(name=\"wss-binding\"\).*/\1 value=\"$EXTERNAL_IP:7443\"\/>/g" /opt/freeswitch/etc/freeswitch/sip_profiles/external.xml
	sed -i "s/\"external_rtp_ip=.*\"/\"external_rtp_ip=$EXTERNAL_IP\"/g" /opt/freeswitch/etc/freeswitch/vars.xml
	sed -i "s/\"external_sip_ip=.*\"/\"external_sip_ip=$EXTERNAL_IP\"/g" /opt/freeswitch/etc/freeswitch/vars.xml
	sed -i "s/\"local_ip_v4=.*\"/\"local_ip_v4=$LOCAL_IP\"/g" /opt/freeswitch/etc/freeswitch/vars.xml

	#external hostname
    SEARCH_HOST=$(grep $DOMAIN_NAME /etc/hosts)
    if [ "$SEARCH_HOST" ]; then
        sed -i "s/.*$DOMAIN_NAME/$EXTERNAL_IP $DOMAIN_NAME/g" /etc/hosts
    else
        echo "$EXTERNAL_IP $DOMAIN_NAME" >> /etc/hosts
    fi

	#dummy NIC
	sed -i "s/^ExecStart.*/ExecStart=\/sbin\/ip addr add $EXTERNAL_IP dev lo/g" /lib/systemd/system/dummy-nic.service;
	
    # Restart server
    if [ ! $OLD_IP = "127.0.0.1" ]; then
        /sbin/ip addr delete $OLD_IP/32 dev lo
    fi
    /sbin/ip addr add $EXTERNAL_IP dev lo
    bbb-conf --restart
    systemctl restart nginx
fi
```
こちらも`sudo crontab -e`で自動実行するようにする。

```shell:sudo&nbsp;crontab&nbsp;-e
3-58/5 * * * * bash /usr/local/bin/apply-config.sh > /var/log/apply-config.log 2>&1
@reboot /usr/local/bin/apply-config.sh > /var/log/apply-config.log 2>&1
```
##ホストOSからアクセスするためのアドレス設定
ルータの設定によっては、グローバルアドレスではつながらないので、hostsファイルに仮想マシンのローカルIPアドレスを設定する。

```shell:\Windows\System32\drivers\etc\hosts&nbsp;(ホストOS側)
192.168.XX.XX www.hogehoge.com
```
##STUNサーバの設定
静的NATまたはDMZの時はポートをそのままサーバに中継するので不要だが、転送できない場合はSTUNサーバの設定が必要。
詳細は以下を参照されたい。
https://kurento.readthedocs.io/en/stable/doc/admin_guide.html#installation

具体的には、以下の通り設定する。なぜかサーバ名ではなく、**IPアドレスで指定**しなければならないので注意。
例えば、stun.l.google.com:19302の場合は以下のようになる。

```shell:/etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini
stunServerAddress=74.125.23.127
stunServerPort=19302
#つながらない場合は、以下を設定してみる(インターフェース名は自分の環境に合わせる）。
networkInterfaces=ens33
```
*iOSデバイスでカメラ共有の不具合* がある場合は、さらに以下を設定する。
【リンク】[BigbluebuttonでiOSデバイスのカメラが使用できない件](https://qiita.com/maron2000/items/293ae18845919b9b4aa8)

```/usr/share/bbb-web/WEB-INF/classes/spring/turn-stun-servers.xml
<!-- 一部抜粋 -->
<bean id="stun1" class="org.bigbluebutton.web.services.turn.StunServer">
   <!-- constructor-arg index="0" value="stun:stun.freeswitch.org"/ --> <!--修正前 -->
   <constructor-arg index="0" value="stun:stun.l.google.com:19302"/> <!--修正後 -->
</bean>
```

#4.サーバの起動
設定が終わったら、サーバを起動`sudo bbb-conf --restart`してみる。
ローカルと外から見たIPアドレスが違うのでワーニングが出るが、NAT環境では当然違うので問題ない。

```shell:sudo&nbsp;bbb-conf&nbsp;--restart
# IP does not match:
#                           IP from ifconfig: 192.168.XX.XX
#   /etc/nginx/sites-available/bigbluebutton: www.hogehoge.com
Restarting BigBlueButton 2.2.9 ...
Stopping BigBlueButton
Starting BigBlueButton

# Potential problems described below
# IP does not match:
#                           IP from ifconfig: 192.168.XX.XX
#   /etc/nginx/sites-available/bigbluebutton: www.hogehoge.com
........................
# Warning: The setting of 123.YYY.YYY.YYY for proxy_pass in
#
#    /etc/bigbluebutton/nginx/sip.nginx
#
# does not match the local IP address (192.168.XX.XX).
# (This is OK if you've manually changed the values)
```
他にエラーが出るようなら、`sudo bbb-conf --check`の結果を見比べてみる。

```shell:sudo&nbsp;bbb-conf&nbsp;--check
BigBlueButton Server 2.2.9 (1891)
                    Kernel version: 4.4.0-178-generic
                      Distribution: Ubuntu 16.04.6 LTS (64-bit)
                            Memory: 16414 MB
                         CPU cores: 4

/usr/share/bbb-web/WEB-INF/classes/bigbluebutton.properties (bbb-web)
       bigbluebutton.web.serverURL: https://www.hogehoge.com
                defaultGuestPolicy: ALWAYS_ACCEPT
                 svgImagesRequired: true

/etc/nginx/sites-available/bigbluebutton (nginx)
                       server name: www.hogehoge.com
                              port: 80, [::]:80
                              port: 443 ssl
                    bbb-client dir: /var/www/bigbluebutton

/var/www/bigbluebutton/client/conf/config.xml (bbb-client)
                Port test (tunnel): rtmp://www.hogehoge.com
                              red5: www.hogehoge.com
              useWebrtcIfAvailable: true

/opt/freeswitch/etc/freeswitch/vars.xml (FreeSWITCH)
                       local_ip_v4: 192.168.XX.XX
                   external_rtp_ip: 123.YYY.YYY.YYY
                   external_sip_ip: 123.YYY.YYY.YYY

/opt/freeswitch/etc/freeswitch/sip_profiles/external.xml (FreeSWITCH)
                        ext-rtp-ip: $${external_rtp_ip}
                        ext-sip-ip: $${external_sip_ip}
                        ws-binding: :5066
                       wss-binding: 123.YYY.YYY.YYY:7443

/usr/local/bigbluebutton/core/scripts/bigbluebutton.yml (record and playback)
                     playback_host: www.hogehoge.com
                 playback_protocol: https
                            ffmpeg: 4.2.2-1bbb1~ubuntu16.04

/etc/bigbluebutton/nginx/sip.nginx (sip.nginx)
                        proxy_pass: 123.YYY.YYY.YYY

/usr/local/bigbluebutton/bbb-webrtc-sfu/config/default.yml (Kurento SFU)
                        kurento.ip: 123.YYY.YYY.YYY
                       kurento.url: ws://127.0.0.1:8888/kurento
                    localIpAddress: 192.168.XX.XX
               recordScreenSharing: true
                     recordWebcams: true
                  codec_video_main: VP8
               codec_video_content: VP8

/usr/share/meteor/bundle/programs/server/assets/app/config/settings.yml (HTML5 client)
                             build: 894
                        kurentoUrl: wss://www.hogehoge.com/bbb-webrtc-sfu
                  enableListenOnly: true


# Potential problems described below
# IP does not match:
#                           IP from ifconfig: 192.168.XX.XX
#   /etc/nginx/sites-available/bigbluebutton: www.hogehoge.com

# Warning: The setting of 123.YYY.YYY.YYY for proxy_pass in
#
#    /etc/bigbluebutton/nginx/sip.nginx
#
# does not match the local IP address (192.168.XX.XX).
# (This is OK if you've manually changed the values)
```
#5. サーバへアクセス
ブラウザからアクセスしてみよう。
`https://サーバ名`

![起動画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577966/070e17b8-e88c-ff70-7a43-46ea6b813238.png)

#6.その4へ
ようやくサーバが起動できたので、次はユーザ設定を説明する。