minecraft-tmux-service
minecraft-tmux-service copied to clipboard
minecraft.service launches script, then process exits
Thanks for making these scripts available. They are by far the best of the minecraft init scripts I have run across.
I'm having a bit of an issue when launching it from systemctrl. The tmux and java process start, then stop a second or two later. The shell script works correctly; it's only when launching from systemd that I have an issue.
root@dorkcraft:/usr/local/bin/minecraft# systemctl status minecraft
* minecraft.service - Minecraft Server
Loaded: loaded (/lib/systemd/system/minecraft.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Fri 2021-01-01 18:42:58 CST; 18min ago
Process: 5246 ExecStart=/usr/local/bin/minecraft/service.sh start (code=exited, status=0/SUCCESS)
Process: 5283 ExecStop=/usr/local/bin/minecraft/service.sh stop (code=exited, status=1/FAILURE)
Main PID: 5250 (code=exited, status=0/SUCCESS)
Jan 01 18:42:52 dorkcraft systemd[1]: Starting Minecraft Server...
Jan 01 18:42:52 dorkcraft service.sh[5246]: Starting minecraft server in tmux session
Jan 01 18:42:52 dorkcraft systemd[1]: Started Minecraft Server.
Jan 01 18:42:58 dorkcraft service.sh[5283]: Server is not running!
Jan 01 18:42:58 dorkcraft systemd[1]: minecraft.service: Control process exited, code=exited, status=1/FAILURE
Jan 01 18:42:58 dorkcraft systemd[1]: minecraft.service: Failed with result 'exit-code'.
Here's the service script. The only changes I've made are to change the location to my install.
[Unit]
Description=Minecraft Server
Wants=network.target
After=network.target
[Service]
Type=forking
User=minecraft
Group=minecraft
KillMode=none
ProtectHome=read-only
ProtectSystem=full
PrivateDevices=no
NoNewPrivileges=yes
PrivateTmp=no
InaccessiblePaths=/root /sys /srv -/opt /media -/lost+found
ReadWritePaths=/usr/local/bin/minecraft
WorkingDirectory=/usr/local/bin/minecraft
ExecStart=/usr/local/bin/minecraft/service.sh start
ExecReload=/usr/local/bin/minecraft/service.sh reload
ExecStop=/usr/local/bin/minecraft/service.sh stop
[Install]
WantedBy=multi-user.target
And here's the shell script. It is executable. I changed the location here as well as a couple of minecraft arguments. Note that $MC_HOME/minecraft/minecraft-server
is simply a link, so that is correct.
# Minecraft service that starts the minecraft server in a tmux session
MC_HOME="/usr/local/bin/minecraft"
TMUX_SOCKET="minecraft"
TMUX_SESSION="minecraft"
is_server_running() {
tmux -L $TMUX_SOCKET has-session -t $TMUX_SESSION > /dev/null 2>&1
return $?
}
mc_command() {
cmd="$1"
tmux -L $TMUX_SOCKET send-keys -t $TMUX_SESSION.0 "$cmd" ENTER
return $?
}
start_server() {
if is_server_running; then
echo "Server already running"
return 1
fi
echo "Starting minecraft server in tmux session"
tmux -L $TMUX_SOCKET new-session -c $MC_HOME -s $TMUX_SESSION -d /usr/bin/java -Xms512M -Xmx1024M -jar $MC_HOME/minecraft/minecraft-server nogui
return $?
}
stop_server() {
if ! is_server_running; then
echo "Server is not running!"
return 1
fi
# Warn players
echo "Warning players"
mc_command "title @a times 3 14 3"
for i in {10..1}; do
mc_command "title @a subtitle {\"text\":\"in $i seconds\",\"color\":\"gray\"}"
mc_command "title @a title {\"text\":\"Shutting down\",\"color\":\"dark_red\"}"
sleep 1
done
# Issue shutdown
echo "Kicking players"
mc_command "kickall"
echo "Stopping server"
mc_command "stop"
if [ $? -ne 0 ]; then
echo "Failed to send stop command to server"
return 1
fi
# Wait for server to stop
wait=0
while is_server_running; do
sleep 1
wait=$((wait+1))
if [ $wait -gt 60 ]; then
echo "Could not stop server, timeout"
return 1
fi
done
return 0
}
reload_server() {
tmux -L $TMUX_SOCKET send-keys -t $TMUX_SESSION.0 "reload" ENTER
return $?
}
attach_session() {
if ! is_server_running; then
echo "Cannot attach to server session, server not running"
return 1
fi
tmux -L $TMUX_SOCKET attach-session -t $TMUX_SESSION
return 0
}
case "$1" in
start)
start_server
exit $?
;;
stop)
stop_server
exit $?
;;
reload)
reload_server
exit $?
;;
attach)
attach_session
exit $?
;;
*)
echo "Usage: ${0} {start|stop|reload|attach}"
exit 2
;;
esac
This is running in an Ubuntu 20.04 LXC container. More info:
root@dorkcraft:~# uname -a
Linux dorkcraft 5.4.34-1-pve #1 SMP PVE 5.4.34-2 (Thu, 07 May 2020 10:02:02 +0200) x86_64 x86_64 x86_64 GNU/Linux
root@dorkcraft:~# systemd --version
systemd 245 (245.4-4ubuntu3.3)
+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=hybrid
+1 for all of the information provided.
I don't see any mistake in your changes. Does the Minecraft server log file state any reason why the server is shutting down?
Looking at the man page of systemd.exec
, I found this in the section about ReadWritePaths=
Use ReadWritePaths= in order to whitelist specific paths for write access if ProtectSystem=strict is used.
It doesn't state what happens if ProtectSystem
is set to full
. Although unlikely, there is a chance that changing it to strict
could help. A side effect would be, that /tmp
gets protected, too. This needs to stay writeable for the minecraft user to allow tmux creating its socket in there.
ProtectSystem=strict
ReadWritePaths=/usr/local/bin/minecraft /tmp
On the other hand you could also try to relax the restrictions done by systemd since you're already using containerization. Although I have no experience with LXC and don't know what parts of the system are isolated by it.
If you want to leave it to LXC or don't need the extra protection, you can remove the lines from ProtectSystem
to ReadWritePaths
.
Thanks for replying. Upon further inspection, I realized that although the process didn't die when running from the script, I could not connect to the tmux session. It thought there were no sessions. So I started to simplify the command. I took out -c $MC_HOME
, and when that didn't help, -L $TMUX_SOCKET
. Taking out the socket allowed me to connect to the session. I suspect this might be due to an apparmor profile protecting the /tmp
directory, although I also don't understand the use of -c $MC_HOME
here, since it is only a directory.
I added the separate socket so that no one could accidentally close the tmux session, as it won't show up when using the default socket. This is to help preventing that the server stops without systemd knowing about it. If there was a pid file systemd could monitor the process directly, but I couldn't find one for tmux / the process running in the tmux terminal. Using the default socket should work just as fine.
The -c $MC_HOME
specifies the directory that the tmux session is started in. -c
has a different meaning when used with tmux
directly (similar to -L $TMUX_SOCKET
) than when used with the new-session
sub-comand. Basically this specifies the working directory and a cd $MC_HOME && java -jar ...
has the same effect.
I found a way to create a pid file for the minecraft process. Maybe this will help with your problem, as systemd recommends having a PIDFile set if the service type is forking
to determine the main process.
Determining the pid relies on the tmux session being the only one on the socket, so be careful with using the default socket.
I hope this helps :slightly_smiling_face:
Thanks! I have made a couple of posts trying to get to the bottom of the socket issue in an unprivileged LXC container, but have yet to receive any feedback. I suspect that it's a container issue, but don't understand why the user should not be able to access their own socket.
I'll give your change a try when I have a few spare moments.
i went for a different approach, on my ProxMox LXC RockyLinux (now 8.6) container and wanted to share it :
Assumptions:
- minecraft server is installed in /opt/minecraft
- a minecraft user exists and has as home /opt/minecraft ( useradd -r -m -U -d /opt/minecraft -s /bin/bash minecraft )
- the minecraft server jar-file is either named directly as server.jar, or is a symlink to the actual server-
.jar ( i use symlink so easy switching/upgrading without having to fiddle with hardcoded filenames)
systemd unitfile:
[[Unit]
Description=Minecraft Server
[Service]
WorkingDirectory=/opt/minecraft
User=minecraft
Type=forking
ExecStart=/usr/bin/tmux new -s minecraft -d "/usr/bin/java -Xmx3096M -Xms2048M -XX:+UseG1GC -jar server.jar --nogui"
ExecReload=/usr/bin/tmux send-keys -t minecraft:0.0 'say SERVER RELOADING.' C-m 'reload' C-m
ExecStop=/usr/bin/tmux send-keys -t minecraft:0.0 'say SERVER SHUTTING DOWN. Saving map...' C-m 'save-all' C-m 'stop' C-m
ExecStop=/bin/sleep 2
[Install]
WantedBy=multi-user.target
Additional info:
- as tmux is running under the specified user running tmux ls as root will not list the session, su into minecraft and then use tmux standard commands ( like ls, attatch, etc)