OwnServer を使って Subnautica Nitrox を IPv6 (DL-Lite) 環境下で IPv4 向けに建てる

# はじめに
表題の通り、Subnautica のマルチプレイヤー Mod である [Nitrox](https://nitrox.rux.gg/) のサーバを IPv6 (DS-Lite) 環境下で IPv4 のクライアントから接続できるように公開する方法です
ついでに VPS で OwnServer のサーバ側も建てて自前の環境のみで動かす方法も書いてます
さらについでに VPS 込みで OwnServer の起動を自動化するスクリプトも作りました

https://nitrox.rux.gg/

[OwnServer](https://github.com/Kumassy/ownserver) というローカルのゲームサーバをインターネットに公開するためのツールを使います

https://github.com/Kumassy/ownserver

OwnServer 自体の説明については作者様が記事を書いているのでそちらを読んでください

https://zenn.dev/kumassy/articles/ownserver-expose-local-game-server

# 実行環境

ローカルマシンは Windows11 の WSL1 (Ubuntu 20.04 LTS) から実行しています

:::note warn
Linux 用の OwnServer を実行するとうまく疎通できないので WSL1 から Windows 用の OwnServer を実行したりしています
:::

後に出てくる VPS は Ubuntu 20.04 LTS です

# OwnServer を使う理由
Nitrox のサーバを建てようと思ったときは「普通に自宅のルータでポート開放して、PC 側のファイアウォールも開けて、知り合いには IP とポート番号共有すればできるじゃろ」と思ってましたが、いろいろ試した結果 OwnServer を使う以外に私がサーバを建てる方法は見つけられませんでした

:::note warn
基本的に、IPv6 の人が IPv4 の人向けにサーバを建てるのは難しいですが、IPv4 の人が IPv6 の人向けにサーバを建てるのは簡単なので身内鯖であればその方が楽なことが多いです
今回の場合も身内鯖ですが PC のスペック的に建てられるのが私しか居なかったため試行錯誤することになりました
:::

## ポート開放ができない
IPv6 (DS-Lite) 環境だと、IPv4 アドレスを使ってポート開放をすることができません
借りている VPS があるので、SSH とかでポートをリモートフォワードして、`クライアント -> VPS -> トンネル -> ローカルサーバ` の経路で接続できるようにします

## UDP のトンネルが開けられない
SSH でのポートのフォワードは TCP しかできず、UDP を使用している Nitrox はそのままではトンネルを開けることができませんでした

:::note info
軽く探したところ UDP を使用しているローカルで建てる必要のありそうなゲームサーバは Nitrox と Minecraft BE くらいしか見つかりませんでした
:::

UDP <-> TCP 変換をして
`クライアント -> VPS (UDP 受信) -> UDPtoTCP 変換 -> トンネル -> TCPtoUDP 変換 -> ローカルサーバ` の経路で接続できるようにします
変換には [socat](http://www.dest-unreach.org/socat/) や [stone](https://www.gcd.org/sengoku/stone/Welcome.ja.html) が使えそうです (このリンクは公式なんでしょうか)

http://www.dest-unreach.org/socat/

https://www.gcd.org/sengoku/stone/Welcome.ja.html

## パケットが壊れる
socat、stone どちらを使っても上記の経路で接続自体はできるようになったのですが、パケットが壊れてしまい正常に通信はできませんでした
私の TCP、UDP 周りの知識が壊滅的なのとドキュメントをちゃんと読まないのが原因だと思いますが、掘り下げが面倒になったので友人から教えてもらった OwnServer を使います

:::note warn
家のネットワーク構成を変更して特定の通信のみ IPv4 PPPoE を使うようにする (よく分かってません) みたいな方法もあるらしく、そちらでも恐らく実現可能なのですが物理ネットワークをいじりたくなかったので見なかったことにしました
:::

# 手順
OwnServer は CLI の方を使います。GUI でもできると思うので適当に読み替えてください
下記はサーバ建てる場合の手順ですが、参加者の場合でも `*` が付いた項目は実行する必要があります

## OwnServer ダウンロード
GitHub から実行ファイルをダウンロードします
Windows 用なので、`ownserver_vx.y.z_x86_64-pc-windows-gnu.zip` です

https://github.com/Kumassy/ownserver/releases

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369264/f7ab9f32-df7f-2f8a-e696-0edec6c322c3.png)

解凍すると `ownserver.exe` が出てくるので適当にパスが通っている場所に置きましょう

## OwnServer 実行
```bash
ownserver.exe --local-port 11000 --payload udp
```
を実行します

```bash
(ins) ~ $ ownserver.exe --local-port 11000 --payload udp
Connecting to auth server: https://auth.ownserver.kumassy.com/v1/request_token
Your proxy server: shard-XXXX.ownserver.kumassy.com
Connecting to proxy server: shard-XXXX.ownserver.kumassy.com:5000
Your Client ID: client_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
+----------------------------------------------------------------------------------------------------+
| Your server udp://localhost:11000 is now available at udp://shard-XXXX.ownserver.kumassy.com:PPPPP |
+----------------------------------------------------------------------------------------------------+
```

標準出力された `shard-XXXX.ownserver.kumassy.com:PPPPP` がサーバアドレスとポートなので参加者に共有します


## *Subnautica Legacy バージョンのインストール
2023/07/11 現在 Nitrox が Subnautica の最新バージョン 2.0 に対応していないのでバージョンを下げます
Steam のライブラリで Subnautica を右クリックし、`プロパティ...` を選択
開いたメニューの右側の `ベータ` をクリックし、`ベータへの参加` プルダウンの値を `legacy - Public legacy builds` にします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369264/0a15fc80-62e6-c857-16e2-705bce59a5b5.png)


## *Nitrox ダウンロード
公式ページからダウンロードし、適当な場所に解凍します

https://nitrox.rux.gg/download

## Nitrox 実行

### サーバ起動
解凍したディレクトリの中にある `NitroxLauncher.exe` を実行します
起動後、左側のメニューの `Server` を選択し、`START SERVER` をクリックします
これでサーバが起動します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369264/1fc1dac4-7193-b39d-97e2-839ff93950d7.png)

:::note info
ラジオボタンはどちらでも良いですがウィンドウを増やしたくないので `Docked console` にしています
:::

### *クライアント起動
その後、左側のメニューの `Play game` を選択し、`PLAY` をクリックします
これでクライアント側も起動します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369264/f43eba14-8656-c911-a0e6-17f15141614e.png)

## *接続
ゲームのメインメニューの `Nitrox_Multiplayer` をクリックし、メニューから `Nitrox_AddServer` をクリック
出てきたウィンドウのテキストフィールドを埋めます
- `Nitrox_AddServerName`: 適当な分かりやすい名前
- `Nitrox_AddServerHost`: `shard-XXXX.ownserver.kumassy.com` (OwnServer 実行時に表示されたアドレス)
- `Nitrox_AddServerPort`: `PPPPP` (OwnServer 実行時に表示されたポート)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369264/bde0d4f9-5d8f-61d8-fd5a-971a42c992cc.png)

埋めたら `Nitrox_AddServerAdd` ボタンを押します

サーバ一覧に追加したサーバが表示されているのでクリックします
するとプレイヤー名や色を選ぶ画面が出てくるので適当に埋めて `Nitrox_Join` をクリックすれば接続完了です

:::note warn
OwnServer 側で用意された環境を使うとアドレスとポートが毎回変わるので毎回サーバの登録手順を行う必要があります
後述の VPS 環境で構築するとアドレスとポートが固定され、二度目以降の接続時は表示されているサーバをクリックするだけでできるようになります
:::

# おまけ: VPS のアドレスで公開する
OwnServer は自前の環境で OwnServer のサーバサイドを建てられるように `ownserver-server` と `ownserver-auth` が用意されているのでそれを使ってアドレスとポートが変わらないようにします。説明がさらに雑になるのでご了承ください

これ以降の手順では VPS などグローバル IPv4 アドレスを持っているマシンが必要になります

:::note info
参加者のうち IPv4 回線の人の PC に OwnServer サーバサイドを建ててそこで公開し、サーバ自体は IPv6 回線の人の PC で稼働させる、みたいなこともできるはずです (多分)
:::

# 作業 (VPS 側)
VPS 側に OwnServer のサーバサイドのプログラムをインストールして実行します

## cargo のインストール
ソースコードからビルドするために `cargo` をインストールします
[公式](https://doc.rust-lang.org/cargo/getting-started/installation.html) のドキュメントを見て `cargo -h` が実行できる状態にしてください

https://doc.rust-lang.org/cargo/getting-started/installation.html

## ownserver-server のインストール

ownserver リポジトリをクローンしてビルドします

https://github.com/Kumassy/ownserver

下記を実行します

```bash
git clone https://github.com/Kumassy/ownserver.git # クローン
cd ownserver # クローンしたディレクトリに移動
cargo build --release # ビルド
sudo mv target/release/ownserver-server /usr/local/bin/ # 適当なパスの通っている場所に置く
```

## ownserver-auth のインストール

ほとんど [ownserver-server のインストール手順](#ownserver-server-のインストール) と同様です
ownserver-auth リポジトリをクローンしてビルドします

https://github.com/Kumassy/ownserver-auth

下記を実行します

```bash
git clone https://github.com/Kumassy/ownserver-auth.git # クローン
cd ownserver-auth # クローンしたディレクトリに移動
cargo build --release # ビルド
sudo mv target/release/ownserver-auth /usr/local/bin/ # 適当なパスの通っている場所に置く
```

## ポート開放
iptables などで下記のポートを開けます。環境によって開け方は違うので調べてください
- 11000 (UDP): Nitrox のポート。身内鯖であれば知り合いの IP アドレスに対してのみ開放で問題ないです
- 8123 (TCP): ownserver-auth 用のポート。自身の IP アドレスに対してのみ開放で問題ないです
- 5000 (TCP): ownserver-server 用のポート。自身の IP アドレスに対してのみ開放で問題ないです

:::note warn
`自身の IP アドレスに対してのみ開放で問題ないです` って書いてますが、DS-Lite 環境下で自身の IPv4 アドレスは固定できない気がするので完全に開放することになりそうな気がします
:::

## VPS 側起動
ownserver-auth と ownserver-server を起動します
ssh で二回接続するか tmux を使うかなどでどちらも起動しっぱなしの状態にしてください

なお、下記の環境変数が定義されているものとします
- `HOST_IP`: VPS のグローバル IP アドレス (これだけはローカルマシン側でも必要)
- `SECRET`: 外部に公開しないパスワード的な任意の文字列？ownserver-auth と ownserver-server で一致させる

下記のコマンドで起動します
- ownserver-auth
```bash
ownserver-auth --token-secret ${SECRET} --hosts ${HOST_IP}
```

- ownserver-server
```bash
ownserver-server --host ${HOST_IP} --remote-port-start 11000 --remote-port-end 11001 --token-secret ${SECRET}
```

ここまでで VPS 側での作業は完了です

## ローカル側起動
下記のコマンドで起動します
```bash
ownserver.exe --payload udp --local-port 11000 --token-server http://${HOST_IP}:8123/v0/request_token
```

```bash
(ins) ~ $ ownserver.exe --payload udp --local-port 11000 --token-server http://${HOST_IP}:8123/v0/request_token
Connecting to auth server: http://XXX.XXX.XXX.XXX:8123/v0/request_token
Your proxy server: XXX.XXX.XXX.XXX
Connecting to proxy server: XXX.XXX.XXX.XXX:5000
Your Client ID: client_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
+-----------------------------------------------------------------------------------+
| Your server udp://localhost:11000 is now available at udp://XXX.XXX.XXX.XXX:11000 |
+-----------------------------------------------------------------------------------+
```

IP アドレスが VPS のもので固定されており、ポートも 11000 で固定されているはずです
これで接続するたびにサーバの情報を入力する必要がなくなります

# おまけのおまけ: 自動化スクリプト (Deno)
VPS 側での ownserver-auth、ownserver-server とローカルマシンでの ownserver の起動を自動化する Deno スクリプトを作成しました。汎用性を持たせるために Nitrox の起動までは行いません

ローカルマシン側の WSL に deno コマンド、
ローカルマシン側の Windows に ownserver.exe コマンド、
VPS 側に ownserver-auth, ownserver-server コマンドのパスを通しておく必要があります
また、ローカルマシンの WSL から VPS に接続する ssh プロファイルを `~/.ssh/config` に定義しておく必要もあります

https://github.com/482F/misc/blob/master/ownserver-aio.ts


```bash
(ins) ~ $ ownserver-aio -h

  Usage: ownserver-aio <host-ip> <port>

  Options:

    -h, --help                  - Show this help.
    --ssh-profile-name  <name>  - SSH 接続時のプロファイル名
    --protocol          <name>  - tcp/udp              (Default: "udp")
    --auth-port         <port>  - 認証用ポート番号        (Default: 8123)
    --control-port      <port>  - 接続用ポート番号        (Default: 5000)

(ins) ~ $ ownserver-aio XXX.XXX.XXX.XXX 11000 --ssh-profile-name VPS
Connecting to auth server: http://XXX.XXX.XXX.XXX:8123/v0/request_token
ownserver 実行中・・・
Ctrl+C で終了します

Your proxy server: XXX.XXX.XXX.XXX
Connecting to proxy server: XXX.XXX.XXX.XXX:5000
Your Client ID: client_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
+-----------------------------------------------------------------------------------+
| Your server udp://localhost:11000 is now available at udp://XXX.XXX.XXX.XXX:11000 |
+-----------------------------------------------------------------------------------+
```