みなさんメタバース盛り上がってますか!インフラエンジニアの nobuh です
Facebook も社名を Meta に変更するなど、メタバースが次世代のネットの主役になりえる?可能性があるということで、その動向には目を離せないところです。
すでに実現、実装されているメタバースや VR のプロダクトやサービスもいろいろありますが、今回は Mozilla 社がオープンソースで公開している Mozilla Hubs に注目し、そのサーバーを自分の手元の VirtualBox で動かすことに挑戦してみました!
Mozilla Hubs とは
Mozilla 社の作ったブラウザでアクセス可能な VR の空間共有サービスで、簡単に要約すると3つの形態があります。
- hubs.mozilla.com : Mozilla 社が運営してくれている VR の道具一式がそろったサービスです。
- Hubs Cloud Personal / Hubs Cloud Enterprise : AWS マーケットプレースまたは DigitalOcean でイメージやインスタンスを契約/購入し、それらを使って自分のカスタムドメインのクラウドインスタンスで Mozilla Hubs 一式をホストします。購入したといっても、自分のドメインで運用出来るようにセットアップするまではなかなか手数もかかるようです。
- GitHub で hubs リポジトリ https://github.com/mozilla/hubs や reticulum など Hubs に必要なサーバーのコードが公開されています
今回はこのうちの、GitHub のリポジトリのソースを使い、自分の PC 上の VirtualBox で myhubs.example というテスト用のカスタムドメインで Hubs のサーバーをホストしてみます!
VirtualBox でのサーバー準備
まずは VirtualBox で仮想サーバーを用意します。OS は Debian 11.2 bullseye の netinst iso 版を使いましたが、後述する DB や 言語は docker や asdf を使って用意していますので、おそらく Debian / Ubuntu であればどの Linux ディストリビューションでも問題ないと思います。
VirtualBox でのサーバー追加は全部解説するとスペースが足りませんので、設定の要点のみ列挙いたします。
- OS : 64 bit Linux なら OK, 32 bit では試してないです
- ネットワークアダプタ: ブリッジネットワーク を使います
- CPU : 2個以上
- メモリ :最少でも 5G 、推奨 8G 以上
- 仮想ディスク: 20G ありばとりあえず足ります
同様に Debian のインストールも要点のみ列挙します
- インストーラー CD : Debian 11.2 bullseye netinst iso
- 国: Asia, Japan
- ロケール : en_US.UTF-8 (必須ではないですがエラーメッセージ調査が簡単になるので US にしてます)
- キーボード : Japanese
- hostname : myhubs
- domain : example
- 追加 user : ops としました
- パッケージ : ssh, standard utilities のみチェックを付けます。使わない Desktop とかはチェックを外します
- ネットワーク:ブリッジネットワークにて DHCP で取得した IP をそのまま使っています。お好みで static ip に変更してもかまいません
まず最初に root でログインし ops に sudo 権限を付与します
apt-get update apt install sudo usermod -aG sudo ops
以降本記事では全て ops でログインし作業しているものとします
DNS 代わりの etc/hosts 設定
ブラウザでアクセスする PC と VirtualBox 上の myhubs サーバーと、両方の etc/hosts にサーバーの IP とホスト名を追加します。サーバーの IP が 192.168.0.5 だったときの例
192.168.0.5 myhubs.example
自己署名証明書作成
いわゆるオレオレ証明書ですが、myhubs.example を自分で承認したサーバー証明書を用意します。
ops ユーザーで cert ディレクトリを作成しそこで秘密鍵と CSR を生成します。
Common Name (CN) だけの証明書は非推奨の流れがありますので Subject Alt Name (SAN) も用意します。SAN を用意するのでワイルドカードのドメイン *.myhubs.example を追加しておきました。
mkdir ~/certs && cd certs echo subjectAltName = DNS:myhubs.example,DNS:*.myhubs.example > san.txt openssl genrsa -out server.key 2048 openssl req -out server.csr -key server.key -new
会社名など色々聞かれるが自由に記載してかまいません、 CN には myhubs.example を指定するところだけ忘れずに。
次に CSR と san.txt を合わせて署名して証明書 server.crt を生成します。
openssl x509 -req -days 3650 -signkey server.key -in server.csr -out server.crt -extfile san.txt
生成した証明書の内容を openssl コマンドで確認してみた例です。
ops@myhubs:~/mozilla$ openssl x509 -text -noout -in ../certs/server.crt |grep -C 3 myhubs Serial Number: 4b:99:86:72:ad:ac:40:5a:10:8c:d5:ac:de:ef:f9:ef:16:93:15:cb Signature Algorithm: sha256WithRSAEncryption Issuer: C = JP, ST = Hokkaido, L = Sapporo, O = NOBUH, OU = HUBS, CN = myhubs.example Validity Not Before: Feb 19 14:33:09 2022 GMT Not After : Feb 17 14:33:09 2032 GMT Subject: C = JP, ST = Hokkaido, L = Sapporo, O = NOBUH, OU = HUBS, CN = myhubs.example Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) -- Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Alternative Name: DNS:myhubs.example, DNS:*.myhubs.example Signature Algorithm: sha256WithRSAEncryption 52:72:00:9b:b7:b5:c7:8a:30:ad:d7:9a:9a:87:7e:51:80:2f: 79:e8:00:52:54:37:1d:26:65:67:a2:7b:c2:5b:41:f2:cd:93:
PostgreSQL 11 のために Docker を用意
Hubs で指定されている DB が PostgreSQL 11 で多少古いため、docker を使って準備します。尚、psql クライアントは最新のでも操作できますので単独でインストールしておきます。
sudo apt-get install ca-certificates curl gnupg lsb-release postgresql-client 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
PostgreSQL セットアップ
Hubs の各種リポジトリを入れるディレクトリ mozilla を造り、そこに docker-compose.yml ファイルを作成します。
mkdir ~/mozilla && cd mozilla touch docker-compose.yml
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"
起動し psql で database 一覧を見るなど確認します
sudo docker-compose up -d psql -U postgres -h 127.0.0.1 -c '\l'
asdf をインストール
asdf を使い各言語は任意のバージョンを指定して使えるようにします。
sudo apt install curl git dirmngr gpg gawk 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
Reticulum サーバーのセットアップ
Mozilla Hubs は JS のフロントエンドのサーバーである Hubs と、ユーザー管理やルーム内部の同期などの全てを処理する Reticulum 、音声に使われる Dialog など複数のサーバーで処理を行っています。まず最初に Reticulum サーバーをセットアップします。
git clone https://github.com/mozilla/reticulum.git cd reticulum git reset --hard d627ff04 (今回の手順で構築出来てるのがこの commit で、その後未確認なのでここまで戻してください)
asdf を使って Elixir 1.12 + Erlang 23 を入れます
asdf plugin add erlang asdf plugin add elixir sudo apt install libssl-dev automake autoconf libncurses5-dev make unzip g++ inotify-tools asdf install erlang 23.3.4.11 asdf global erlang 23.3.4.11 asdf install elixir 1.12.3-otp-23 asdf global elixir 1.12.3-otp-23
phoenix フレームワークのアプリのビルドを mix コマンドで行います
mix local.hex --force mix deps.get mix local.rebar --force mix ecto.create mkdir -p storage/dev
最初に作ってあったサーバー証明書を priv/cert ディレクトリを作ってシンボリックリンクで配置します
mkdir -p priv/cert ln -s ~/certs/server.crt priv/cert/ ln -s ~/certs/server.key priv/cert/
次に Dialog との通信用鍵ペアを生成しますが、ここが少し面倒です。
https://travistidwell.com/jsencrypt/demo/ というサービスがありますのでそこで 1024 ビット RSA キーを生成し、priv/cert ディレクトリに以下のファイル名で秘密鍵と公開鍵の内容を保存しておきます(下のはあくまで例です)
priv/cert/perms.priv.pem
-----BEGIN RSA PRIVATE KEY----- MIICWgIBAAKBgGelwkR0D5Eaox0+NisT4T4xSIz63FOmGK2hrP49LokyxKqYHPPx KHO4Jgsof84oSRfBI9TRP/htlTl5eY979CyUzR2UjENVE36NihcPEAsrjcKk6Km8 LW5sJwswFglLLTdLRH0Au0397Isux764hPDlfYI0UETQ3icSjgFtHewPAgMBAAEC gYA1UuVIfIGJwK+MmvYZYYfvjEFsLp/t9TUbF2O+BVIMye6+abXzlu2d427HLNXc BYPdUcOSePk1YYN1Z1awCDCNm2JnquRT0Z1/HgmMeLHFvKXKLmpsKJhd2viianmS 1ND........................................................1CAPT 5I+S4s/RYIDbQC71gn0KKYO2srZXPnlYfcUU7XGgjuSu8b4es6zDB0lMgqf9ZElm 2dK2ji0CQQCc5hs5g0CvZBw0YYNVrK8hrcTV6Ypb8i4Z3uR9RonWDQuY81fj+hqV wmO/vRrJoFHK6rKOxMrgwYxl/zNnrUSrAkBbmk6lY7yi1mvn/t/AMVUwMn6ubZSf mxa6ekWwdcbp4+oQOrGtjj9rnAeqsWR6khDLFL0epBXlvuiSpeZ5L69lAkBpCfgh +cf9Y7UqMDo/yjr4/h+v4gjZ43mPolQvtmCi59riy88EdjUEG76x58UeRPFdOuDN idwUuh7nTgG5IBu/AkBN94zKUzG2YRZ0wAz+xhQtprZnV3WkYGfs25mYmB12UDzM DKoQJvNX+i5HLiZASybFEvF/4+mm8fFjqVW0awwL -----END RSA PRIVATE KEY-----
priv/cert/perms.pub.pem
-----BEGIN PUBLIC KEY----- MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGelwkR0D5Eaox0+NisT4T4xSIz6 3FOmG......................................................UzR2U jENVE36NihcPEAsrjcKk6Km8LW5sJwswFglLLTdLRH0Au0397Isux764hPDlfYI0 UETQ3icSjgFtHewPAgMBAAE= -----END PUBLIC KEY-----
次に sed を使って秘密鍵の中味の改行コードを素の文字列 \n に置き換えたものを perms.priv.pem.1line として作成します。
sed -z 's/\n/\\n/g' priv/cert/perms.priv.pem |sed -E 's/\\n$/\n/g' > priv/cert/perms.priv.pem.1line
いよいよ設定ファイルの config/dev.exs 内を修正します
- ホスト名を myhubs.exampole に変更
- 証明書ファイル名のパス priv/cert〜 に変更
- perms_key で定義している秘密鍵の内容を perms.priv.pem.1line をコピペしたものに入れ替える
- Dialog (janus host) のポートを 4443 に変更
元ファイルを dev.exs.original として diff したのがこちらです
ops@myhubs:~/mozilla/reticulum$ diff config/dev.exs.original config/dev.exs 5,8c5,8 < host = "hubs.local" < cors_proxy_host = "hubs-proxy.local" < assets_host = "hubs-assets.local" < link_host = "hubs-link.local" --- > host = "myhubs.example" > cors_proxy_host = "myhubs.example" > assets_host = "myhubs.example" > link_host = "myhubs.example" 13c13 < dev_janus_host = "dev-janus.reticulum.io" --- > dev_janus_host = "myhubs.example" 28,29c28,29 < keyfile: "#{File.cwd!()}/priv/dev-ssl.key", < certfile: "#{File.cwd!()}/priv/dev-ssl.cert" --- > keyfile: "#{File.cwd!()}/priv/cert/server.key", > certfile: "#{File.cwd!()}/priv/cert/server.crt" 175c175 < config :ret, Ret.PermsToken, perms_key: (System.get_env("PERMS_KEY") || "") |> String.replace("\\n", "\n") --- > config :ret, Ret.PermsToken, perms_key: "<-----BEGIN RSA PRIVATE などのヘダー含めて、ここに 1line 化した秘密鍵をコピペで貼り付けます>" 201c201 < 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 を起動します。
iex -S mix phx.server
Public な room を検索する API https://myhubs.example:4000/api/v1/media/search?source=rooms&filter=public&cursor=0 をブラウザで試してみます。下記のようなJSON を返せば OK です
{"meta":{"source":"public_rooms","next_cursor":1},"entries":[],"suggestions":null}
Coturn セットアップ
WebRTC Mediasoup で作られた Dialog を使うために、必要となる STUN/TURN サーバーの coturn をセットアップします。
sudo apt install coturn sudo systemctl stop coturn sudo cp /etc/turnserver.conf /etc/turnserver.conf.original
/etc/turnserver.conf にて 127.0.0.1 の PostgreSQL ret_dev データベースのスキーマ coturn でアクセスするように設定し、以下の diff の様に設定します
$ sudo diff /etc/turnserver.conf.original /etc/turnserver.conf 299c299 < #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 start coturn でスタートさせます
Dialog セットアップ
Reticulum, Coturn の次に音声サーバーの Dialog をセットアップします
cd ~/mozilla git clone https://github.com/mozilla/dialog.git cd dialog git reset --hard 4edefad (今回の手順で構築出来てるのがこの commit で、その後未確認なのでここまで戻してください) npm install
証明書を配置し、reticulum の方で作成しておいた通信用公開鍵を配置します
mkdir certs ln -s ~/certs/server.crt certs/fullchain.pem ln -s ~/certs/server.key certs/privkey.pem ln -s ~/mozilla/reticulum/priv/cert/perms.pub.pem certs/perms.pub.pem
次のコマンドで自分のサーバーの IP (例 192.168.0.5)を指定して起動します
MEDIASOUP_LISTEN_IP=0.0.0.0 MEDIASOUP_ANNOUNCED_IP=192.168.0.5 npm start
Hubs セットアップ
最後に Web のフロントサーバーの Hubs をセットアップします
ファイルシステムの inotify がデフォルトの 8000 などだと小さいので予め拡張します。
/etc/sysctl.conf に fs.inotify.max_user_watches=50000 の1行を追加し sudo sysctl –system で反映します。
ソースを取得し、ここでも手順で実績ある commit まで戻しておきます
git clone https://github.com/mozilla/hubs.git cd hubs git reset --hard 926dbde62
最初に作っておいた証明書をここでも使います。ファイル名は hubs/certs/cert.pem と key.pem 固定です
mkdir certs ln -s ~/certs/server.crt certs/cert.pem ln -s ~/certs/server.key certs/key.pem
.defaults.env を .env にコピーしホスト名を変更します。
< SHORTLINK_DOMAIN="hub.link" --- > SHORTLINK_DOMAIN="myhubs.example:4000" 8c8 < RETICULUM_SERVER="dev.reticulum.io" --- > RETICULUM_SERVER="myhubs.example:4000" 11c11 < CORS_PROXY_SERVER="hubs-proxy.com" --- > #CORS_PROXY_SERVER="hubs-proxy.com" 21c21 < NON_CORS_PROXY_DOMAINS="hubs.local,dev.reticulum.io" --- > NON_CORS_PROXY_DOMAINS="hubs.local,dev.reticulum.io,myhubs.example:4000"
webpack.config.js 内も myhubs.example に変更します。以下 diff 例です。
241c241 < const host = process.env.HOST_IP || env.localDev || env.remoteDev ? "hubs.local" : "localhost"; --- > const host = process.env.HOST_IP || env.localDev || env.remoteDev ? "myhubs.example" : "localhost"; 287c287 < allowedHosts: [host, "hubs.local"], --- > allowedHosts: [host, "myhubs.example"],
ビルドします。(メモリを大量に使い、時間もかかります)
npm ci
dev サーバースタート
npm run dev
自己署名証明書をブラウザに例外認識させるために一連の URL を踏んでから、Hubs のフロントにアクセスします
- https://myhubs.example:4443/
- https://myhubs.example:4000/api/v1/media/search?source=rooms&filter=public&cursor=0
Hubs にアクセス
dev 環境でのとりあえずの使い方
ルームを作る
- Sign In / Sign Up の機能はまだ上手くうごかせてませんので、部屋を作成する ボタンでランダムなハッシュで部屋を生成し、Join Room を選らんで入ります。
- アバターの名前は自由に設定できますが英数のみのようです
入っている部屋に招待する
招待用のリンク機能がまだ上手く使えてませんので、とりあえず最初に作って入った部屋の URL を直接他の人の PC やブラウザで入力してください
(例)https://myhubs.example:8080/hub.html?hub_id=rU6ePqt
今はまだ真っ暗な部屋で移動して、マイクで会話したり文字のチャットをしたり、などしか出来ていませんが、マルチプレーヤーの VR という雰囲気だけでも味わっていただけたらと思います!
引き続き、自営サーバーでのシーン作成やアバター作成、それらの部屋でのロード、などにも挑戦して行きますので続編にもご期待下さい!!!
弊社ではメタバースに興味のある xR エンジニアやプログラマ、インフラエンジニアなどを積極募集しておりますので、ご興味ある方はぜひご応募くださいー ⇒ 採用情報