1

What I intend to do

I'm attempting to make a restart script for my Minecraft server so my friends can use the /restart command in-game because they don't have SSH access to my server to restart Minecraft.


My script

Currently my restart.sh script contains

exec >> zzz.log
exec 2>&1

set -x

sleep 5

exec /etc/init.d/minecraft start


Script break down

The first two lines will redirect standardout and standarderror (as Linux fluent users will already know) into the zzz.log file, this is just so I can capture the output to help me figure what's going on.

set -x is also another part to help me figure what's going on, this will output each line that is executed into zzz.log because the above lines redirect the output to there.

sleep(5) as it suggests will make the script pause for 5 seconds, this is just to ensure Minecraft has had enough time to shutdown.

exec will make the following command /etc/init.d/minecraft start run in a different process. Since I do not know how the script is invoked, I assumed this could be a child process of the Minecraft server and thus if the Minecraft server process dies, the script will too, having it this way should ensure the command is run.


My issue

Now, if the Minecraft server is offline and I execute ./restart.sh the server starts up perfectly fine. When in-game if I type /restart the Minecraft server shuts down like its supposed to, but never re-launches again. Looking at my zzz.log file I can see the problem lays around the exec /etc/init.d/minecraft start command, this line is never successfully executed when Minecraft executes the restart.sh script. Why is this?


init script

I obtained the init script from here. This allows me to start, stop, restart the Minecraft server along with various other commands to control the Minecraft server.

  • 1. You seem to have a script called "/etc/init.d/minecraft". From where did you install it? 2. I don't understand how your "restart.sh" stops minecraft. Can you explain? – PPanther77 Dec 8 '16 at 15:12
  • @PPanther77 I've added the source of the init script to my question. The reason why I only call start is because the Minecraft server shuts down when /restart is called within the game. So it seems redundant to me to stop something that doesn't exist (at least theoretically it wouldn't by that point) which is why I have sleep(5) to ensure it has finished shutting down by the time the rest of the script is run. – PairedPrototype Dec 9 '16 at 16:31
  • What is executing restart.sh? – SevenSidedDie Dec 12 '16 at 5:16
  • Easy fix: /etc/inittab and add your mc process to the respawn list. – dly Dec 12 '16 at 8:38
  • @SevenSidedDie I can only assume it would be the Minecraft server process, since I add the path of the shell script in it's config file. – PairedPrototype Dec 12 '16 at 9:08
1

How I came to this solution

Thanks to @dly's comment, I now have a solution!/etc/inittab doesn't exist on Ubuntu 16.04, but /etc/systemd does which means the solution is a bit different than what it would have been initially.

With a quick read around I was able to find some nice information on systemd unit files. This is probably not the best resource to use since it doesn't tell you if the particular option should be placed under [Unit], [Service] or [Install], but nevertheless, it tells you about the key options needed.


Follow along for users with a similar issue

The following will assume one has completed the install steps for Ahtenus' init script for Minecraft/Bukkit servers (this also works perfectly fine for my Spigot server).

To start, you'll need to run this systemctl enable minecraft.service. Then you'll probably want to edit the unit file that gets created for you, you can do this with systemctl edit --full minecraft.service, this will open a text editor (nano in my case, I didn't get to choose). Here you'll be able to edit the parameters. I configured mine like this:

# Automatically generated by systemd-sysv-generator

[Unit]
Documentation=man:systemd-sysv-generator(8)
SourcePath=/etc/init.d/minecraft
Description=Minecraft server
Before=multi-user.target
Before=multi-user.target
Before=multi-user.target
Before=graphical.target
Before=shutdown.target
After=local-fs.target
After=remote-fs.target
After=network-online.target
Wants=network-online.target
Conflicts=shutdown.target

[Service]
Type=forking
Restart=always
TimeoutSec=1min
RestartSec=5
IgnoreSIGPIPE=no
KillMode=process
RemainAfterExit=no
PIDFile=/home/MyUser/minecraft/minecraft-server.pid
ExecStart=/etc/init.d/minecraft start
ExecStop=/etc/init.d/minecraft stop

[Install]
WantedBy=multi-user.target

Most of this is auto created for you, but there may be a few options you'll want to change and add, so I'll go through a few of the options.

  • SourcePath is the absolute path to the init script.
  • Description fairly self-explanatory.
  • Restart has several options, I choose always so no matter how the process dies, it will 'always' be restarted.
  • TimeoutSec is the timeout for a failed start before it tries to start again.
  • RestartSec is how long it should wait before starting the service again after shutdown.
  • RemainAfterExit whether the service should be considered as active even after it processes has exited.
  • PIDFile the path to a PID file for the main process, this should only contain the PID and will be removed when the process is shutdown, but will never be written to by systemd. The Minecraft init script will create this on startup.
  • ExecStart the comand to run to start the service
  • ExecStop the command to run to kill the service


Testing it works

Now we can test this works, in case the service has already been started, we can create a new process using systemctl restart minecraft even if there wasn't a process for this service, it will create a new one. Then we can use screen to connect to the the Minecraft console screen -r minecraft-server, now we can type a command for the server to stop either stop or restart, these can also be used in-game in the same way (remember to prepend the / when in-game, the console always does this for you). The Minecraft server should now shutdown, and after the RestartSec time specified has elapsed, you should be able to verify the the Minecraft service is running again by either reconnecting to the screen again or using systemctl status minecraft (use q to exit this).


Further reading

I found this page on the Redhat documentation site mildly informative as well. (Link in comments, I don't have enough rep to post 3+ links).

  • Redhat documentation link: https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sect-Managing_Services_with_systemd-Unit_Files.html – PairedPrototype Dec 13 '16 at 9:22
0

In bash exec replaces the current script with the command argument without forking a new process. If restart.sh is being run under a process that goes down, I imagine it would take restart.sh with it.

  • So exec will run it as a child process? – PairedPrototype Dec 12 '16 at 9:11
  • I'm not sure about other shells but the bash documentation is pretty clear that exec creates no new processes when run like this. – Leigh Garbs Dec 12 '16 at 14:07
  • Ah, I see. I was going by the information The exec() family of functions replaces the current process image with a new process image. supplied by man exec. – PairedPrototype Dec 12 '16 at 14:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.