インフィニットループ 技術ブログ

2022年03月02日 (水)

著者 : nob

続 Mozilla Hubs – VirtualBox でホストした自作シーンに入ってみた

みなさんメタバース盛り上がってますか!インフラエンジニアの nobuh です。
前回の記事 Mozilla Hubs を VirtualBox でホストしてみた に続いて、PC 上の VirtualBox を使い、今回は 真っ黒ではない自作シーンのルーム に入るところまでを動作確認出来ましたので、その方法を共有したいと思います!

Mozilla Hubs って?

詳しくは前回の記事 Mozilla Hubs を VirtualBox でホストしてみた でも解説していますが、Mozilla Hubs は Mozilla 社が提供している VR のサービスで、オープンソースでも公開されていて、それを  PC 上の VirtualBox で運用してみよう! というのが今回の Mozilla Hubs 挑戦シリーズの趣旨になります。

VirtualBox でのサーバー準備

OS 廻りの基本的なところは前回の記事と同じですが、再び概要を列挙いたします。
VirtualBox 設定

  • OS : 64 bit Linux
  • ネットワークアダプタ: ブリッジネットワーク を使います
  • CPU : 2個以上
  • メモリ :最少 5G 、推奨 8G 以上
  • 仮想ディスク: 30G 以上

Debian 11 インストール

  • インストーラー CD : Debian 11.2 bullseye netinst iso
  • 国: Asia, Japan
  • ロケール : en_US.UTF-8 (メッセージ調査が簡単になるので US にしてます)
  • hostname : hubs
  • domain : local
  • 追加 user : ops2 としましたが何でも可
  • パッケージ : ssh, standard utilities のみチェックを付けます。使わない Desktop とかはチェックを外します
  • IP アドレス:DHCP で取得した IP をそのまま使っています。お好みで static ip に変更してもかまいません

言語ランタイムは後述する asdf で用意していますので Debian に限らず最近の Ubuntu であればどのバージョンでも問題ないと思われます

OS まわりセットアップ

root でログインし使うパッケージをインストールします。

    apt-get update
    apt install libssl-dev automake autoconf libncurses5-dev make unzip g++
    apt install inotify-tools curl git dirmngr gpg gawk sudo
    apt install ca-certificates gnupg lsb-release

sysctl で fs.innotify.max_user_watches の数を表示し

    root@hubs:~# sysctl fs.inotify.max_user_watches
    fs.inotify.max_user_watches = 50000

5万以下であった場合は /etc/sysctl.conffs.inotify.max_user_watches = 50000 を追記して

    sysctl --system

で反映してください

DNS 代わりの /etc/hosts 編集

今回は独自ドメインではなくデフォルトの hubs.localhubs-proxy.local を使う前提で設定を進めていきます。
VirtualBox のサーバー上の /etc/hosts は以下に設定します。

    127.0.0.1	localhost hubs hubs.local hubs-proxy.local

ブラウザを動かすクライアントPC自体の /etc/hosts は以下に設定します。(VirtualBox のサーバーの IP が 192.168.0.7 の例)

    192.168.0.7  hubs.local hubs-proxy.local

ユーザーと作業ディレクトリ作成

ユーザー ops2 に sudo 権限を付与します。

    adduser ops2
    usermod -aG sudo ops2

言語ランタイムのキャッシュや設定はユーザーの $HOME 直下の .cache などに蓄積されますので、Mozilla Hubs のインストールをやり直す場合は今回のようにユーザーから新規に作り直すのがお薦めです。
以上で root を一度ログアウトし、sudo 付与済みの ops2 で作業を行っていきます。
ops2 のホーム下に作業用に mozilla ディレクトリを作成しておきます

    cd && mkdir mozilla && cd mozilla

Docker と PostgreSQL 11 セットアップ

指定されている Postgres が 11 とやや古いため docker を使ってセットアップします。

    curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
    echo \
    "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update
    sudo apt-get install docker-ce docker-ce-cli containerd.io

一度ログアウト後 docker-compose をインストールします。

    sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

docker-compose.yml ファイルを以下の内容で作成します。

    version: '3'
    services:
        db:
            image: postgres:11
            environment:
                POSTGRES_USER: postgres
                POSTGRES_PASSWORD: postgres
            volumes:
                - ./tmp/db:/var/lib/postgresql/data
            ports:
                - "127.0.0.1:5432:5432"

起動します

    sudo docker-compose up -d

asdf で node.js v12 セットアップ

node.js や elixir といった各言語のランタイムは asdf を使って特定バージョンを使えるようにします。
まずは asdf をインストール

    git clone https://github.com/asdf-vm/asdf.git ~/.asdf
    echo '. $HOME/.asdf/asdf.sh' >> ~/.bashrc
    echo '. $HOME/.asdf/completions/asdf.bash' >> ~/.bashrc
    exec $SHELL -l

最初に node.js v12 (erbium) をインストールします。

    asdf plugin add nodejs
    asdf install nodejs lts-erbium
    asdf global nodejs lts-erbium

自己署名証明書作成

今回は Mozilla Hubs 指定のデフォルトの hubs.local と hubs-proxy.local を使っていますが、それでもデフォルトで自動生成される自己署名証明書の多くは鍵長が足りていない、Subject Alt Name (SAN) が無いなどのエラーを起こしましたので、自分で新規に作成します。

    mkdir ~/certs && cd ~/certs
    echo subjectAltName = DNS:hubs.local,DNS:hubs-proxy.local > san.txt
    openssl genrsa -out server.key 2048
    openssl req -out server.csr -key server.key -new

組織名など聞かれますが何でもかまいません。Common Name (CN) だけは hubs.local で入力してください。(例)

    Country Name (2 letter code) [AU]:JP
    State or Province Name (full name) [Some-State]:Hokkaido
    Locality Name (eg, city) []:Sapporo
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:infiniteloop Co,Ltd
    Organizational Unit Name (eg, section) []:NOBUH
    Common Name (e.g. server FQDN or YOUR name) []:hubs.local

csr が出来たら san.txt と合わせて自分で署名して証明書を生成します

    openssl x509 -req -days 3650 -signkey server.key -in server.csr -out server.crt -extfile san.txt

Hubs セットアップ

GitHub の Hubs リポジトリを clone しますが、変更が激しいためこの記事で確認出来ている特定 commit 4fe2529a9 まで戻します。

    cd ~/mozilla
    git clone https://github.com/mozilla/hubs.git
    cd hubs
    git reset --hard 4fe2529a9

certs ディレクトリを作成、最初に作っておいた証明書をシンボリックリンクで配置します。ファイル名は cert.pem と key.pem 固定です。

    mkdir certs
    ln -s ~/certs/server.crt certs/cert.pem
    ln -s ~/certs/server.key certs/key.pem

他のコンフィグはそのまま修正不要です。local モードで起動します。

    npm ci
    npm run local

ブラウザで https://hubs.local:8080/ にアクセスします。オレオレ証明書のため各社のブラウザで警告が出ますが、無視してアクセスする操作を行います。なんらかのページが表示されていれば OK です。以下 Chrome の例

Admin セットアップ

Hubs のターミナルはそのまま。別のターミナルを開き ops2 でログインします。
次に同じ hubs リポに格納されている admin サーバーをセットアップします。
ここでも作成しておいた証明書を使います。ファイル名も固定です。

    cd ~/mozilla/hubs/admin
    mkdir certs
    ln -s ~/certs/server.crt certs/cert.pem
    ln -s ~/certs/server.key certs/key.pem

起動します。(時間がかかります)

    npm ci
    npm run local

https://hubs.local:8989/ にアクセスして Hubs と同じように証明書を例外承認します。
admin サーバーは稼動させたまま。別のターミナルを開きます。

Spoke セットアップ

シーンエディタの Spoke サーバーをセットアップします。こちらも把握出来ている commit まで戻してください。

    cd ~/mozilla
    git clone https://github.com/mozilla/Spoke
    cd Spoke
    git reset --hard 9669ef73

yarn と corss-env を npm でインストールします。

    npm install -g yarn
    npm install -g cross-env

必要なパッケージをインストールし

    yarn install

ここでも証明書を配置します。

    mkdir certs
    ln -s ~/certs/server.crt certs/cert.pem
    ln -s ~/certs/server.key certs/key.pem

Spoke サーバーを起動します。

    ./scripts/run-local-reticulum.sh

https://hubs.local:9090/ にアクセスし、例外承認をして何がしかのトップ画面が表示されていれば問題ないです。

Reticulum セットアップ

Hubs, Admin, Spoke の3つのサーバーが起動されている状態になりましたら、いよいよ中心的なサーバーになる Reticulum サーバーのセットアップに入ります。
Erlang 22 と Elixir 1.8 のインストール
前回の記事では Erlang 23 と Elixir 1.12 を使っていましたが、今回は Erlang 22 と Elixir 1.8 を使いますので注意してください。

    asdf plugin add erlang
    asdf install erlang 22.3.4.24
    asdf global erlang 22.3.4.24
    asdf plugin add elixir
    asdf install elixir 1.8.2-otp-22
    asdf global elixir 1.8.2-otp-22

次に Reticulum のソースを clone し、把握しているコミットまで戻します。

    cd ~/mozilla
    git clone https://github.com/mozilla/reticulum.git
    cd reticulum
    git reset --hard fc80a577

elixir のツール mix や phoenix フレームワークでのビルドを進めます。

    mix local.hex --force
    mix deps.get
    mix local.rebar --force
    mix ecto.create
    mkdir -p storage/dev

証明書を配置します。

    ln -s ~/certs/server.key priv/server.key
    ln -s ~/certs/server.crt priv/server.crt

Dialog 音声サーバーとの通信用の 1024 ビット RSA 秘密鍵 perms.priv.pem と公開鍵 perms.pub.pem を用意します。

    cd priv
    openssl genrsa 1024 > perms.priv.pem
    openssl rsa -pubout < perms.priv.pem > perms.pub.pem

さらに秘密鍵の値の改行を素の2文字 ‘\n’ に変換したファイル perms.priv.pem.line を sed で作成します。

    sed -z 's/\n/\\n/g' perms.priv.pem |sed -E 's/\\n$/\n/g' > perms.priv.pem.line

config/dev.exs ファイルの中の以下の4点を修正します。

  • dev_janus_host を hubs.local にする
  • keyfile/certfile のパスを自分が置いた server.key, server.crt に
  • perms_key の文字列の値として perms.priv.pem.line の内容を貼り付ける
  • janus_port を 443 から 4443 に
        dev_janus_host = "dev-janus.reticulum.io"
            ↓
        dev_janus_host = "hubs.local"
        keyfile: "#{File.cwd!()}/priv/dev-ssl.key",
        certfile: "#{File.cwd!()}/priv/dev-ssl.cert"
            ↓
        keyfile: "#{File.cwd!()}/priv/server.key",
        certfile: "#{File.cwd!()}/priv/server.crt"
        config :ret, Ret.PermsToken, perms_key: (System.get_env("PERMS_KEY") || "") |> String.replace("\\n", "\n")
            ↓
        config :ret, Ret.PermsToken, perms_key: "ここに perms.priv.pem.line の内容を貼り付けます"
        config :ret, Ret.JanusLoadStatus, default_janus_host: dev_janus_host, janus_port: 443
            ↓
        config :ret, Ret.JanusLoadStatus, default_janus_host: dev_janus_host, janus_port: 4443

ここで一度 dev モードの Reticulum を起動します。

    cd ~/mozilla/reticulum
    iex -S mix phx.server

https://hubs.local:4000/health にアクセスして ok と表示されているか確認します。

次に Reticulum のサーバーで skipadmin オプション付きでトップページが表示されるのを確認します https://hubs.local:4000/?skipadmin

さらにトップページの Sign In/Sign up ボタンを押すとメールアドレスを入れるダイアログが出ます。今回の設定ではまだメール機能は使えてませんので、適当なアドレスを入力します。(例)nobuh@hubs.local

Next を押しますが、メールは届きません。代わりに Reticulum を起動したコンソールで、リンクを送信した旨のログ(黄色の線)を見つけます。

同じブラウザでリンクを貼り付けて実行すると Verification Complete の表示が出て、右上の自分のアカウントでログイン済みの表示になります。

次にシーンエディタ Spoke のページ https://hubs.local:4000/spoke を開いて、右上が Logout のメニューになっていれば OK です。

ログイン状態が確認できましたら、今ログインしたユーザーに管理権限をつけます。Reticulum の iex プロンプトで1行コマンド

    Ret.Account |> Ret.Repo.all() |> Enum.at(0) |> Ecto.Changeset.change(is_admin: true) |> Ret.Repo.update!()

を実行します

Coturn と Dialog のセットアップ

Reticulum のユーザー管理が無事動いてることが確認出来ましたら、次に音声サーバーのセットアップを行います。
まずは UDP の通信で必要になる STUN/TURN サーバーの coturn をインストールします。

    sudo apt install coturn

/etc/turnserver.conf の psql-userdb の行のコメントを外し以下に変更します。

    #psql-userdb="host=<host> dbname=<database-name> user=<database-user> password=<database-user-password> connect_timeout=30"
        ↓
    psql-userdb="host=127.0.0.1 dbname=ret_dev user=postgres password=postgres options='-c search_path=coturn' connect_timeout=30"

設定を反映するため再起動します。

    sudo systemctl restart coturn

最後に WebRTC Mediasoup の Dialog サーバーをインストールします。

    cd ~/mozilla
    git clone https://github.com/mozilla/dialog.git
    cd dialog
    git reset --hard 4edefad
    npm install

certs ディレクトリを作成し、証明書をファイル名 fullchain.pem, privkey.pem で配置します。また、reticulum で作成した通信用公開鍵もここに配置します。

    mkdir certs && cd certs
    ln -s ~/certs/server.crt fullchain.pem
    ln -s ~/certs/server.key privkey.pem
    ln -s ~/mozilla/reticulum/priv/perms.pub.pem .
    cd ..

自分のサーバーの IP (例 192.168.0.7)を指定して起動します。

    MEDIASOUP_LISTEN_IP=0.0.0.0 MEDIASOUP_ANNOUNCED_IP=192.168.0.7 npm start

トップ画面 https://hubs.local:4000/ から「部屋を作る」で前回の記事と同様な真っ暗な部屋に入れれば音声サーバー設定は無事完了です。

自己署名証明書を使っている際によく発生すること

事前に以下の 4 URL を踏んで証明書の例外承認をしたブラウザから最後に Reticulum にアクセスする必要がありますが、つい忘れがちですのでまとめて再掲いたします。

オリジナルなシーン作成

長い準備でしたがサーバーがようやく完成しました。ここからが本記事の本題です!
https://hubs.local:4000/spoke にアクセスし New Project ボタンを押します。
自作の Reticulum サーバーにはプロジェクトが何もありませんので流用できるプロジェクトが何もありません。New Empty Project を押します。
Blender のようなモデルツールの画面になりますが、早速エラーが表示されます。

これはデフォルトで用意しようとするアセット、黄色で囲んだ Terrain_Crater1.glb が自分のサーバーには無いためエラーになったものです。無くて正しいので ok を押してダイアログを消したあと、Terrain_Crater1.glb を選択して削除しておきます。
Elemets メニューにあるオブジェクトはサーバーが空の状態でも使えますので、Ground Plane と Water その他を置いてみました。この状態で右上の Publish Scene を押します。(Ground Plane などの静的物体となるオブジェクトが1個もないと publish 時に collection is undefined エラー表示で失敗しますので何か一つは物体を足してください)

一度も save していないとまず save するよう促されますので save します。
次に Publish の条件を聞かれます。

  • Allow Remix と
  • Allow Promotion

の2つを聞かれますのでどちらもチェックを付けます。
進めると、パフォーマンスの確認画面になります。重すぎるモデルなどはここで気がつけます。

publish が完了すると open scene のボタンが現れます。この open scene を押すと作成したシーンを使って新しい部屋を生成することが出来ます。

部屋に招待する

  • 部屋にいるときの URL (例 https://hubs.local:4000/BAGfh7d/lustrous-capital-tract )
  • またはハッシュ値までの短いリンク (例 https://hubs.local:4000/BAGfh7d)

を招待リンクとして使えます。(自分と他2名入った様子)

本家 hubs.mozilla.com のモデルの Remix

一から全部モデリングしてルームを作るのは大変ですので、本家 hubs.mozilla.com で公開されているフリーなルームを活用してみます。
https://hubs.mozilla.com/spoke にアクセスし、ユーザー登録をしてください。
Project メニューに利用可能なシーンが沢山ありますので、そのうちの一つ Art Gallery を開いてみます。

File メニューに Export as binary glTF がありますのでエクスポートを実行します。必須ではないですが、メッシュの結合などは利用した方がよいと思います。

ダウンロードすれば本家のサイトでの作業は完了です。
次に https://hubs.local:4000/spoke で自分のサーバーにアクセスします。メニューに Logout が表示された ログイン済み状態であることを忘れず確認してください。
自作シーンのときと同じく New Empty Project を作成し、エラーになっている glb を削除します。Asset メニューの My Assets を選ぶと Upload ボタンがありますので、ダウンロードしておいた glb ファイルをアップロードします。

アップロードすると My Assets の1個のオブジェクトとして登録されるので、選択して自分のシーンに配置します。(このモデルはドアが無い閉じた箱状の空間になっていますので、人が入ってくる Spawn Point が箱の中になるように配置の際は気を付けてください。)

あとは Publish して Open Scene すれば使えます!
以上長文になりましたが、自分の PC 上の VirtualBox のサーバーで Mozilla Hubs のルーム作成機能を使うことが出来ました!!
独自ドメインでの運用や、自作アバターの使用、本物のメールでのユーザー登録など、Mozilla Hubs のホスティングではまだまだ解決すべきところも多々ありますので今後も研究を続けていきたいと思います!
弊社ではメタバースに興味のある xR エンジニアやプログラマ、インフラエンジニアなどを積極募集しておりますので、ご興味ある方はぜひご応募くださいー ⇒ 採用情報

ブログ記事検索

このブログについて

このブログは、札幌市・仙台市の「株式会社インフィニットループ」が運営する技術ブログです。 お仕事で使えるITネタを社員たちが発信します!