Linux - Systemd Service Unit for Minecraft Servers

I am currently running two Minecraft servers and planning to spin a third. However it is becoming an ordeal to manage all the tmux sessions for them. I then have decided to use systemd to manage them and create room for dynamic growth.

1) Creating the unit file

This unit is set as Type=forking where the initial process is expected to fork at least once and exit, leaving a child running.

The ExecStop= options make sure to announce that the server is shutting down to the players, stop and save the map. And finally, kill the tmux session.

[Unit]
Description=Minecraft Server %i
After=network.target

[Service]
WorkingDirectory=/mineserver/%i
Type=forking

PrivateUsers=true

# User Config
User=minecraft
Group=minecraft

# Security Options
ProtectSystem=full
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true

# Default Memory Values
Environment="MCMINMEM=12G" "MCMAXMEM=12G" "SHUTDOWN_DELAY=10" "POST_SHUTDOWN_DELAY=15"
EnvironmentFile=-/mineserver/%i/server.conf

# Starting - Minecraft Server
ExecStart=/usr/bin/tmux -L %i new-session -c /mineserver/%i/ -s %i -d '/bin/java -Xms${MCMINMEM} -Xmx${MCMAXMEM} -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=40 -XX:G1MaxNewSizePercent=50 -XX:G1HeapRegionSize=16M -XX:G1ReservePercent=15 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -jar fabric-server-launch.jar nogui'

# Logging
LogLevelMax=debug

# Stopping - Minecraft Server
ExecStop=/usr/bin/tmux \
         -L %i \
         send-keys \
         -t %i:0.0 'say Servidor Desligando. Salvando mapa...' Enter \
         'save-all' 
# Delay
ExecStop=/bin/sh -c '/bin/sleep ${SHUTDOWN_DELAY}'

# Stop command
ExecStop=/usr/bin/tmux \
         -L %i \
         send-keys \
         -t %i:0.0 'stop' Enter \

# Delay before kill the tmux session
ExecStop=/bin/sh -c '/bin/sleep ${POST_SHUTDOWN_DELAY}'

# Terminating the tmux session
ExecStop=/usr/bin/tmux \
         -L %i \
         kill-session \
         -t %i

Restart=on-failure
RestartSec=60s

[Install]
WantedBy=multi-user.target

/etc/systemd/system/minecraft@.service

After= Ensure that the unit starts after the networking.

WorkingDirectory= Sets the working directory for executed processes.

Type= The service manager will consider the unit up after the main process exits.

PrivateUsers= Sets up a new user namespace for the executed processes and configures a minimal user and group mapping.

ProtectSystem= If set to "full", the /etc/ directory is mounted read-only.

ProtectHome= If true, the directories /home/, /root, and /run/user are made inaccessible and empty for processes invoked by this unit.

ProtectKernelTunables= If true, kernel variables will be made read-only to all processes of the unit.

ProtectKernelModules= If true, explicit module loading will be denied.

ProtectControlGroups= If true, the Linux Control Groups hierarchies accessible through /sys/fs/cgroup/ will be made read-only to all processes of the unit.

Environment= Sets environment variables for executed processes.

EnvironmentFile= Similar to Environment= but reads the environment variables from a text file. Settings from this file override settings created with Enviroment=.

Restart= Configures whether the service shall be restarted when the service process exits, is killed, or a timeout is reached.

RestartSec= Configures the time to sleep before restarting a service.

Let's verify if the unit has no sysntax erros.

systemd-analyze verify /etc/systemd/system/minecraft@.service

2) How to use

The working directory is /mineserver and we just need to create folders for each server we want to run and enable/start the service according to its folder name.

┬─[root@minecraft:/mineserver]─[00:49:06]
╰─>$ tree -L 1
.
├── 0
├── backups
├── mc1-fabric-carpet-1-18-1
├── scripts
systemctl enable minecraft@mc1-fabric-carpet-1-18-1
systemctl start minecraft@mc1-fabric-carpet-1-18-1
┬─[root@minecraft:/mineserver]─[00:52:31]
╰─>$ systemctl status minecraft@mc1-fabric-carpet-1-18-1
● minecraft@mc1-fabric-carpet-1-18-1.service - Minecraft Server mc1-fabric-carpet-1-18-1
     Loaded: loaded (/etc/systemd/system/minecraft@.service; enabled; vendor preset: disabled)
     Active: active (exited) since Sat 2022-02-05 00:52:31 GMT; 2s ago
    Process: 112110 ExecStart=/usr/bin/tmux new-session -c /mineserver/mc1-fabric-carpet-1-18-1/ -s mc1-fabric-carpe>
   Main PID: 112110 (code=exited, status=0/SUCCESS)
        CPU: 39ms

Feb 05 00:52:31 minecraft systemd[1]: Starting Minecraft Server mc1-fabric-carpet-1-18-1...
Feb 05 00:52:31 minecraft systemd[1]: Finished Minecraft Server mc1-fabric-carpet-1-18-1.

Starting the server.

┬─[root@minecraft:/mineserver]─[00:54:50]
╰─>$ systemctl stop minecraft@mc1-fabric-carpet-1-18-1
┬─[root@minecraft:/mineserver]─[00:57:12]
╰─>$ systemctl status minecraft@mc1-fabric-carpet-1-18-1
○ minecraft@mc1-fabric-carpet-1-18-1.service - Minecraft Server mc1-fabric-carpet-1-18-1
     Loaded: loaded (/etc/systemd/system/minecraft@.service; enabled; vendor preset: disabled)
     Active: inactive (dead) since Sat 2022-02-05 00:57:12 GMT; 3s ago
    Process: 112110 ExecStart=/usr/bin/tmux new-session -c /mineserver/mc1-fabric-carpet-1-18-1/ -s mc1-fabric-carpet-1-18-1 -d /bin/j>
    Process: 112260 ExecStop=/usr/bin/tmux send-keys -t mc1-fabric-carpet-1-18-1:0.0 say Servidor Desligando. Salvando mapa... Enter s>
    Process: 112262 ExecStop=/bin/sh -c /bin/sleep ${SHUTDOWN_DELAY} (code=exited, status=0/SUCCESS)
    Process: 112267 ExecStop=/usr/bin/tmux send-keys -t mc1-fabric-carpet-1-18-1:0.0 stop Enter (code=exited, status=0/SUCCESS)
    Process: 112269 ExecStop=/bin/sh -c /bin/sleep ${POST_SHUTDOWN_DELAY} (code=exited, status=0/SUCCESS)
    Process: 112274 ExecStop=/usr/bin/tmux kill-session -t mc1-fabric-carpet-1-18-1 (code=exited, status=0/SUCCESS)
   Main PID: 112110 (code=exited, status=0/SUCCESS)
        CPU: 173ms

Feb 05 00:52:31 minecraft systemd[1]: Starting Minecraft Server mc1-fabric-carpet-1-18-1...
Feb 05 00:52:31 minecraft systemd[1]: Finished Minecraft Server mc1-fabric-carpet-1-18-1.
Feb 05 00:56:47 minecraft systemd[1]: Stopping Minecraft Server mc1-fabric-carpet-1-18-1...
Feb 05 00:57:12 minecraft systemd[1]: minecraft@mc1-fabric-carpet-1-18-1.service: Deactivated successfully.
Feb 05 00:57:12 minecraft systemd[1]: Stopped Minecraft Server mc1-fabric-carpet-1-18-1.

Stopping the server.

Resources

Tutorials/Server startup script
This is an example of possible Minecraft server startup and maintenance script for GNU/Linux distros. For all modern Servers supporting Systemd. Systemd is the jack of all trades. For Ubuntu, it comes with 15.04 (15.04 is an old version which have had end-of-support, we suggest using later LTS versi…
Minecraft systemd unit file that uses tmux instead of screen
Minecraft systemd unit file that uses tmux instead of screen - gist:bb17853ffc76fbb9b039
systemd.service
systemd - ArchWiki
systemd.unit(5) — Arch manual pages
systemd.syntax(7) — Arch manual pages
Systemctl service timed out during start
<I have created *.service and placed it in my /etc/systemd/system folder: [Unit] Description=WSO2 IoT Message broker [Service] Environment="JAVA_HOME=/usr/lib/jvm/java-8-oracle" Type=
tmux(1) - Linux manual page
Why is systemd stopping service immediately after it is started?
I created a systemd service which should invoke a shell script, when started or on reboot. [Unit] Description=Starts the DCCA index software [Install] WantedBy=multi-user.target [Service] ExecSta...
How can I start a totally independentt new instance of tmux?
If I have already a tmux session opened, results that I can’t start a new one with another tmux configuration, for ie: $ tmux # loads new session using ~/.tmux.conf In another terminal... $ tmux...