Skip to content

Instantly share code, notes, and snippets.

@justincjahn
Last active January 16, 2024 20:15
Show Gist options
  • Save justincjahn/4fe65b552b0622662420928cc8ffc7c0 to your computer and use it in GitHub Desktop.
Save justincjahn/4fe65b552b0622662420928cc8ffc7c0 to your computer and use it in GitHub Desktop.
Minecraft server(s) using systemd and screen.

Install

# Install dependencies
sudo yum install -y java-1.8.0-openjdk screen

# Create a new unprivileged user for minecraft
useradd -r -m -d /opt/minecraft minecraft

# Create the directory that will house our minecraft instances
sudo su --shell /bin/bash minecraft
mkdir instances
exit

# Copy the minecraft@.service file into the correct place.
sudo vi /etc/systemd/system/minecraft@.service

# Reload systemd units
sudo systemctl daemon-reload

Provision a new server

# Sudo into the minecraft user's shell
sudo su --shell /bin/bash minecraft

# Move into the instances directory
cd instances

# Create a new folder to house your instance
mkdir server1

# Install your minecraft instance, and make sure there is a minecraft_server.jar file.
# If you use Forge servers, you can use the following:
ln -s forge*.jar minecraft_server.jar

# Start and enable (start after boot) the server.
sudo systemctl start minecraft@server1
sudo systemctl enable minecraft@server1
[Unit]
Description=Minecraft Server: %i
After=network.target
[Service]
WorkingDirectory=/opt/minecraft/instances/%i
User=minecraft
Group=minecraft
Restart=always
ExecStart=/usr/bin/screen -DmS mc-%i /usr/bin/java -Xmx2G -jar minecraft_server.jar nogui
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 15 SECONDS..."\015'
ExecStop=/bin/sleep 5
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 10 SECONDS..."\015'
ExecStop=/bin/sleep 5
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 5 SECONDS..."\015'
ExecStop=/bin/sleep 5
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "save-all"\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "stop"\015'
[Install]
WantedBy=multi-user.target
@SirKratosAurion
Copy link

SirKratosAurion commented Sep 11, 2018

To view the console su to minecraft with:

sudo su minecraft

then

screen -R mc-server1

@tehmessiah75
Copy link

It keeps asking me for minecraft's password to run these:

Start and enable (start after boot) the server.

sudo systemctl start minecraft@server1
sudo systemctl enable minecraft@server1

@MECU
Copy link

MECU commented Mar 13, 2019

It keeps asking me for minecraft's password to run these:

Start and enable (start after boot) the server.

sudo systemctl start minecraft@server1
sudo systemctl enable minecraft@server1

sudo is part of the linux system. It's asking for the sudo password. This isn't related to minecraft. https://en.wikipedia.org/wiki/Sudo

@radjah
Copy link

radjah commented Apr 11, 2019

To view the console su to minecraft

sudo -u minecraft screen -R mc-server1

man sudo

@lucasporlier
Copy link

The user should be named steve (y)

@aklinker1
Copy link

aklinker1 commented Feb 8, 2020

I was having lots of permission errors, so I wrote a script to set this all of this up and create instances automatically.

Script

You can put this script anywhere.

#!/bin/bash
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root"
   exit 1
fi

# Create user if needed
id -u minecraft &> /dev/null
if [ $? -eq 1 ]; then
    echo "Initial setup"
    echo "- Creating 'minecraft' user"
    sudo useradd -r -m -d /opt/minecraft minecraft
    sudo chown -R minecraft:minecraft /opt/minecraft
    echo "- Create systemd service"
    echo "[Unit]
Description=Minecraft Server: %i
After=network.target

[Service]
WorkingDirectory=/opt/minecraft/instances/%i

User=minecraft
Group=minecraft

Restart=always
RestartSec=1s

ExecStart=/usr/bin/screen -DmS mc-%i /usr/bin/java -Xms1024M -Xmx1900M -jar minecraft_server.jar nogui

ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff \"say SERVER SHUTTING DOWN IN 15 SECONDS...\"\015'
ExecStop=/bin/sleep 5
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff \"say SERVER SHUTTING DOWN IN 10 SECONDS...\"\015'
ExecStop=/bin/sleep 5
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff \"say SERVER SHUTTING DOWN IN 5 SECONDS...\"\015'
ExecStop=/bin/sleep 5
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff \"save-all\"\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff \"stop\"\015'

[Install]
WantedBy=multi-user.target" > /etc/systemd/system/minecraft@.service
fi

# Setup folders if needed
cd /opt/minecraft
[ -d server-images ] || mkdir server-images
[ -d instances ] || mkdir instances

# Get server info
echo -en "\nEnter the new server's id (snake_case): "
read SERVER_ID
while [ -d "instances/$SERVER_ID" ]; do
    echo -en "'instances/$SERVER_ID' already exists.\nTry Again: "
    read SERVER_ID
done

echo -e "\nExisting server images:"
ls server-images
echo -en "\nEnter the image you want to use or ? to download a new one: "
read IMAGE_NAME

while [ ! -f "server-images/$IMAGE_NAME" ] && [ "$IMAGE_NAME" != "?" ]; do
    echo -en "'server-images/$IMAGE_NAME' does not exist.\nTry Again: "
    read IMAGE_NAME
done

# Donwload new image
if [ "$IMAGE_NAME" = "?" ]; then
    echo -n "Enter download URL: "
    read DOWNLOAD_URL
    echo -n "Enter the image name (example: 'vanilla-1.15.2.jar'): "
    read IMAGE_NAME
    echo "$DOWNLOAD_URL > $IMAGE_NAME"
    echo -en "Downloading server image... "
    curl "$DOWNLOAD_URL" --output "server-images/$IMAGE_NAME"
    echo "Done!"
fi

# Accept EULA
echo -en "\nBy continuing, you accept the following EULA (https://account.mojang.com/documents/minecraft_eula)\n[Press enter to accept]"
read ACCEPT_EULA

# Generate instance
echo -en "\nCreating 'instances/$SERVER_ID'... "
mkdir "instances/$SERVER_ID"
cp "server-images/$IMAGE_NAME" "instances/$SERVER_ID/$IMAGE_NAME"
cd "instances/$SERVER_ID"
echo "eula=true" > eula.txt
ln -s "$IMAGE_NAME" minecraft_server.jar
# POINT THE NEXT LINE TO AN EXISTING INSTANCE
# If you don't have an existing instance, it will log an error and minecraft will generate this file for you.
cp "../default_instance/server.properties" server.properties 
sudo chown -R minecraft:minecraft .
cd /opt/minecraft
echo "Done!"

# Spinning up for the first time
echo -en "\nSpinning up to generate necessary server files (this will take ~2 minutes)... "
sudo systemctl start "minecraft@$SERVER_ID"
sleep 2m # lol
sudo systemctl stop "minecraft@$SERVER_ID"
sudo chown -R minecraft:minecraft "instances/$SERVER_ID"
echo "Done!"

# Helpful stuff
echo -e "\nYour server is ready to go! Helpful commands:"
echo "------"
echo "  # Start it up"
echo "  sudo systemctl start minecraft@$SERVER_ID"
echo "  sudo systemctl stop minecraft@$SERVER_ID"
echo "  sudo systemctl restart minecraft@$SERVER_ID"
echo "  sudo systemctl reload minecraft@$SERVER_ID"
echo ""
echo "  # If you want to start this server on startup"
echo "  sudo systemctl enable minecraft@$SERVER_ID"
echo "  # If you want to undo enabling it"
echo "  sudo systemctl disable minecraft@$SERVER_ID"
echo "------"
echo ""

@magicus
Copy link

magicus commented Feb 29, 2020

@aklinker1 Thank you for the script! The minecraft user part seemed to work fine. FYI, there's a bug where you presuppose an existing 'survival' instance:'

cp "../survival/server.properties" server.properties

@magicus
Copy link

magicus commented Feb 29, 2020

I had problems running screen using sudo -u. I've used the following template to create scripts for connecting to my instances:

#!/bin/bash
/usr/bin/sudo -u minecraft script -q -c 'screen -R mc-INSTANCE' /dev/null

@aklinker1
Copy link

@magicus Hmm, I forgot I did that. Shouldn't make a difference, it just won't copy and minecraft will generate one for you. I'll add a comment on that line telling people to change it if needed

@lukewhrit
Copy link

Are there any issues with using this on Ubuntu server?

@aklinker1
Copy link

That's what I use!

@prydin
Copy link

prydin commented May 20, 2020

Thanks! This was just what I was looking for!

@ryan77627
Copy link

Hey, love the example service. I would suggest one edit. As it stands, once the last command is run when stopping the service ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "stop"\015', systemd will consider the process completed and kill any processes remaining. This is bad since it kills screen the moment after it's told to type stop in the MC console. This means the server never has a chance to properly stop, since it is immediately killed along with screen.

I would recommend adding KillMode=none to somewhere under the [Service] section to stop systemd from killing anything by itself so the server has a chance to gracefully shutdown. Screen will still terminate itself when java exits

My only concern is systemd will consider the process ended after sending the stop command though, so linux may still shutdown before the server is shutdown, but I'm not too concerned about that because I haven;t done a lot of testing in that case yet

@Nullcaller
Copy link

Thanks, @ryan77627! KillMode=none is absolutely necessary for using screen with systemd, you've solved my issue with it.

@lukasfink1
Copy link

lukasfink1 commented Oct 31, 2020

I would recommend adding KillMode=none to somewhere under the [Service] section to stop systemd from killing anything by itself so the server has a chance to gracefully shutdown. Screen will still terminate itself when java exits

My only concern is systemd will consider the process ended after sending the stop command though, so linux may still shutdown before the server is shutdown, but I'm not too concerned about that because I haven;t done a lot of testing in that case yet

My approach is to use KillSignal=SIGCONT instead of KillMode=none. The advantage is that it’ll wait for the server to exit at system shutdown but kill the server with SIGKILL if the server didn’t stop after a timeout (by default 90 s).

Edit: grammar

@JamesAnunda
Copy link

JamesAnunda commented Nov 1, 2020

To view the console su to minecraft with:

sudo su minecraft

then

screen -R mc-server1

you have no idea how long I been looking for this. Digital Ocean seriously needs to update their documentation on this.

@katian
Copy link

katian commented Nov 7, 2020

what do you think about :
ExecStop=/bin/bash -c "while ps -p $MAINPID > /dev/null; do /bin/sleep 1; done"

@cbytestech
Copy link

How does this handle the server.Properties file? If setting this up for each user to have their own, wouldn't they each need their own copy?

@njaksch
Copy link

njaksch commented Jul 6, 2021

So I copied your service unit, modified it to fit my server and added recommendations from comments.
This is my first systemd unit and if I start it the ExecStop commands all immediatly execute?

[Unit]
Description=Minecraft Forge Server
After=network.target

[Service]
WorkingDirectory=/home/niclas/forge

User=niclas
Group=niclas

Restart=always
KillMode=none

ExecStart=/usr/bin/screen -dmS forge /usr/lib/jvm/java-11-openjdk-amd64/bin/java -Xms1G -Xmx8G -jar forge-1.16.5-36.1.32.jar nogui

ExecStop=/usr/bin/screen -p 0 -S forge -X eval 'stuff "say SERVER SHUTTING DOWN IN 5 SECONDS..."\015'
ExecStop=/bin/sleep 5
ExecStop=/usr/bin/screen -p 0 -S forge -X eval 'stuff "save-all"\015'
ExecStop=/usr/bin/screen -p 0 -S forge -X eval 'stuff "stop"\015'
ExecStop=/bin/sleep 10

[Install]
WantedBy=multi-user.target

@MaxSMoke-KillSZ-Official
Copy link

MaxSMoke-KillSZ-Official commented Jul 26, 2021

What is or who is a "stuff"?

@Maxgamerboy1
Copy link

@MaxSMoke-KillSZ-Official I was wondering what this did too. It's a screen command for inputting text or keyboard commands to a running screen session.
https://www.gnu.org/software/screen/manual/screen.html#:~:text=Stuff%20a%20string%20in%20the%20input%20buffer%20of%20a%20window
\015 is the ASCII keycode for a carriage return, the Enter key

@Aviatorpaal
Copy link

Aviatorpaal commented Sep 8, 2021

I had to add "Type=forking" to the file for systemctl to interpret it correctly, and not start/stop-loop the minecraft@survival.service

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

[Service]
Type=forking
WorkingDirectory=/opt/survival
User=minecraft
Group=minecraft
Restart=always
ExecStart=/usr/bin/screen -dmS mc%i /usr/bin/java -Xmx4G -jar minecraft_server.jar nogui
ExecStop=/usr/bin/screen -p 0 -S mc%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 10 SECONDS..."\015'
ExecStop=/bin/sleep 10
ExecStop=/usr/bin/screen -p 0 -S mc%i -X eval 'stuff "save-all"\015'
ExecStop=/usr/bin/screen -p 0 -S mc%i -X eval 'stuff "stop"\015'
ExecStop=/bin/sleep 25

[Install]
WantedBy=multi-user.target

@GwynethLlewelyn
Copy link

I'm using systemd + screen to launch a different application (similar in concept to launching a Minecraft server) so I tried to adapt things to my own purposes. This was not easy, but I've encountered the same issue as @Aviatorpaal and had to use Type=forking as well. There were also some slight differences in the parameters sent to screen, some of them not obvious. Ultimately, I got my own setup working using the skeleton framework suggestion posted on the Unix StackExchange (see point 2.), which worked quite well for me. It should also work fine for Minecraft or any kind of interactive server application that benefits from having a console.

@Fiwi1265
Copy link

Thanks this thread is exactly what I needed.

@Dominik-Gubrynowicz
Copy link

Hi, I have an error: screen[2355]: No screen session found. Any ideas what might be wrong? (Ubuntu 20.04)

@sublok
Copy link

sublok commented Jan 24, 2022

Will this work with 1.18.1 java @user_jvm_args.txt @libraries/net/minecraftforge/forge/1.18.1-39.0.45/unix_args.txt "$@"?

@RAD750
Copy link

RAD750 commented Mar 16, 2022

To view the console su to minecraft with:

sudo su minecraft

then

screen -R mc-server1

Don't use sudo su. Instead, do sudo -u minecraft -s, or directly sudo -u minecraft screen -R mc-server1

Cheers

@mitcherthewitcher
Copy link

This thread helped me out. Thanks 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment