Memo: How I launched a Minecraft server (JE & BE) using a 7-year old laptop

**Disclaimer**
This is just like a memo for myself. No detailed explanation. Please google the keywords if you need.

## Goal

To launch Minecraft server for with friends (= outside of my LAN) using my old laptop. 

Some said they want to play Java Edition (JE), whilst others wanted Bedrock Edition (BE). So I tryed running both versions simultaneously, which is now successfully working. 


## Requirements

- Assuming up to 5 users' simultaneous connections
- Shutdown automatically every morning, and reboot every evening (some people warn that one should not run a laptop for 24h as a server)
- Assign one of my sub-domain for the server so that users can access the server easily.

## Rig

**ASUS UX305FA-5Y71**

- CPU: Core M-5Y71 (2 cores, 4 threads, 1.2 GHz base - 2.9 GHz max., TDP 4.5W)
- RAM: 8GB
- Strage: 128GB SSD

Ubuntu 20.04 LTS (with GUI) was already installed.

## What I did

### Unplug its inner battery

This is a very important step for safety. The rig is expected to be connected with the power plug while running as a server, which is an inadequate condition for the Li-ion battery.

Open the bottom cover of the laptop, and unplug the battery from the circuit board. Then, mask the battery-side connecter with tape to isolate electrically.

### Preparation

- Install Docker  
  Follow the instruction in Docker official document.
- Install SSH Server (``sudo apt install openssh-server``)
- Make Directories:
    - ~/Minecraft
        - ./data
        - ./mc-backup
    - ~/Minecraft-be
        - ./data
- Disable GUI (`` sudo systemctl set-default multi-user.target ``) 
  (You can do this whenever you like, and redo this by ``sudo systemctl set-default graphical.target``)  
  cf. https://tek2tech.com/ubuntu-2004-desktop-environment/
  


### Pull Docker Image

- https://hub.docker.com/r/itzg/minecraft-server
- https://hub.docker.com/r/itzg/mc-backup
- https://hub.docker.com/r/itzg/minecraft-bedrock-server

cf.  
https://frontl1ne.net/2019/10/docker-minecraft/

### Write ``docker-compose.yml`` 
cf. https://oldbigbuddha.dev/posts/my-server-for-minecraft

```yml:~/Minecraft/docker-compose.yml
version: "3"

services:
  # Application
  mc-paper:
    image: itzg/minecraft-server
    ports:
      - 25565:25565
      - 25575:25575
    environment:
      EULA: "TRUE"
      TYPE: "PAPER"
      INIT_MEMORY: "1G"
      MAX_MEMORY: "4G"

      STOP_SERVER_ANNOUNCE_DELAY: 60

      # Disable following AutoPause-related settings
      # due to Spigot's error.
      #
      # ENABLE_AUTOPAUSE: "TRUE"
      # MAX_TICK_TIME: "-1"
      #  More aggressive settings for demo purposes
      # AUTOPAUSE_TIMEOUT_INIT: "30"
      # AUTOPAUSE_TIMEOUT_EST: "10"
      #
      # OVERRIDE_SERVER_PROPERTIES: "TRUE"
    volumes:
      - ./data:/data
      - /etc/timezone:/etc/timezone:ro
    tty: true
    stdin_open: true
    restart: always
    deploy:
      resources:
        limits:
          memory: 4500m

  # Backup
  backup:
    image: itzg/mc-backup
    environment:
      BACKUP_INTERVAL: "6h"
      PRUNE_BACKUPS_DAYS: 3
      PAUSE_IF_NO_PLAYERS: "false"
      INITIAL_DELAY: "10m"
    depends_on:
    - mc-paper
    volumes:
      - ./data:/data:ro
      - ./mc-backups:/backups
      - /etc/timezone:/etc/timezone:ro
    restart: unless-stopped
    network_mode: "service:mc-paper"
```

```yml:~/Minecraft-be/docker-compose.yml
version: "3"

services:
  # Application
  mc-be:
    image: itzg/minecraft-bedrock-server
    ports:
      - 19132:19132/udp
    environment:
      EULA: "TRUE"
      SERVER_NAME: "My_MineCraft_Bedrock"
    volumes:
      - ./data:/data
      - /etc/timezone:/etc/timezone:ro
    tty: true
    stdin_open: true
    restart: always
    deploy:
      resources:
        limits:
          memory: 2500m
```

To make the RAM resource limits effective, we need to desiginate ``--compatibility`` options when ``docker-compose up`` and ``down``. This is not recommended, according to the docker official. If your machine has plenty amount of RAM, you may not need to determine the limit and use ``--compatibility`` option.


### Allow the user to run ``docker`` without ``sudo`` 
cf. https://qiita.com/DQNEO/items/da5df074c48b012152ee
```bash:bash
$ sudo groupadd docker
$ sudo gpasswd -a <USERNAME> docker
$ sudo systemctl restart docker
```
Then, reboot (or relogin) to enable the setting.


### Define Firewall Ruleset

```bash:bash
$ sudo ufw status
```
  
```:ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       192.168.11.0/24
25565/tcp                  ALLOW       Anywhere
25575                      ALLOW       192.168.11.0/24
19132                      ALLOW       Anywhere
25565/tcp (v6)             ALLOW       Anywhere (v6)
19132 (v6)                 ALLOW       Anywhere (v6)
```

Note:
- Port 22 ... for SSH (only from LAN)
- Port 25565 ... for Minecraft Java Edition (TCP)
- Port 25575 ... for Minecraft Java RCON (only from LAN) (TCP)
- Port 19132 ... for Minecraft Bedrock Edition (UDP (+TCP ?))

Don't forget setting the port forwarding up of the router.


### Prevent the System from Sleep Mode When the Lid is Closed 

Add ``HandleLidSwitch=ignore`` in ``/etc/systemd/logind.conf``.

  https://nisshingeppo.com/ai/ubuntu-nonsleep/



### Prepare Shell Scripts for ``docker-compose up`` and ``docker-compose down``



```bash:~/Minecraft/Minecraft-up.sh
#!usr/bin/bash -l

echo `date +%Y-%m-%dT%H:%M:%S`\| Launching JAVA Edition on mc-je screen
/usr/bin/screen -U -A -m -d -S mc-je /usr/local/bin/docker-compose --file /home/<USERNAME>/Minecraft/docker-compose.yml --compatibility up
echo `date +%Y-%m-%dT%H:%M:%S`\| Waiting for 5 min ...
sleep 300
echo `date +%Y-%m-%dT%H:%M:%S`\| Launching BedRock Edition on the mc-be screen
/usr/bin/screen -U -A -m -d -S mc-be /usr/local/bin/docker-compose --file /home/<USERNAME>/Minecraft-be/docker-compose.yml --compatibility up
```
```bash:~/Minecraft/Minecraft-down.sh
#!usr/bin/bash -l

echo `date +%Y-%m-%dT%H:%M:%S`\| Shutting Minecraft JAVA Edition down...
/usr/local/bin/docker-compose --file /home/<USERNAME>/Minecraft/docker-compose.yml --compatibility down -t 600

echo `date +%Y-%m-%dT%H:%M:%S`\| Shutting Minecraft BedRock Edition down...
/usr/local/bin/docker-compose --file /home/<USERNAME>/Minecraft-be/docker-compose.yml --compatibility down -t 600
```


### Save backups and transfer them to NAS via FTP
cf. https://qiita.com/kabegamikamio/items/9c1a30c63de31be834da

For JAVA editon, we can use ``itzg/mc-backup`` docker package. However, for bedrock edition, we need to manage backup by ourselves.
```bash:~/Minecraft-be/be-backup.sh
#!/bin/bash

TARGET_DIR=/home/<USERNAME>/Minecraft-be/data/worlds

BACKUP_DIR=/home/<USERNAME>/Minecraft-be/backup/`date +%Y-%m-%d_%H:%M:%S`
BACKUP_FOLDER=/home/<USERNAME>/Minecraft-be/backup/

NUM_GENS=5

delete_file () {
    CNT=0
    for file in `ls -1t ${BACKUP_FOLDER}*.zip`
    do
        CNT=$((CNT+1))
        if [ $CNT -le $NUM_GENS ]; then
            continue
        fi
        eval "rm ${file}"
    done
}


makezip () {
    zip ${1} -r ${2}
}


make_zip $BACKUP_DIR $TARGET_DIR
delete_file
```
This code compresses the world folder to a timestamped zip file and delete past file to remain last ``NUM_GEN`` (=5, in this example) backups.

And, to keep these backups more solidly, I upload them onto my local NAS using FTP:
```bash:~/Minecraft/ftp-upload.sh
#!/usr/bin/bash -l

/usr/bin/ftp -n >> /home/<USERNAME>/Minecraft/ftp-upload.log << EOF
  verbose
  open <IP ADDRESS>
  user <FTP USERNAME> <FTP PASSWORD>
  prompt
  passive
  cd /mc-backup/je/
  lcd /home/<USERNAME>/Minecraft/mc-backups
  mput *
  cd /mc-backup/be
  lcd /home/<USERNAME>/Minecraft-be/backup
  mput *
  bye
EOF
```  
Note: it may be better to designate "ftp -n -p" to make sure to use active mode.

### Write ``crontab`` settings

```bash:bash
$ crontab -e
```

This command opens the crontab setting file with an editor. My setting is as below:

```:/var/spool/cron/crontabs/<USERNAME>
# m h  dom mon dow   command
SHELL=/usr/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin/
@reboot            bash -l /home/<USERNAME>/Minecraft/Minecraft-up.sh >> /home/(USERNAME)/Minecraft/Minecraft-up.log 2>&1

 00 1   *   *   *  bash -l /home/<USERNAME>/Minecraft-be/be-backup.sh >> /home/(USERNAME)/Minecraft-be/be-backup.log 2>&1
  5 8   *   *   *  bash -l /home/<USERNAME>/Minecraft/Minecraft-down.sh >> /home/(USERNAME)/Minecraft/Minecraft-down.log 2>&1
 10 8   *   *   *  bash -l /home/<USERNAME>/Minecraft-be/be-backup.sh >> /home/(USERNAME)/Minecraft-be/be-backup.log 2>&1
 15 8   *   *   *  bash -l /home/<USERNAME>/Minecraft/Minecraft-down.sh >> /home/(USERNAME)/Minecraft/Minecraft-down.log 2>&1
      
```

To set up auto scheduled shutdown and restart using `rtcwake`, we need to execute ``crontab`` under ``sudo``:
```bash:bash
$ crontab -e
```

```:/var/spool/cron/crontabs/root
# m h  dom mon dow   command
SHELL=/usr/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin

 20 8   *   *   *   /usr/sbin/rtcwake -s 36000 -m off >> /home/<USERNAME>/Minecraft/Minecraft-servershutdown.log 2>&1
```
This setting schedules automatic shutdown (=``-m off``) at 08:20 every morning and automatic reboot at 18:20 (= ``-s 36000`` = 36,000 seconds = 10 hours after 08:20).

cf. 
https://awnet.org/archives/53
https://freefielder.jp/blog/2018/07/ubuntu-cron-sudo.html


----

### Appendix. Automatic Login when booted

**This is possibly unnecessary for this work.**

One may be need to create ``/etc/systemd/system/getty@tty1.service.d`` directory and ``override.conf`` file before execute the scripts above. 

```bash:bash
sudo systemctl edit getty@tty1
```
```:/etc/systemd/system/getty@tty1.service.d/override.conf
[Service]
ExecStart=
ExecStart=-/sbin/agetty/ --noissue --autologin (USERNAME) %I $TERM
Type=idle
```
cf.   
https://zenn.dev/noraworld/articles/ubuntu-reboot-auto-login
https://askubuntu.com/questions/819117/how-can-i-get-autologin-at-startup-working-on-ubuntu-server-16-04-1