Add starbound server

This commit is contained in:
Tristan Daniël Maat 2022-04-23 04:08:45 +01:00
parent e7102adec1
commit cd92ec64c2
Signed by: tlater
GPG key ID: 49670FD774E43268
8 changed files with 253 additions and 6 deletions

View file

@ -6,6 +6,7 @@
./services/minecraft.nix ./services/minecraft.nix
./services/nextcloud.nix ./services/nextcloud.nix
./services/webserver.nix ./services/webserver.nix
./services/starbound.nix
./ids.nix ./ids.nix
]; ];
@ -20,6 +21,9 @@
trustedUsers = [ "@wheel" ]; trustedUsers = [ "@wheel" ];
}; };
nixpkgs.config.allowUnfreePredicate = pkg:
builtins.elem (lib.getName pkg) ["forge-server" "steam-runtime" "steamcmd"];
sops = { sops = {
defaultSopsFile = ../keys/external.yaml; defaultSopsFile = ../keys/external.yaml;
secrets.steam = { }; secrets.steam = { };
@ -34,7 +38,7 @@
useDHCP = false; useDHCP = false;
interfaces.eth0.useDHCP = true; interfaces.eth0.useDHCP = true;
firewall.allowedTCPPorts = [ 80 443 2222 2221 25565 ]; firewall.allowedTCPPorts = [ 80 443 2222 2221 25565 21025 ];
}; };
time.timeZone = "Europe/London"; time.timeZone = "Europe/London";

View file

@ -0,0 +1,50 @@
{
"allowAdminCommands" : true,
"allowAdminCommandsFromAnyone" : false,
"allowAnonymousConnections" : true,
"allowAssetsMismatch" : true,
"anonymousConnectionsAreAdmin" : false,
"bannedIPs" : [],
"bannedUuids" : [],
"checkAssetsDigest" : false,
"clearPlayerFiles" : false,
"clearUniverseFiles" : false,
"clientIPJoinable" : false,
"clientP2PJoinable" : true,
"configurationVersion" : {
"basic" : 2,
"server" : 4
},
"crafting" : {
"filterHaveMaterials" : false
},
"gameServerBind" : "::",
"gameServerPort" : 21025,
"interactiveHighlight" : true,
"inventory" : {
"pickupToActionBar" : true
},
"maxPlayers" : 8,
"maxTeamSize" : 4,
"monochromeLighting" : false,
"playerBackupFileCount" : 3,
"queryServerBind" : "::",
"queryServerPort" : 21025,
"rconServerBind" : "::",
"rconServerPassword" : "",
"rconServerPort" : 21026,
"rconServerTimeout" : 1000,
"runQueryServer" : false,
"runRconServer" : false,
"safeScripts" : true,
"scriptInstructionLimit" : 10000000,
"scriptInstructionMeasureInterval" : 10000,
"scriptProfilingEnabled" : false,
"scriptRecursionLimit" : 100,
"serverFidelity" : "automatic",
"serverName" : "tlater.net",
"serverOverrideAssetsDigest" : null,
"serverUsers" : {
},
"tutorialMessages" : true
}

View file

@ -51,9 +51,6 @@ let
eula = pkgs.writeText "eula.txt" "eula=true"; eula = pkgs.writeText "eula.txt" "eula=true";
in { in {
nixpkgs.config.allowUnfreePredicate = pkg:
builtins.elem (lib.getName pkg) [ "forge-server" ];
users = { users = {
extraUsers.minecraft = { extraUsers.minecraft = {
uid = config.ids.uids.minecraft; uid = config.ids.uids.minecraft;

View file

@ -0,0 +1,110 @@
{
pkgs,
lib,
...
}: let
inherit (lib) concatStringsSep;
in {
systemd.services.starbound = {
description = "Starbound";
after = ["network.target"];
serviceConfig = {
ExecStart = "${pkgs.local.starbound}/bin/launch-starbound ${./configs/starbound.json}";
Type = "simple";
# Credential loading for steam auth (if necessary; prefer
# anonymous login wherever possible).
LoadCredential = "steam:/run/secrets/steam";
# Security settings
DynamicUser = true;
# This is where the StateDirectory ends up
WorkingDirectory = "/var/lib/starbound";
# Creates /var/lib/starbound (or rather, a symlink there to
# /var/lib/private/starbound), and sets it up to be writeable to
# by the dynamic user.
StateDirectory = "starbound";
# Note some settings below are basically tautologous with
# `NoNewPrivileges`, but they all work slightly differently so
# add additional layers in case of bugs.
## THESE SETTINGS ARE A GOOD IDEA BUT THE STEAM CLIENT IS
## REALLY, REALLY BAD, AND FOR SOME REASON I NEED TO USE IT TO
## DOWNLOAD GAME SERVERS AS WELL:
##
# To guarantee the above (only permits 64-bit syscalls, 32-bit
# syscalls can circumvent the above restrictions).
#
# Obviously, if running a 32 bit game server, change this.
# SystemCallArchitectures = "native";
# Game servers shouldn't need to create new namespaces ever.
#
# TODO: Since steam uses namespaces for things *entirely
# unrelated* to installing game servers, we need to allow
# namespace access. Ideally I'd instead do this in an
# ExecStartPre, but alas, this isn't possible because of
# https://github.com/systemd/systemd/issues/19604.
#
# RestrictNamespaces = true;
# Don't need to let the game server see other user accounts
PrivateUsers = true;
# *Probably* not harmful for game servers, which probably don't update dynamically
ProtectHostname = true;
# Yeah, if a game server tries to edit the hardware clock something's fishy
ProtectClock = true;
# Don't let game servers modify kernel settings, duh
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
# Game servers shouldn't use cgroups themselves either
ProtectControlGroups = true;
# Most game servers will never need other socket types
RestrictAddressFamilies = ["AF_UNIX AF_INET AF_INET6"];
# Also a no-brainer, no game server should ever need this
LockPersonality = true;
# Some game servers will probably try to set this, but they
# don't need it. It's only required for audio processing and
# such, which the server end doesn't need to do.
RestrictRealtime = true;
# Don't allow a variety of syscalls that gameservers have no
# business using anyway
SystemCallFilter =
"~"
+ (concatStringsSep " " [
"@clock"
"@cpu-emulation"
"@debug"
"@keyring"
"@memlock"
"@module"
# "@mount" TODO: Consider adding when steamcmd is run in ExecStartPre
"@obsolete"
"@raw-io"
"@reboot"
"@resources"
"@setuid"
"@swap"
]);
# Normally only "read-only", but steamcmd will puke if there is
# no home directory to write to (though the nix package will
# implicitly symlink to the path that we set in its override, so
# no actual files are created, besides a symlink).
ProtectHome = "tmpfs";
# Implied by DynamicUser anyway, but it doesn't hurt to add
# these explicitly, at least for reference.
RemoveIPC = true;
PrivateTmp = true;
PrivateDevices = true;
NoNewPrivileges = true;
RestrictSUIDSGID = true;
ProtectSystem = "strict";
# ProtectHome = "read-only"; # See further up
};
};
}

View file

@ -130,9 +130,26 @@
]) ])
])) ]))
]; ];
shellHook = '' shellHook = let
inherit (pkgs.lib.attrsets) mapAttrsToList;
inherit (pkgs.lib.strings) concatStringsSep;
ports = {
"3022" = "2222";
"3080" = "80";
"3443" = "443";
"3021" = "2221";
"25565" = "25565";
"21025" = "21025"; # Starbound
};
QEMU_NET_OPTS =
concatStringsSep ","
(mapAttrsToList
(host: vm: "hostfwd=::${host}-:${vm}")
ports);
in
''
export QEMU_OPTS="-m 3941 -smp 2 -curses" export QEMU_OPTS="-m 3941 -smp 2 -curses"
export QEMU_NET_OPTS="hostfwd=::3022-:2222,hostfwd=::3080-:80,hostfwd=::3443-:443,hostfwd=::3021-:2221,hostfwd=::25565-:25565" export QEMU_NET_OPTS="${QEMU_NET_OPTS}"
# Work around sudo requiring a full terminal # Work around sudo requiring a full terminal
export NIX_SSHOPTS="-t" export NIX_SSHOPTS="-t"

View file

@ -13,4 +13,7 @@ in {
# Minecraft modpacks # Minecraft modpacks
voor-kia = callPackage ./minecraft/voor-kia.nix { }; voor-kia = callPackage ./minecraft/voor-kia.nix { };
voor-kia-client = callPackage ./minecraft/voor-kia-client.nix { }; voor-kia-client = callPackage ./minecraft/voor-kia-client.nix { };
# Starbound
starbound = callPackage ./starbound { };
} }

View file

@ -0,0 +1,34 @@
{
stdenv,
lib,
makeWrapper,
patchelf,
steamPackages,
replace-secret,
}: let
# Use the directory in which starbound is installed so steamcmd
# doesn't have to be reinstalled constantly (we're using DynamicUser
# with StateDirectory to persist this).
steamcmd = steamPackages.steamcmd.override {
steamRoot = "/var/lib/starbound/.steamcmd";
};
wrapperPath = lib.makeBinPath [patchelf steamcmd replace-secret];
in
stdenv.mkDerivation {
name = "starbound-update-script";
nativeBuildInputs = [makeWrapper];
dontUnpack = true;
patchPhase = ''
interpreter="$(cat $NIX_CC/nix-support/dynamic-linker)"
substitute ${./launch-starbound.sh} launch-starbound --subst-var interpreter
'';
installPhase = ''
mkdir -p $out/bin
cp launch-starbound $out/bin/launch-starbound
chmod +x $out/bin/launch-starbound
'';
postFixup = ''
wrapProgram $out/bin/launch-starbound \
--prefix PATH : "${wrapperPath}"
'';
}

View file

@ -0,0 +1,32 @@
#!/usr/bin/env bash
set -eu
if ! [[ -v STATE_DIRECTORY && -v CREDENTIALS_DIRECTORY ]]; then
echo "Error: Runtime dir or credential not set"
exit 1
fi
# Update the server to the latest version
echo "Updating/installing starbound"
mkdir -p "${STATE_DIRECTORY}/.steamcmd"
steamcmd <<EOF
force_install_dir $STATE_DIRECTORY
login tlater $(cat "$CREDENTIALS_DIRECTORY/steam")
app_update 211820
quit
EOF
echo "Updating config"
if [ -f "$1" ]; then
mkdir -p ./storage
cp "$1" ./storage/starbound_server.config
fi
echo "Running starbound server"
patchelf --set-interpreter '@interpreter@' ./linux/starbound_server
# Must be run from the directory that the binary is in (why do game
# devs do this?)
cd linux
./starbound_server