２ スクリプト一覧

**[１ Minecraft bedrock server の建て方（Backup by Git）](https://qiita.com/QiitaYkuyo/items/625ed2b6025c93211514)**
**２ スクリプト一覧（今ここ）**
**[３ 各スクリプトの詳細＆引用元・参考先](https://qiita.com/QiitaYkuyo/items/4f76b09afec30246cda7)**

### 要件（必要な実行環境）
`lsb_release -a`
　No LSB modules are available.
　Distributor ID: Ubuntu
　Description:    Ubuntu 22.04.2 LTS
　Release:        22.04
　Codename:       jammy
`head -1 <(bash --version)`
　GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
`tmux -V`
　tmux 3.2a
`git --version`
　git version 2.34.1

### 必要なパッケージのインストール
`sudo apt install tar unzip curl wget tmux git`

**以下、上から順にすべて実行してください**

### Minecraft 用のユーザー、サーバーを用意
#### ユーザー・グループ作成
```bash:bash：USER
New_USER=minecraft
HOME_DIR=/opt/minecraft
New_GROUP=$New_USER
Login_Shell=/bin/bash

sudo adduser --system \
             --home $HOME_DIR \
             --shell $Login_Shell \
             --group \
             $New_USER
```

**＃確認**
```bash:bash：USER
# 新規ユーザーのID、所属グループを表示
id $New_USER
# 特定のグループの所属メンバーを確認
getent group $New_GROUP
```

#### home ディレクトリに、マインクラフトを展開
※１行ずつ実行
```bash:bash：USER
# 作成したユーザーにログイン
sudo -i -u $New_USER

# サーバーのアーカイブをダウンロード、展開
DOWNLOAD_URL=$(curl -H "Accept-Encoding: identity" -H "Accept-Language: en" -s -L -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BEDROCK-UPDATER)" https://minecraft.net/en-us/download/server/bedrock/ |  grep -o 'https://minecraft.azureedge.net/bin-linux/[^"]*')
wget $DOWNLOAD_URL -O ~/bedrock-server.zip

unzip -o bedrock*server*.zip
rm -f bedrock*server*.zip

exit
```

### ワールドデータ・設定ファイルの保存先を作成
#### ディレクトリ作成
```bash:bash：USER
# ユーザー・グループ作成　で作ったユーザーとグループ
New_USER=minecraft
New_GROUP=$New_USER

sudo rm -r "/opt/MC_Manage"
sudo mkdir -p /opt/MC_Manage/{Properties,World_Backup}
sudo chown -R $New_USER:$New_GROUP "/opt/MC_Manage/"
sudo chmod -R 750 "/opt/MC_Manage/"
# 確認
sudo ls -laF "/opt/MC_Manage/"
```
#### サービス化、起動・停止スクリプト
```bash:minecraft.service：USER
sudo su -c 'cat << __EOF__ > "/etc/systemd/system/minecraft.service"
[Unit]
Description=Minecraft Service
Wants=network.target
After=network.target

[Service]
Type=forking

ProtectHome=true
ProtectSystem=full
PrivateDevices=true
NoNewPrivileges=true
InaccessibleDirectories=/root /home /sys /srv /media -/lost+found
ReadWriteDirectories=/opt/minecraft
WorkingDirectory=/opt/minecraft

ExecStart=+/usr/bin/setpriv --reuid=$(/usr/bin/id -u minecraft) --regid=$(/usr/bin/id -g minecraft) --init-groups /opt/MC_Manage/start.sh
ExecStartPost=+/usr/bin/bash /opt/MC_Manage/backup.sh
ExecReload=+/usr/bin/bash -c "/usr/bin/setpriv --reuid=minecraft --regid=minecraft --init-groups /usr/bin/env XDG_RUNTIME_DIR=/run/user/$(/usr/bin/id -u minecraft) /usr/bin/systemctl --user stop nonstop_save.timer && /usr/bin/bash /opt/MC_Manage/backup.sh"
ExecStop=+/usr/bin/setpriv --reuid=$(/usr/bin/id -u minecraft) --regid=$(/usr/bin/id -g minecraft) --init-groups /usr/bin/bash -c "/usr/bin/env XDG_RUNTIME_DIR=/run/user/$(/usr/bin/id -u minecraft) /usr/bin/systemctl --user stop nonstop_save.timer; exit 0"
ExecStop=+/usr/bin/setpriv --reuid=$(/usr/bin/id -u minecraft) --regid=$(/usr/bin/id -g minecraft) --init-groups /opt/MC_Manage/stop.sh

TimeoutStartSec=20
TimeoutStopSec=600
Restart=on-failure

[Install]
WantedBy=multi-user.target

__EOF__'
```

```bash:start.sh：USER
sudo su -c "cat << '__EOF__' > \"/opt/MC_Manage/start.sh\"
"'#!/bin/bash''
if [ ! -v MC_EnvCheck_INIT ] && [ -f "/opt/MC_Manage/mc_env.bash" ]; then
  . "/opt/MC_Manage/mc_env.bash"
fi

# Minecraft Server start
/usr/bin/tmux new-session -s minecraft -d
/usr/bin/tmux pipe-pane -t minecraft "cat >$Mine_DIR/Command.log"
/usr/bin/tmux send -t minecraft "LD_LIBRARY_PATH=$Mine_DIR ./bedrock_server | tee $Mine_DIR/Result.log" ENTER
/usr/bin/tmux send -t minecraft "gamerule showcoordinates true" ENTER
/usr/bin/tmux send -t minecraft "gamerule keepInventory true" ENTER
__EOF__'
```

```bash:backup.sh：USER
sudo su -c "cat << '__EOF__' > \"/opt/MC_Manage/backup.sh\"
"'#!/bin/bash''
BK_INTERVAL=2h

/usr/bin/setpriv \
  --reuid=$(/usr/bin/id -u minecraft) \
  --regid=$(/usr/bin/id -g minecraft) \
  --init-groups \
/usr/bin/env XDG_RUNTIME_DIR=/run/user/$(/usr/bin/id -u minecraft) \
  /usr/bin/systemd-run \
    --on-active=${BK_INTERVAL} \
    --on-unit-active=${BK_INTERVAL} \
    --user \
    --collect \
    --unit=nonstop_save.service \
      /bin/bash -c "\
        . /opt/MC_Manage/nonstop_save.bash ;\
        HOME=/opt/minecraft mc_save BAK_SERVICE"
__EOF__'
```

```bash:stop.sh：USER
sudo su -c "cat << '__EOF__' > \"/opt/MC_Manage/stop.sh\"
"'#!/bin/bash''
if [ ! -v MC_EnvCheck_INIT ] && [ -f "/opt/MC_Manage/mc_env.bash" ]; then
  . "/opt/MC_Manage/mc_env.bash"
fi

# Minecraft Server save & terminate
if [ "`type -t mc_save`" != "function" ]; then
  . "$Script_Path/nonstop_save.bash"
fi
mc_save commit unnecessary

/usr/bin/tmux send -t minecraft stop ENTER
/bin/sleep 10
/usr/bin/tmux kill-session -t minecraft

if [ "`type -t backup_worlds`" != "function" ]; then
  . "$Script_Path/backup_worlds.bash"
fi
backup_worlds "Backup of stopped servers"

echo "Stopped Minecraft Server"
__EOF__'
```

```bash:bash：USER
# ls /var/lib/systemd/linger
sudo loginctl enable-linger minecraft
# 所有者の変更
sudo chown minecraft:minecraft "/opt/MC_Manage/start.sh" "/opt/MC_Manage/backup.sh" "/opt/MC_Manage/stop.sh"
# 実行権限を付与
sudo chmod 751 "/opt/MC_Manage/start.sh" "/opt/MC_Manage/backup.sh" "/opt/MC_Manage/stop.sh"
```

**エイリアス（ user:minecraft で bash -c 用）を設定**
```bash:bash：USER
cat << '__EOF__' >> ~/.bash_aliases
function MC () {
  unset Arguments
  Arguments="${*//\"/\\\"}"
  Arguments="${Arguments:-exec bash --login}"
  sudo setpriv --reuid=$(/usr/bin/id -u minecraft) --regid=$(/usr/bin/id -g minecraft) --init-groups --reset-env bash --login -O expand_aliases -c "cd ~;IFS=' ' ${Arguments//\\\"/\"}"
}
__EOF__
```
```bash:.bash_aliases を .bashrc に記載：USER
. ~/.bashrc; if [ "`declare -F MC`" != "MC" ]; then
  echo "describe .bash_aliases"
  cat << '__EOF__' >> ~/.bashrc
if [ -f ~/.bash_aliases ]; then
  . ~/.bash_aliases
fi
__EOF__
fi
```

### Minecraft Server 管理用スクリプトの用意
#### Git ディレクトリの作成
```sudo -i -u minecraft```
**＃設定ファイル**
```bash:bash：Minecraft
Properties="/opt/MC_Manage/Properties"
git init "$Properties"

cat << __EOF__ > "$Properties/.git/config"
[user]
     name = Minecraft Server
    email = MinecraftServer@mydomain.com
__EOF__

git -C "$Properties" config --local gc.reflogExpire "never"
git -C "$Properties" config --local gc.reflogExpireUnreachable "never"
git -C "$Properties" config --local gc.pruneExpire "1.hours.ago"

git -C "$Properties" commit --allow-empty --allow-empty-message -m ''
git -C "$Properties" commit --amend --allow-empty --allow-empty-message --no-edit

git -C "$Properties" reflog delete HEAD@{1} $(git -C "$Properties" branch --show-current)@{1}
```

**＃ワールドデータ**
```bash:bash：Minecraft
World_Backup="/opt/MC_Manage/World_Backup"
git init "$World_Backup"

cat << __EOF__ > "$World_Backup/.git/config"
[user]
     name = Minecraft Server
    email = MinecraftServer@mydomain.com
__EOF__

git -C "$World_Backup" config --local gc.reflogExpire "never"
git -C "$World_Backup" config --local gc.reflogExpireUnreachable "3.days"
git -C "$World_Backup" config --local gc.pruneExpire "1.hours.ago"

git -C "$World_Backup" commit --allow-empty --allow-empty-message -m ''
git -C "$World_Backup" commit --amend --allow-empty --allow-empty-message --no-edit

git -C "$World_Backup" reflog delete HEAD@{1} $(git -C "$World_Backup" branch --show-current)@{1}
```

#### 環境変数の設定
```bash:.bash_profile：Minecraft
cat << '__EOF__' >> ~/.bash_profile
# .bash_profile
. "/opt/MC_Manage/mc_env.bash"
__EOF__

cp ~/.bash_profile "/opt/MC_Manage/"
```

```bash:mc_env.bash：Minecraft
cat << '__EOF__' > "/opt/MC_Manage/mc_env.bash"
#!/bin/bash
# profile evoker
set +u
export -n MC_EnvCheck_INIT ; unset MC_EnvCheck_INIT
declare MC_EnvCheck_INIT="MC_EnvCheck_INIT"
declare -x Script_Path="/opt/MC_Manage"

# Sourcing
if [ -f "$Script_Path/variable.bash" ]; then . "$Script_Path/variable.bash"; fi
if [ -f "$Script_Path/mc_tmux.bash" ]; then . "$Script_Path/mc_tmux.bash"; fi
if [ -f "$Script_Path/nonstop_save.bash" ]; then . "$Script_Path/nonstop_save.bash"; fi
if [ -f "$Script_Path/backup_props.bash" ]; then . "$Script_Path/backup_props.bash"; fi
if [ -f "$Script_Path/backup_worlds.bash" ]; then . "$Script_Path/backup_worlds.bash"; fi
if [ -f "$Script_Path/restore_world.bash" ]; then . "$Script_Path/restore_world.bash"; fi
if [ -f "$Script_Path/git_delete.bash" ]; then . "$Script_Path/git_delete.bash"; fi

# エイリアス
alias mc_start="echo start Minecraft Server; bash $Script_Path/start.sh"
alias mc_stop="echo terminate Minecraft Server; bash $Script_Path/stop.sh"
__EOF__
```

```bash:variable.bash：Minecraft
cat << '__EOF__' > "/opt/MC_Manage/variable.bash"
#!/bin/bash
export Mine_DIR Worlds_DIR Script_Path Props_Bak_DIR Worlds_Bak_DIR

# 変数
      Mine_DIR="/opt/minecraft"
    Worlds_DIR="/opt/minecraft/worlds"
   Script_Path="/opt/MC_Manage"
 Props_Bak_DIR="/opt/MC_Manage/Properties"
Worlds_Bak_DIR="/opt/MC_Manage/World_Backup"

__EOF__
```

#### tmux にコマンドを送信しやすくするエイリアス
```bash:mc_tmux.bash：Minecraft
cat << '__EOF__' > "/opt/MC_Manage/mc_tmux.bash"
#!/bin/bash
if [ ! -v MC_EnvCheck_INIT ] && [ -f "/opt/MC_Manage/mc_env.bash" ]; then
  . "/opt/MC_Manage/mc_env.bash"
fi

# tmux エイリアス
function mc_send () {
  /usr/bin/tmux send -t minecraft "$1" ENTER
}
__EOF__
```

#### サーバーを止めないで保存するスクリプト
```bash:nonstop_save.bash：Minecraft
cat << '__EOF__' > "/opt/MC_Manage/nonstop_save.bash"
#!/bin/bash
if [ ! -v MC_EnvCheck_INIT ] && [ -f "/opt/MC_Manage/mc_env.bash" ]; then
  . "/opt/MC_Manage/mc_env.bash"
fi

# Save Section
function mc_save () {
  if [ "$(tmux ls -F '#{session_name}' -f '#{==:#{session_name},minecraft}' 2>/dev/null)" != "minecraft" ]; then
    if [ "${1}" = "BAK_SERVICE" ]; then
      XDG_RUNTIME_DIR=/run/user/$(id -u minecraft) systemctl --user stop nonstop_save.timer
      exit 0
    fi || true
    git --git-dir="$Worlds_Bak_DIR/.git" \
        --work-tree="$Worlds_DIR" \
        add --intent-to-add -- :/
    git --git-dir="$Worlds_Bak_DIR/.git" \
        --work-tree="$Worlds_DIR" \
        diff --quiet --exit-code
    [ "$?" = "1" ] && backup_worlds 'Backup of stopped servers'
    # 新規ファイルか更新されたファイルがあった場合は、$?=1 を示す
    return 0
  fi

  /usr/bin/tmux send -t minecraft "save resume" ENTER
  sleep 1

  /usr/bin/tmux send -t minecraft "save hold" ENTER
  sleep 1

  EXITCODE=1 ; TRY_COUNT=0
  while [ "$EXITCODE" -ne "0" ]; do
   ((TRY_COUNT++))
    /usr/bin/tmux send -t minecraft "save query" ENTER
    sleep 1
    grep "Data saved. Files are now ready to be copied." <(tail -30 "$Mine_DIR/Result.log") > /dev/null 2>&1
    EXITCODE=$?
    if [ "$TRY_COUNT" -eq "20" ]; then break; fi
  done

  if [ "${1}_${2}" != "commit_unnecessary" ]; then
    backup_worlds 'Save running server'
  fi

  /usr/bin/tmux send -t minecraft "save resume" ENTER
}

__EOF__
```

#### Git を使ってワールドデータ・設定ファイルのバックアップ
**＃設定ファイル**
```bash:backup_props.bash：Minecraft
cat << '__EOF__' > "/opt/MC_Manage/backup_props.bash"
#!/bin/bash
if [ ! -v MC_EnvCheck_INIT ] && [ -f "/opt/MC_Manage/mc_env.bash" ]; then
  . "/opt/MC_Manage/mc_env.bash"
fi

# エイリアス 設定ファイル関連
function backup_props () {
  git --git-dir="$Props_Bak_DIR/.git" \
      --work-tree="$Mine_DIR" \
      add -- permissions.json server.properties allowlist.json
  git -C "$Props_Bak_DIR" commit --amend --date=now --allow-empty-message -m ''"$@"

  mc_delete "$Props_Bak_DIR" 10
}

function show_props_bak () {
  git -C "$Props_Bak_DIR" --no-pager log --max-count=${1:-5} --reflog --format='%C(auto)%+h [%ad] %Cgreen%s' --name-only; echo ''
}

__EOF__
```

**＃ワールドデータ**
```bash:backup_worlds.bash：Minecraft
cat << '__EOF__' > "/opt/MC_Manage/backup_worlds.bash"
#!/bin/bash
if [ ! -v MC_EnvCheck_INIT ] && [ -f "/opt/MC_Manage/mc_env.bash" ]; then
  . "/opt/MC_Manage/mc_env.bash"
fi

# エイリアス ワールドデータ関連
function backup_worlds () {
  SET_PATH="GIT_DIR=\"$Worlds_Bak_DIR/.git\" GIT_WORK_TREE=\"$Worlds_DIR\""
  unset Args
  while read READ; do 
    Args="$Args \"$READ\""
  done < <(eval $SET_PATH git ls-files --others --exclude-standard :/)
  eval $SET_PATH git add -- $Args >/dev/null 2>&1
  eval $SET_PATH git add --update
  eval $SET_PATH git update-index --remove --stdin < <(eval $SET_PATH git ls-files :/)
  git -C "$Worlds_Bak_DIR" commit --amend --date=now --allow-empty-message -m ''"$@"
  unset SET_PATH

  mc_delete "$Worlds_Bak_DIR"
  echo "Backups have been completed."
}

function show_worlds_bak () {
  SKIP=0
  while read LINE; do
    git -C "$Worlds_Bak_DIR" log --max-count=1 --skip=$SKIP --reflog --format='%C(auto)%h [%ad] %Cgreen%s'
    git -C "$Worlds_Bak_DIR" ls-tree -d --name-only $LINE
    echo ''
   ((SKIP++))
  done < <(git -C "$Worlds_Bak_DIR" log --max-count=${1:-5} --reflog --format='%C(auto)%h')
}

__EOF__
```

#### 復元用スクリプト
```bash:restore_world.bash：Minecraft
cat << '__EOF__' > "/opt/MC_Manage/restore_world.bash"
#!/bin/bash
if [ ! -v MC_EnvCheck_INIT ] && [ -f "/opt/MC_Manage/mc_env.bash" ]; then
  . "/opt/MC_Manage/mc_env.bash"
fi

# 既存のワールドを上書き
function restore_world () {
  if [ ! -d "$Worlds_DIR/$2" ]; then
    echo "ワールドが存在しません。正しいフォルダ名を入力してください。"
    return 1
  fi

  unset Commit_ID
  if [ "$1" = "HEAD" ] || [ "$1" = "@" ] || [ "$1" = "" ]; then
    read Commit_ID < \
    <(git --git-dir="$Worlds_Bak_DIR/.git" \
          --work-tree="$Worlds_DIR" \
          for-each-ref \
            --sort=-committerdate \
            --count=1 \
            --format="%(objectname:short)" \
            refs/heads)
  fi
  Commit_ID=${Commit_ID:-$1}
  backup_worlds 'Backup before restore'
  git --git-dir="$Worlds_Bak_DIR/.git" \
      --work-tree="$Worlds_DIR" \
      restore --no-overlay --worktree --source=$Commit_ID -- "$2"
}

# 別のワールドとして復元
function restore_another () {
  if [ "$3" = "" ]; then
    echo "復元先のフォルダ名が入力されていません。新しいフォルダ名を入力してください。"
    return 1
  fi

  Another_Name="$3"
  Another_DIR="$Worlds_DIR/$Another_Name"
  if [ -d "$Another_DIR" ]; then
    echo "すでにその名前のフォルダーが存在しています。別の名前で再度実行してください。"
    return 1
  fi
  mkdir -p "$Another_DIR"
  git -C "$Worlds_Bak_DIR" archive --format=tar $1 -- "$2" | tar Cx "$Another_DIR" --strip-components 1
}

__EOF__
```

#### バックアップの削除用スクリプト
```bash:git_delete.bash：Minecraft
cat << '__EOF__' > "/opt/MC_Manage/git_delete.bash"
#!/bin/bash
if [ ! -v MC_EnvCheck_INIT ] && [ -f "/opt/MC_Manage/mc_env.bash" ]; then
  . "/opt/MC_Manage/mc_env.bash"
fi

function mc_delete () {
  unset SKIP Working_DIR
  SKIP=${2:-2}
  Working_DIR=${1:-$Worlds_Bak_DIR}

  while read COUNT_HEAD; do 
    git -C "$Working_DIR" reflog delete "HEAD@{$SKIP}"
  done < <(git -C "$Working_DIR" --no-pager log --walk-reflogs --skip=$SKIP --format='%gd' HEAD)

  while read COUNT_MAIN; do 
    git -C "$Working_DIR" reflog delete "$(git -C "$Working_DIR" branch --show-current)@{$SKIP}"
  done < <(git -C "$Working_DIR" --no-pager log --walk-reflogs --skip=$SKIP --format='%gd' refs/heads/$(git -C "$Working_DIR" branch --show-current))

  git -C "$Working_DIR" gc --quiet
}

__EOF__
```

#### 最後に実行
```bash:＃１１個のファイルに対して存在確認を行う：Minecraft
DIR=/opt/MC_Manage ;A=0 ;if : ;then
  [ -e $DIR/start.sh ] || eval 'A=1 ;echo "not exist \"start.sh\". Please create it."'
  [ -e $DIR/backup.sh ] || eval 'A=1 ;echo "not exist \"backup.sh\". Please create it."'
  [ -e $DIR/stop.sh ] || eval 'A=1 ;echo "not exist \"stop.sh\". Please create it."'
  [ -e $DIR/mc_env.bash ] || eval 'A=1 ;echo "not exist \"mc_env.bash\". Please create it."'
  [ -e $DIR/variable.bash ] || eval 'A=1 ;echo "not exist \"variable.bash\". Please create it."'
  [ -e $DIR/mc_tmux.bash ] || eval 'A=1 ;echo "not exist \"mc_tmux.bash\". Please create it."'
  [ -e $DIR/backup_props.bash ] || eval 'A=1 ;echo "not exist \"backup_props.bash\". Please create it."'
  [ -e $DIR/backup_worlds.bash ] || eval 'A=1 ;echo "not exist \"backup_worlds.bash\". Please create it."'
  [ -e $DIR/nonstop_save.bash ] || eval 'A=1 ;echo "not exist \"nonstop_save.bash\". Please create it."'
  [ -e $DIR/restore_world.bash ] || eval 'A=1 ;echo "not exist \"restore_world.bash\". Please create it."'
  [ -e $DIR/git_delete.bash ] || eval 'A=1 ;echo "not exist \"git_delete.bash\". Please create it."'
  [ "$A" = "0" ] && echo "OK. All files exist."
fi
```

~~~bash:bash：Minecraft
＃改行コード
for file in /opt/MC_Manage/* ;do sed -i -e 's/\r//g' "$file" && echo "$file" ;done

＃環境変数、関数の読み込み
source ~/.bash_profile

exit
~~~

~~~bash:bash：USER
＃サービスの読み込み
sudo systemctl daemon-reload

＃念のためタイムゾーンを東京に変更するコマンドを実行する
sudo timedatectl set-timezone Asia/Tokyo
~~~

### ファイアウォールの構成
```sudo apt install ufw bind9-dnsutils -y```

**ここから先は各自で自分に合った設定を行ってください**
```bash:bash：USER
# sudo ufw reset && sudo ufw status

# 内側に入ってくる通信を既定で拒否
sudo ufw default deny
# LAN内の通信をすべて許可
sudo ufw allow from 192.168.0.0/16
# Tailscaleも許可
# ip -f inet -o addr show | grep tail | awk -F '[: ]' '{print $3}'
sudo ufw allow in on tailscale0
# SSHには念のため制限を掛けておく
sudo ufw limit ssh

# UFWの有効化
sudo ufw enable
sudo ufw reload
sudo ufw status verbose
```
**Minecraft 用のファイアウォール構成ファイルを作成**
```bash:bash：USER
sudo su -c "cat << '__EOF__' > '/etc/ufw/applications.d/Minecraft'
[Minecraft]
title=Minecraft
description=Minecraft UDP Port
ports=19132:19133/udp
__EOF__"
```
**Minecraft Server 参加者をホワイトリスト形式で許可**
**↓使い方：**```sudo bash ~/AcceptMC.bash```
　**Minecraft に参加する人の名前:** 個々人を識別するための一意な名前を入力
　**Minecraft に参加する人のIPまたはホスト名:** グローバルIPアドレスかホスト名を入力
※各参加者の "グローバルIPアドレス" が変わる都度、更新してください
```bash:AcceptMC.bash：USER
cat << '__EOF__' > ~/AcceptMC.bash
#!/bin/bash
# 詳細を入力
printf ' Minecraft に参加する人の名前: ' ; read MC_Connect_USER ; echo $MC_Connect_USER
printf ' Minecraft に参加する人のIPまたはホスト名: ' ; read HOSTNAME_OR_IP ; echo $HOSTNAME_OR_IP

# 変数解除
unset IP_Addr MC_USER

# 古いファイアウォールの構成
MC_USER="${MC_Connect_USER:-NONE_OLD_FW}"
Old_FW=$(sudo ufw show added | awk "/Minecraft comment/"' && '"/$MC_USER/")
Old_FW="${Old_FW#'ufw '}"

# 新しいファイアウォールの構成
IP_Addr="$(dig +short $HOSTNAME_OR_IP)"
IP_Addr="${IP_Addr:-$HOSTNAME_OR_IP}"
New_FW="allow from $IP_Addr to any app Minecraft comment '$MC_USER'"

# 設定を更新
if [ "$Old_FW" != "$New_FW" ]; then
  [ -n "$Old_FW" ] && eval sudo ufw delete "$Old_FW" && echo "DELETE Older FireWall"
  eval sudo ufw "$New_FW" && echo "CREATE New FireWall"
else
  echo "do not update."
fi

# 確認
sudo ufw status | awk '/Action/;/------/;/Minecraft/'

echo "Script Finish"
exit 0
__EOF__
```
単純にファイアウォールを削除する場合は
```bash:bash：USER
# 以下の実行結果の中から取り消したいコマンドをコピー
sudo ufw show added | sed '1d;s/^ufw//'

# 下のコマンドに続けてペースト
sudo ufw delete 
```


以上！！！