コンテナ版マインクラフトサーバを構築してhttps化したDynmapを使う

#はじめに
本記事ではマインクラフトのサーバをコンテナで構築します。
仮想マシンを作ってJDKをインストールしてjarファイルを実行して・・・というやり方が多いと思います。
このやり方も問題ないですが、サクッと作れるコンテナ版マインクラフト＋αをご紹介します。
この方法で以下のようなサーバを作成することができます。

* Minecraft Forge対応サーバ
* Forge版のDynmapの表示
* Dynmapをリバースプロキシ経由にしてhttps化

**構成図**
![kouseizu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78843/13981da2-4514-4ef3-3dab-5b540a20eeb4.png)


**※前提条件**

* 筆者の環境はCentOS 7です（古くてすみません）
* DockerとDocker-composeがインストール済
* 独自ドメイン等でdynmap.yourdomain.com等で名前解決できる
* マインクラフトのポートTCP:25565（任意）、Let's Encrypt用にTCP:80,443が使える

#使うもの紹介
今回使用するコンテナ、MODを紹介します。Forgeを導入しますので、Dynmap以外にも色々導入して大丈夫です。

##docker-letsencrypt-nginx-proxy-companion
Nginxベースのリバースプロキシ機能と、Let's Encrypt証明書発行機能をもったコンテナスタックです。
自動で証明書の発行・更新をしつつ、背後のWebサーバのリバースプロキシとして機能します。
証明書発行の認証にはhttp-01チャレンジを使用するのでIN側TCPポート80,443での通信が必要です。
https://github.com/nginx-proxy/docker-letsencrypt-nginx-proxy-companion

##itzg/minecraft-server
itzg(Geoff Bourne)氏がメンテナンスするマインクラフトのコンテナ版です。
バニラサーバであればこのコンテナを起動するだけでマインクラフトサーバが立ち上がります。
https://github.com/itzg/docker-minecraft-server

##Minecraft Forge
マインクラフトに様々なMODを適用する際の前提MOD。
大体のMODはこのForgeを要求します。今回のDynmapもForgeを使用します（Forge版以外もあります）。
http://files.minecraftforge.net

##Dynmap
ウェブブラウザからGoogle MapライクのUIでマインクラフトのワールドを確認できるMODです。
真上、斜め、別ディメンションが確認できて各種マーカーを立てたり、チャット機能があったりと非常に高機能です。
さらに最初から簡易Webサーバも備えているため、別途Webサーバを用意することなく使用できます。
今回はこの簡易Webサーバにリバースプロキシ経由でアクセスします。
https://www.curseforge.com/minecraft/mc-mods/dynmapforge


#docker-letsencrypt-nginx-proxy-companionのインストール
これを使うと、Nginxのリバースプロキシ機能とLet's Encryptによるhttps化が可能になります。
例えば独自ドメインをお持ちならhttps\://dynmap.yourdomain.com/ のようなアドレスでDynmapにアクセスが可能になります。
マインクラフト以外でも使える便利なDockerスタックなので、今回はdocker-composeファイルを独立させます。
以下のdocker-compose.ymlでコンテナ達を起動してください。

```yaml:docker-compose.yml
version: '3'

services:
  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - conf:/etc/nginx/conf.d
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - dhparam:/etc/nginx/dhparam
      - certs:/etc/nginx/certs:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro
    labels:
      - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy"
    restart: always

  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: nginx-proxy-le
    depends_on:
      - nginx-proxy
    volumes:
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - dhparam:/etc/nginx/dhparam:ro
      - certs:/etc/nginx/certs
      - /var/run/docker.sock:/var/run/docker.sock:ro
    restart: always

volumes:
  conf:
  vhost:
  html:
  dhparam:
  certs:

networks:
  default:
    external:
      name: nginx-proxy
```

```bash:docker-compose
$sudo docker-compose up -d
```

#マインクラフトのインストール
Docker Hubにあるitzg/minecraft-serverを使用します。
Dynmapを入れるディレクトリはmodsディレクトリとなります。
docker-compose.ymlを置くディレクトリで以下を実行してください。

```bash:mkdir
$sudo mkdir mods
```

マインクラフトのdocker-compose.ymlは以下になります。
Dockerネットワーク名は、docker-letsencrypt-nginx-proxy-companionと合わせてください。

```yaml:docker-compose.yml
version: "3.7"

services:
  mc:
    image: itzg/minecraft-server
    ports:
    - 25565:25565
    - 8123:8123
    environment:
      EULA: "TRUE"
      VERSION: 1.16.4
      DIFFICULTY: normal
      SERVER_NAME: SERVERNAME
      TYPE: FORGE
      FORGEVERSION: 35.1.32
      ANNOUNCE_PLAYER_ACHIEVEMENTS: "true"
      TZ: Asia/Tokyo
      ENABLE_RCON: "true"
      RCON_PASSWORD: "PASSWORD"
      RCON_PORT: 28016
      ENABLE_QUERY: "true"
      ENABLE_STATUS: "true"
      OPS: Operator_Name
      USE_AIKAR_FLAGS: "true"
      MEMORY: 16G
      USE_LARGE_PAGES: "true"
      VIRTUAL_HOST: dynmap.your.domain
      VIRTUAL_PORT: 8123
      LETSENCRYPT_HOST: dynmap.your.domain
      LETSENCRYPT_EMAIL: email@address

    tty: true
    stdin_open: true
    restart: always

    volumes:
    - mc_forge:/data
    - ./mods:/mods:ro

volumes:
  mc_forge: {}

networks:
  default:
    external:
      name: nginx-proxy
```

以下に、各項目の説明をします。環境によっては不要な項目もあると思いますので、適宜削除などしてください。
また、ゲームに関する変数の詳細（難易度等）は以下リンクを参照してください。
[server.properties（Minecraft WIKI）](https://minecraft-ja.gamepedia.com/Server.properties)


**マインクラフト関係**

| 環境変数 | 今回の値 | 説明 |
|:-:|:-:|:-:|
|EULA|"TRUE"|マインクラフトの使用許諾に同意（必須）|
|VERSION|1.16.4|マインクラフトのバージョン|
|DIFFICULTY|normal|ゲーム難易度|
|SERVER_NAME|SERVERNAME|サーバ名|
|TYPE|FORGE|サーバのタイプ。今回はForge。|
|FORGEVERSION|35.1.32|Forgeのバージョン|
|ANNOUNCE_PLAYER_ACHIEVEMENTS|"true"|プレイヤーの達成を表示するかどうか（任意）|
|TZ|Asia/Tokyo|タイムゾーン|
|ENABLE_RCON|"true"|RCON（マインクラフトの遠隔操作）を有効にする|
|RCON_PASSWORD|"PASSWORD"|RCONのパスワード|
|RCON_PORT|28016|RCONのポート番号|
|ENABLE_QUERY|"true"|サーバーの稼働状態の送信を有効|
|ENABLE_STATUS|"true"|サーバーの詳細な？稼働状態の送信を有効|
|OPS|Operator_Name|サーバオペレータ（OP権限）ユーザの設定|
|USE_AIKAR_FLAGS|"true"|Java変数の最適化|
|MEMORY|16G|Javaで確保するメモリ|
|USE_LARGE_PAGES|"true"|Javaラージページの設定（メモリ12GB以上）|

**Dynmap/リバースプロキシ/Let's Encrypt関係**

| 環境変数 | 今回の値 | 説明 |
|:-:|:-:|:-:|
|VIRTUAL_HOST|dynmap.your.domain|dynmapを表示するFQDN|
|VIRTUAL_PORT|8123|dynmapのポート番号|
|LETSENCRYPT_HOST|dynmap.your.domain|dynmapを表示するFQDN|
|LETSENCRYPT_EMAIL|email@address|Let's Encryptから連絡を受けるメールアドレス|


次に、modsディレクトリにdynmapを格納します。以下からダウンロードしてmodsディレクトリに入れてください。
https://www.curseforge.com/minecraft/mc-mods/dynmapforge

あとはdocker-compose upすればマインクラフトが起動してきます。

```bash:docker-compose
$sudo docker-compose up -d
```

起動後しばらくすると（1分程度）、docker-letsencrypt-nginx-proxy-companionによってhttps化されます。
https\://dynmap.your.domain/でアクセスできるようになっているはずです。
マインクラフト自体ははデフォルトポートであれば通常どおり"your.domain"で接続できます。

うまく起動してこない場合、Dockerのログを確認してみてください。

```bash:docker-compose
$sudo docker-compose logs -f 
```

**証明書例**
![dynmap_example.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78843/b84a74ae-8dae-434b-5c34-dc843cd7b24b.png)


**マインクラフト接続例**
![server_example.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78843/5a3b6556-7fb9-80ac-0811-e4179ab91357.png)

#おわりに
シンプルなマインクラフトサーバの構築はもともと難しいものではありませんでしたが、
コンテナで実行することでマインクラフトもIaCとして管理できます。ほしいマインクラフト環境がすぐに構築できるのはいいですね。
また、dynmapもコンフィグを設定すればリバースプロキシすることができましたが、コンテナ版マインクラフトでもっと簡単にできます。
それでは良いマインクラフトライフを！

おまけ：私の環境では、さらにPrometheusとGrafanaを使ってプレイヤーの状態を確認したりして遊んでます！
![example.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78843/b9894f64-c7a0-9aa6-5a0f-5c48625c6130.png)