Skip to content

Instantly share code, notes, and snippets.

Last active December 12, 2022 09:18
Show Gist options
  • Save JamesTheAwesomeDude/7a582af73448e330fc7bcfb5efef68d1 to your computer and use it in GitHub Desktop.
Save JamesTheAwesomeDude/7a582af73448e330fc7bcfb5efef68d1 to your computer and use it in GitHub Desktop.
systemd user-unit file for Minecraft server
# ~/.config/systemd/user/minecraft@.service
# Setup:
# loginctl enable-linger "${USER}"
# systemctl --user daemon-reload
# ln -sfv ../../jars/paper.jar /var/minecraft/servers/survival/server.jar
# systemctl --user enable --now minecraft@"$(systemd-escape /var/minecraft/servers/survival)".service
Description=Minecraft Server (%I)
ExecStart=java -jar server.jar
SuccessExitStatus=INT SIGINT 130
#!/usr/bin/env python3
import urllib3, json, sys, logging, os, errno, hashlib
# you might need to run one of these first:
# apt install python3-urllib3
# python3 -m pip install urllib3
# python3 -m pip install --user urllib3
# dnf install python3-urllib3
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
http = urllib3.PoolManager(headers={'user-agent': '""/2022.03.15'})
def getjson(url, *, suppress_error=False, http=http):
r = http.request('GET', url)
data = json.load(r)
if not suppress_error:
if ('error' in data) and (data['error'] is not None):
raise RuntimeError(data['error'])
if r.status != 200:
raise urllib3.exceptions.HTTPError(r.status)
return data
if len(sys.argv) > 1:
version = sys.argv[-1]
version = getjson("")['versions'][-1]
# this does NOT need to be refactored, I think; it's already sorted:
logging.debug(f"version = {version}")
build = getjson(f"{version}")['builds'][-1]
#TODO: does this need to be refactored? It's unclear whether being-sorted is part of the promise:
logging.debug(f"build = {build}")
application = getjson(f"{version}/builds/{build}")['downloads']['application']
fname = application['name']
sha256sum_good = application['sha256']
logging.debug(f"sha256 = {sha256sum_good}")
if os.path.exists(fname) and '-f' not in sys.argv:
raise FileExistsError(errno.EEXIST, os.strerror(errno.EEXIST), fname)"Downloading version {version}, build #{build} (to {fname})...")
with open(fname + '.part', 'wb') as f,\
http.request('GET', f"{version}/builds/{build}/downloads/{fname}", preload_content=False) as r:
hash = hashlib.sha256()
for chunk in
sha256sum = hash.hexdigest()
if sha256sum == sha256sum_good:"SHA256 OK: {fname} [{sha256sum}]")
os.replace(fname + '.part', fname)
print("You should run:\n\tln -svf %s %s\n\tsystemctl --user restart \"minecraft@$(systemd-escape \"${PWD}\").service\"" % (repr(fname), repr('server.jar')))
raise AssertionError(f"File is corrupted.\nexpected: {sha256sum_good}\ngot: {sha256sum}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment