Sueta
SP

Spigot-systemd

1.0.0

Better integration of spigot with systemd

·Plugin

Systemd-integration for Spigot
Running your server as a systemd service is, of course, already possible without any modifications. However, there are several advanced features of systemd that are useful when running a Minecraft server, but require some alterations to the server software. This plugin aims to enable some of these features.

Current Features
Startup notification
With this plugin, the server will notify systemd of a succesful startup. You can start Spigot as Type=notify and systemd will treat spigot as "activating" until the server is ready to accept players.
The server is considered "running" when all the loaded plugins have been activated and at least one world has been initialized.

Status message
The plugin will send status messages to systemd, which will be displayed by systemctl status.
They are simple "I am ready" messages at the moment, more helpful ones might follow (I am thinking about player counts).

What can you do with it? (socket activation)
The main reason why this plugin exists is on-demand startup of Spigot. In the Linux world there exists the term "socket activation". This describes the idea of dynamically starting a server when the first client connects to it. Socket activation with systemd usually works like this:

  1. systemd opens a (TCP/UDP/Unix/...)-socket and waits for incoming connections.
  2. When packets arrive on that socket, systemd starts the responsible service, passing the socket to the starting service.
  3. The service starts up, and accepts the incoming connections on the socket.

This method does not work with Spigot, because Spigot opens it's own tcp sockets and is not able to recieve sockets passed in by systemd (this would be a difficult thing to do in Java).
However, there exists a small proxy program systemd-socket-proxyd, which will take the sockets passed in by systemd and forward the connections to Spigots tcp socket.
But, if you do this with an unmodified Spigot (or vanilla Mineraft) server, systemd will consider Spigot to be ready immediately after starting the Spigot process. Then the proxy will forward the connection before Spigot is ready and the connection will be refused.
So when the first player connects, the server will start, but the player will be shown an error and has to reconnect manually (at which point they will be able to join).
Also, the proxy will obscure IPs (maybe interfering with online-mode?), and whenever a player with your server in ther serverlist open up their Minecraft client, they will "ping" your server which will cause Spigot to start, even if the player does not actually want to join.
These latter problems can be solved by putting BungeeCord in front of your actual Server(s), and for the readiness problem this plugin exists.

Using BungeeCord, the proxy, this plugin, and Type=notify, the process now looks like this:

  1. BungeeCord opens the TCP socket facing outside, systemd opens TCP sockets on loopback.
  2. A player connects to BungeeCord, Bungee holds the connection and connects to the socket opened by systemd.
  3. systemd receives the connection from Bungee and starts Spigot.
  4. Spigot starts and (with this plugin) notifies systemd when ready.
  5. systemd now starts systemd-socket-proxyd and passes in the socket (and thus the connection from Bungee).
  6. systemd-socket-proxy proxies the connection from Bungee to Spigot.
  7. Spigot is already ready, accepts the connection.
  8. Bungee is now connected to Spigot and in turn connects the player.

Here are a few example service and socket files for this setup:

configuration files

[email protected]
Instanced service unit to start different installations of Spigot.

[Unit]
Description=Minecraft Server instance %i
After=network.target
RequiresMountsFor=/srv/spigot/%i

[Service]
Type=notify
User=spigot
WorkingDirectory=/srv/spigot/%i
ExecStart=/usr/bin/java -Xmx1G -XX:+UseConcMarkSweepGC -jar /srv/spigot/%i/spigot.jar --noconsole
SuccessExitStatus=143

ProtectHome=yes
ProtectSystem=full
PrivateDevices=yes
PrivateTmp=yes

[email protected]
Instanced service unit for the proxies connecting the systemd-sockets to Spigot.

[Unit]
Description=Socket activation proxy for spigot instance %i
[email protected]%i.service
[email protected]%i.service
[email protected]%i.service
[email protected]
[email protected]

[Service]
EnvironmentFile=/srv/spigot/%i/envfile
# The envfile contains the SPIGOT_PORT

ExecStart=/usr/lib/systemd/systemd-socket-proxyd localhost:${SPIGOT_PORT}
# You might need to replace localhost with 127.0.0.1 if your Spigot does not speak ipv6.

ProtectHome=true
ProtectSystem=full
PrivateTmp=yes
PrivateDevices=yes

[email protected]
The socket units for the spigot-activators.

[Unit]
Description=Socket activation proxy socket for spigot instance %i

[Socket]
BindToDevice=lo

[Install]
WantedBy=sockets.target

override.conf (for [email protected])
Unfortunately we cannot use EnvironmentFile in socket units, so unless we name the Spigot instances by their TCP ports, we have to override the socket instances and add the specific Spigot ports.

[Socket]
ListenStream=[::]:25580
# This listens on ipv6, which currently requires you to patch Bungee. Of course, you can just listen on ipv4.

bungee.service
Service unit for BungeeCord. Could also be instanced if neccessary.

[Unit]
Description=BungeeCord Minecraft proxy
After=network.target
RequiresMountsFor=/srv/bungee

[Service]
Type=simple
User=spigot
WorkingDirectory=/srv/bungee
ExecStart=/usr/bin/java -Xmx512M -jar BungeeCord.jar --noconsole
SuccessExitStatus=143

ProtectHome=yes
ProtectSystem=full
PrivateDevices=yes
PrivateTmp=yes

[Install]
WantedBy=multi-user.target

License & Credits
Spigot-systemd is using the SDNotify library (to talk with systemd), which in turn is using JNA (to connect to the unix socket used to talk with systemd).
SDNotify is licensed under LGPL 2.1.
JNA is dual-licensed under LGPL 2.1 and the Apache Software License.
Spigot-systemd is licensed under AGPLv3. This means, if you are a professional hoster and sell access to servers using this plugin, you have to provide your customers (and players) with the source of this plugin (especially if you modified it).

Similar projects

Plugin →