systemdとscreenでMinecraft: Java Editionのサーバを起動する

# 検証環境

- OS: Ubuntu Server 22.04 LTS
- Java: 17 (OpenJDK)
- Minecraft: Java Edition 1.19.4

# 初期設定

- Minecraftのサーバの起動前に事前に必要な設定

```bash
# rootユーザにスイッチ
$ sudo su -

# Java(OpenJDK)のインストール
$ apt update && apt install openjdk-17-jdk

# Minecraftのサーバのダウンロード先となるディレクトリの作成
$ mkdir /opt/minecraft && cd /opt/minecraft

# Minecraftのサーバをダウンロード
$ curl -o server.jar -L https://piston-data.mojang.com/v1/objects/8f3112a1049751cc472ec13e397eade5336ca7ae/server.jar

# EULA(利用許諾契約)に同意
$ echo "eula=true" > eula.txt

# minecraftユーザの作成
# Minecraftのサーバの実行ユーザとして使用する
$ useradd minecraft -m

# パスワード無しでsudoコマンドを実行できるようにしておく
$ echo "minecraft ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/minecraft

# カレントディレクトリ以下のファイルの所有者とグループを再帰的にminecraftに変更
$ chown minecraft:minecraft . -R
```

# サーバの起動

- Minecraftのサーバを起動するにあたっての問題点、各種起動方法の比較、最終的にsystemdとscreenを選定した理由についてまとめる

## 問題点

- Minecraftのサーバはシェルから抜けても継続して実行したいが、バックグラウンドで実行するオプションは用意されていない
- Minecraftのサーバをバックグラウンドで実行できたとしても、サーバの操作の際にはフォアグラウンドに戻す必要がある
    - 今回はゲーム内のチャットやRCON経由でのサーバの操作については考えない
    - RCONについては「[MinecraftのサーバにRCONで接続する](https://qiita.com/h_tyokinuhata/items/85d855f88d5d33c21949)」にまとめている
- 自分が思いつく限りで上記の問題を完全に、または部分的に解決する方法は以下の４つ

### `&` + `nohup`/`disown`

- `&`は大抵のシェルで提供されているバックグラウンドで実行する仕組み
- `nohup`や`disown`はバックグラウンドで実行したプロセスをシェルから切り離すコマンド
    - プロセスをシェルから切り離す必要があるのは、シェルの終了時にバックグラウンドで実行したプロセスも終了されてしまう可能性があるため
    - 詳しくは「[シェルのジョブ制御に慣れる](https://qiita.com/h_tyokinuhata/items/ac922012a8a60b9bba84)」にまとめている
- これら２つを組み合わせる方法

#### メリット

- シンプルで簡単にプロセスをバックグラウンドで実行できる

#### デメリット

- プロセスの起動、停止、再起動等を柔軟に扱えない
- 起動時の依存関係や順序の管理が困難
- プロセスの監視やロギングに関する機能は統合されていない
- 実行後は基本的にフォアグラウンドに戻すことができない
    - シェルとプロセスが紐付いており、ジョブとして管理されている場合は`fg`コマンドでフォアグラウンドに戻すこともできるが、プロセスがシェルから切り離されている場合はこの方法は使えない
    - 詳しくは「[シェルのジョブ制御に慣れる](https://qiita.com/h_tyokinuhata/items/ac922012a8a60b9bba84)」にまとめている

#### 実行例

- `nohup`

```bash
$ nohup java -Xms2G -Xmx2G -jar /opt/minecraft/server.jar --nogui &
```

- `disown`

```bash
$ java -Xms2G -Xmx2G -jar /opt/minecraft/server.jar --nogui &
$ disown <ジョブ番号>
```

### systemd

- RHEL系やDebian系、その他多くのLinuxディストリビューションで広く採用されているinitプロセスであるsystemdを利用する方法

#### メリット

- サービス(プロセス)の起動、停止、再起動等を柔軟に扱える
- 起動時の依存関係や順序の管理が可能
- プロセスの監視やロギングに関する機能が統合されている

#### デメリット

- initプロセスやsystemdについてある程度知っておく必要がある
- 設定ファイルが別途必要
- 比較的、学習コストが高い
- 実行後は基本的にフォアグラウンドに戻すことができない

#### 実行例

- 設定

```ini:/etc/systemd/system/minecraft.service
[Unit]
Description=Minecraft server
After=network-online.target

[Service]
Type=forking
User=minecraft
Group=minecraft
WorkingDirectory=/opt/minecraft
ExecStart=java -Xms2G -Xmx2G -jar /opt/minecraft/server.jar --nogui
ExecStop=/bin/kill -s HUP $MAINPID
Restart=always

[Install]
WantedBy=multi-user.target
```

- 実行

```bash
# systemdのデーモンをリロードし、/etc/systemd/system/minecraft.serviceを読み込む
$ sudo systemctl daemon-reload
# Minecraftのサーバを再起動時にも自動起動するよう設定
$ sudo systemctl enable minecraft
# Minecraftのサーバを起動
$ sudo systemctl start minecraft
```

### screen

- 古くから存在するシンプルなターミナルマルチプレクサ
    - ターミナルマルチプレクサとは、複数の端末デバイスをセッションとしてまとめて管理するツール
    - １つのウィンドウ内で複数の端末デバイスを表示して切り替えたり、セッションをアタッチすることでフォアグラウンドに戻したり、デタッチすることで逆にバックグラウンドに戻したりすることができる
    - 今回はこのアタッチ、デタッチする機能を主に使用する

#### メリット

- デフォルトでインストールされていることが多い
- シンプルで基本的な機能をサポートしている
- プロセスをバックグラウンドで実行したり、再びフォアグラウンドに戻したりすることができる

#### デメリット

- 起動時の依存関係や順序の管理が困難
- プロセスの監視やロギングに関する機能は統合されていない
- カスタマイズ性や拡張性に欠ける
- あまりアクティブにメンテナンスされておらず、機能追加やバグ修正が遅い

#### 実行例

- `-S`オプションはセッションに名前を付けることができる
- `-d`オプションはセッションをバックグラウンドで開始することができる
- `-m`オプションはセッション作成時にシェルを起動しない

```bash
$ screen -S minecraft -d -m java -Xms2G -Xmx2G -jar /opt/minecraft/server.jar --nogui
```

### tmux

- より現代的な高機能なターミナルマルチプレクサ

#### メリット

- より現代的な機能やインタフェースを備える
- カスタマイズ性や拡張性が高く、柔軟な設定が可能
- より高度な機能を提供する
- アクティブに開発されており、機能追加やバグ修正が迅速
- プロセスをバックグラウンドで実行したり、再びフォアグラウンドに戻したりすることができる

#### デメリット

- 起動時の依存関係や順序の管理が困難
- プロセスの監視やロギングに関する機能は統合されていない
- デフォルトでインストールされていないことがある
- 設定方法や操作が独特で、screenに慣れている人には馴染みが薄い

#### 実行例

- 各オプションの挙動はscreenと同様

```bash
$ tmux new-session -s minecraft -d 'java -Xms2G -Xmx2G -jar /opt/minecraft/server.jar --nogui'
```

### 技術選定

- 今回は一時的な検証ではなく比較的長期に渡って運用する可能性が高いことから、ユーザインタフェースが分かりやすく、プロセスの監視やロギングに関する機能が統合されているsystemdを選定
- また、systemd単体ではMinecraftのサーバをフォアグラウンドに戻して操作できないため、systemdからscreen経由でMinecraftのサーバを起動する
- tmuxではなくscreenを選定したのは、今回の場合はシンプルなアタッチやデタッチを行う機能しか使用しないため

# 最終的な設定

- 設定

```ini:/etc/systemd/system/minecraft.service
[Unit]
Description=Minecraft server
After=network-online.target

[Service]
Type=forking
User=minecraft
Group=minecraft
WorkingDirectory=/opt/minecraft
ExecStart=screen -S minecraft -d -m java -Xms2G -Xmx2G -jar /opt/minecraft/server.jar --nogui
ExecStop=screen -S minecraft -X quit
Restart=always

[Install]
WantedBy = multi-user.target
```

- Minecraftのサーバの起動

```bash
$ sudo systemctl daemon-reload
$ sudo systemctl start minecraft
```

- screenコマンドの操作

```bash
# セッションの一覧を表示
$ sudo -u minecraft screen -ls
# デタッチされたセッションにアタッチする
# この操作により、Minecraftのサーバをフォアグラウンドに戻すことができ、この中でMinecraftのサーバの操作が行える
$ sudo -u minecraft screen -r minecraft
```