7

I've set up a systemd service to run my Minecraft server. Now, I need it to repeat the start script when the server crashes. Here's my code so far:

#!/bin/bash

while true; do
    cd /home/mcserver/Spigot
    echo Starting Spigot...
    echo 600 > ./restart-info
    java -jar spigot.jar
    echo Server has stopped or crashed, starting again in 5 minutes...
    sleep 300
done

I can actually view the output of spigot.jar using systemctl status spigot, but I also want to control the server console, maybe using screen.

When I try to do this:

screen -S "Spigot" java -jar spigot.jar

I'll get the Must be connected to a terminal error. This command only works in a terminal (not in a script) and I can attach it using screen -r.

Is there any way to "bypass" this screen bug? I already tried to place script /dev/null before the screen command. I don't want to use screen with -d and -m because it'll run in the background and the script will keep restarting my server.

4
  • 1
    Why not use systemds restart feature?
    – Panki
    Jul 13, 2020 at 9:00
  • I'm not sure if restart helps... I want the script to wait until java -jar spigot.jar stops. And I also want to run the jar file in screen so I can reattach to it at anytime.
    – adazem009
    Jul 13, 2020 at 9:03
  • Why do you need to reattach? You can read the output with journalctl. Or do you need to interact with it?
    – Panki
    Jul 13, 2020 at 9:04
  • Yes, I need to interact with it and read the output from systemctl status spigot.service
    – adazem009
    Jul 13, 2020 at 9:05

3 Answers 3

22

I suspect you've stumbled on this blog post which uses screen to solve a problem where your minecraft server stops when you $ java -jar spigot.jar, then close your ssh or putty session. That method seems to have become the cannonical answer as to how to run a minecraft server, even though it isn't necessary.

systemd is a totally different (and better) solution to this problem, circumventing the need for screen. You can achieve everything you've done in your script with systemd service options.


To run a vanilla minecraft server, create /etc/systemd/system/minecraft.service with this content:

[Unit]
Description=Minecraft Server

[Service]
Type=simple
WorkingDirectory=/home/minecraft
ExecStart=java -Xmx1024M -Xms1024M -jar /home/minecraft/server.jar nogui
User=minecraft
Restart=on-failure

[Install]
WantedBy=multi-user.target

Set it to launch automatically after boot with systemctl enable minecraft.

You asked about how to control it:

$ sudo systemctl start minecraft   # Starts the service if it wasn't running
$ sudo systemctl stop minecraft    # Stops the service
$ sudo systemctl restart minecraft # Restarts the service
$ sudo systemctl status minecraft  # Find out how the service is doing
$ sudo journalctl -u minecraft -f  # Monitor the logs

This does everything except give you a means to send commands to the console. To do that, we'll set up a file that the server will listen to where you can write your commands by creating the following systemd units:

/etc/systemd/system/minecraft.socket:

[Unit]
PartOf=minecraft.service

[Socket]
ListenFIFO=%t/minecraft.stdin

and /etc/systemd/system/minecraft.service:

[Unit]
Description=Minecraft Server

[Service]
Type=simple
WorkingDirectory=/home/minecraft
ExecStart=java -Xmx1024M -Xms1024M -jar /home/minecraft/server.jar nogui
User=minecraft
Restart=on-failure
Sockets=minecraft.socket
StandardInput=socket
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Now you can send console commands by echoing stuff into that file:

echo "help" > /run/minecraft.stdin
echo "/stop" > /run/minecraft.stdin

What's also cool is that you can make your own custom sequences of commands and cat the entire file into the console. For example, if you play UHC, you can start a new world, have people log-in, then cat uhc.commands > /run/minecraft.stdin to set the gamerules, spread the players, and start the event.

7
  • 3
    What a fantastic answer! Finally an elegant (and standard) solution to the server's stdin problem!
    – MestreLion
    Oct 27, 2020 at 15:18
  • This solves a major nuisance for me which I spent many hours trying to clear-up. Any way I tried to do the service unit with screen or tmux, while it seemed to shut down OK (the six "All chunks are saved" were there), following the log, I encountered multiple exceptions and stack trace messages from the jline console-handling package at shutdown. When I do it this way, without any multiplexer, the shutdown looks nice and clean. Apr 8, 2021 at 3:34
  • I'm not running Minecraft, but something in the same line, and I was wondering... can I have both stdin and stdout on a systemd socket (possibly two, I guess...) and then naively attach to those two sockets and expect to have an interactive pseudoTTY? :-) Oct 19, 2021 at 15:28
  • 1
    Replying to myself: one possibility of doing that is using a 'helper' command such as screen to do the magic: unix.stackexchange.com/a/454098/102206 Oct 19, 2021 at 17:41
  • @GwynethLlewelyn: Yes that's very possible. Here I used StandardInput=socket, but you can also use StandardOutput=socket
    – Stewart
    Oct 20, 2021 at 6:41
3

I don't want to use screen with -d and -m because it'll run in the background and the script will keep restarting my server.

So use -D instead of -d (note the capital case!)

-D -m This also starts screen in "detached" mode, but doesn't fork a new process. The command exits if the session terminates.

As screen won't fork a new process, it will block while java is running, and exit when the server stops.

As a bonus, if you add -S spigot you can monitor the output (and even send commands!) from any terminal by attaching to that screen

And... since you're using a systemd service anyway (and you should indeed), why are you doing this restart loop in your script? Let systemd handle that for you using Restart=always and RestartSec=5min

3
  • Thanks for your answer. I'll try this today and let you know. :)
    – adazem009
    Oct 1, 2020 at 8:17
  • This is all I need for the server right now. Thanks again!
    – adazem009
    Oct 1, 2020 at 14:18
  • -D was best answer for me.thanks. Aug 27, 2022 at 1:56
0

I've found a solution for this, but I won't be able to view output using systemctl status spigot.

#!/bin/bash

while true; do
    cd /home/mcserver/Spigot
    echo Starting Spigot...
    screen -d -m -S Spigot java -jar spigot.jar
    SCREEN_NAME="Spigot"
    while screen -list | grep -q $SCREEN_NAME
    do
        sleep 1
    done
    echo Server has stopped, starting again in 5 minutes...
    sleep 300
done

This script will wait until the screen session terminates. I can now view the output or interact with the console using screen -r or if I have multiple screen sessions running, I can attach using screen -D -R "Spigot".

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .