Use case · Game server

Necesse dedicated server on Linux: SteamCMD, launch flags and UDP 14159

A Necesse dedicated server is Fair Games' free SteamCMD tool, app 1169370, downloaded with an anonymous login and started on Linux by StartServer-nogui.sh, which runs the Java runtime shipped inside the install folder. It listens on UDP 14159 by default, keeps server.cfg and the world saves under ~/.config/Necesse, and takes -world, -port, -slots and a dozen other launch flags. Below: the install under its own account, a systemd unit that saves the world when it stops, backups, updates and the machine to run it on.

See the game servers

What the server needs from the machine

Fair Games publishes no hardware figures for the dedicated server itself. The Steam store lists the game's Linux requirements: a 64-bit OS, an Intel Core i3-4160 or AMD FX-4350 with 4 GB of RAM as the minimum, an i5-4590 or Ryzen 3 2200G quad core with 8 GB as recommended, and 500 MB of disk. Those lines describe the client, which also renders the game.

ItemFigureWhere it comes from
Player slots1 to 250Official wiki, server setup
Default portUDP 14159Official wiki, port forwarding
RAM4 GB min, 8 GB rec.Steam store, game client
Disk500 MBSteam store, game client
RuntimeJava, shipped in the server's jre folderWiki process listing; Java 17 OpenJDK since v0.21.27

Our working rule, not Fair Games': take the recommended client line as the floor for a headless server, then measure. The v1.0.3 notes say memory allocation on dedicated servers was improved significantly and that -XX:+UseG1GC and -XX:+ExplicitGCInvokesConcurrent were added to the server's launch scripts. The admin command /performance records server performance into a file, per the wiki's command list.

Installing SteamCMD and the server

The official wiki's Linux page creates a necesse user, installs SteamCMD's 32-bit library and pulls app 1169370 from a SteamCMD runscript. The block below follows it on Ubuntu 24.04 with changes of ours: the firewall comes first (IPv6 rules on, SSH allowed, enabled, then the game port); only lib32gcc-s1, Valve's package name for current Ubuntu, where the wiki also tries the older lib32gcc1; SteamCMD in its own folder; comments dropped from the runscript; and one install path, /home/necesse/server. The wiki's script installs into the home directory but starts the server from ~/Steam/steamapps/common, so we settled on a single location.

sudo sed -i 's/^IPV6=.*/IPV6=yes/' /etc/default/ufw &&
sudo ufw allow OpenSSH &&
sudo ufw --force enable &&
sudo ufw allow 14159/udp &&
sudo dpkg --add-architecture i386 &&
sudo apt update && sudo apt install -y lib32gcc-s1 curl &&
{ id -u necesse > /dev/null 2>&1 || sudo useradd --create-home --shell /bin/bash necesse; } &&
sudo chmod 700 /home/necesse &&
sudo -u necesse bash -o pipefail -c 'cd /home/necesse && mkdir -p steamcmd && curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxf - -C steamcmd' &&
printf '%s\n' '@ShutdownOnFailedCommand 1' '@NoPromptForPassword 1' 'force_install_dir /home/necesse/server' 'login anonymous' 'app_update 1169370 validate' 'quit' | sudo -u necesse tee /home/necesse/update_necesse.txt > /dev/null &&
sudo -u necesse bash -c 'cd /home/necesse && steamcmd/steamcmd.sh +runscript /home/necesse/update_necesse.txt'
sudo test -x /home/necesse/server/StartServer-nogui.sh && echo installed

Valve's SteamCMD page asks for force_install_dir before the login, as here. No Java package is needed: the wiki's process listing shows StartServer-nogui.sh launching ./jre/bin/java -jar Server.jar -nogui from the install folder. Every line through the SteamCMD run is chained to the previous one with &&, and a re-run skips useradd when the account exists. The final test stands alone: if it does not print installed, find the first error in the output, fix it, and paste the block again.

Creating the world once, by hand

Start the server interactively one time as the service user: sudo -u necesse bash -c 'cd /home/necesse/server && ./StartServer-nogui.sh'. Without -world it asks its questions in the terminal. The wiki's walk-through lists them: world name (we use MyWorld below), custom options, port (14159), player slots (1-250), a server password (blank for none), spawn island, seed and whether to spawn the guide house. Once it is running, type stop, which the wiki's command list describes as save and stop. The world is written to ~/.config/Necesse/saves/MyWorld.zip.

Set the password at that prompt instead of passing -password. A flag sits in the unit file and shows in ps to every local user; a prompt answer does neither. The wiki's parameter table says any flag not given is loaded from the server settings file, and the v0.21.1 notes fixed the server ignoring its saved password on load; our reading of the two is that the password is kept in that file, inside a home directory set to mode 700 above.

Leave -owner out too. The wiki says anyone connecting with that name gets owner permissions. Grant the role once from the console instead, with permissions set YourName owner, which takes a name or an authentication.

systemd: update on start, save on stop

The wiki's unit runs StartServer-nogui.sh -world and stops there. Its Docker notes add that the server does not save on SIGTERM, which is what systemctl stop sends, so progress since the last autosave would be lost. Our version gives the server a named pipe, /home/necesse/console, as its input: ExecStop types stop into it and waits for the process to exit, and the same pipe is your console. SteamCMD updates the server before each start.

sudo test -x /home/necesse/server/StartServer-nogui.sh && sudo -u necesse tee /home/necesse/run-necesse.sh > /dev/null <<'EOF'
cd /home/necesse/server || exit 1
rm -f /home/necesse/console
mkfifo -m 600 /home/necesse/console || exit 1
exec ./StartServer-nogui.sh -world MyWorld -port 14159 -slots 10 -pausewhenempty 1 <> /home/necesse/console
EOF
sudo test -s /home/necesse/run-necesse.sh && sudo tee /etc/systemd/system/necesse.service > /dev/null <<'EOF'
[Unit]
Description=Necesse dedicated server
Wants=network-online.target
After=network-online.target

[Service]
User=necesse
ExecStartPre=-/home/necesse/steamcmd/steamcmd.sh +runscript /home/necesse/update_necesse.txt
ExecStart=/bin/bash /home/necesse/run-necesse.sh
ExecStop=/bin/bash -c '[ -n "$MAINPID" ] || exit 0; echo stop > /home/necesse/console; while kill -0 "$MAINPID" 2>/dev/null; do sleep 1; done'
TimeoutStartSec=1800
TimeoutStopSec=120
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
  • The - before ExecStartPre lets the server start when SteamCMD exits with an error. It does not cover a hung update: TimeoutStartSec=1800, our margin, cuts that off and the start fails, after which Restart=always tries again.
  • ExecStop writes stop only while the main process is alive, then waits for it. TimeoutStopSec=120 is our margin before systemd falls back to SIGTERM.
  • Restart=always is our choice. It also brings the server back after an owner types /stop in chat, so take it down with systemctl stop.
  • -pausewhenempty 1 freezes the world while nobody is online. The wiki's table gives 0 as the default, the v0.21.27 notes say dedicated servers pause when empty by default, so we set it explicitly; use 0 to keep the world running.

Start it only when the firewall is on and the world exists: sudo ufw status | grep -q 'Status: active' && sudo test -e /home/necesse/.config/Necesse/saves/MyWorld.zip && sudo systemctl enable --now necesse. Send console commands with sudo -u necesse sh -c 'echo save > /home/necesse/console' and read the replies in journalctl -u necesse -f.

Launch flags and settings files

FlagEffect, per the wiki's parameter table
-world MyWorldLoads that world instead of asking
-port 14159Port to host on
-slots 10Number of player slots
-passwordServer password; on a command line it shows in ps
-owner NameOwner permissions for anyone joining with that name
-pausewhenempty 1 or 0Pause the world with no players
-noguiTerminal instead of the GUI; the nogui script already passes it
-settings fileLoad server settings from that file
-localdirKeep cache, logs and saves in the folder the server runs from
-datadir pathThe same, at a path you choose
-ip addressBind the server to one address

On Linux the wiki places server.cfg in ~/.config/Necesse/cfg, the logs in ~/.config/Necesse/logs, and worldSettings.cfg inside the world's zip in ~/.config/Necesse/saves. It says to stop the server before editing any of them. Most world rules need no unzipping: owners and admins change them in game with /difficulty, /deathpenalty, /raids and /settings. Keeping data in the default place rather than using -localdir is our choice: the world stays apart from the folder SteamCMD rewrites.

Backups, restores and updates

  1. Make a private folder once: sudo install -d -m 700 /root/necesse-backups.
  2. Stop (which saves), archive the data folder plus the script, runscript and unit, check the archive, and start again: `F=/root/necesse-backups/necesse-$(date +%F).tgz; sudo systemctl stop necesse && sudo tar -czf "$F" -C / home/necesse/.config/Necesse home/necesse/run-necesse.sh home/necesse/update_necesse.txt etc/systemd/system/necesse.service && sudo tar -tzf "$F" > /dev/null && echo ok; sudo systemctl start necesse`. No ok, no backup.
  3. Copy the archive off the machine with scp or plain rsync -a. An archive that never leaves the server dies with its drives.
  4. To restore, set F to the archive you chose, for example F=/root/necesse-backups/necesse-DATE.tgz with its date. If Necesse.before-restore is left over from an earlier restore, move or delete it first. Then stop the server, check the archive, move the current data aside rather than deleting it, unpack, and confirm the world came back: `sudo systemctl stop necesse && sudo test -s "$F" && sudo tar -tzf "$F" > /dev/null && sudo test ! -e /home/necesse/.config/Necesse.before-restore && sudo mv /home/necesse/.config/Necesse /home/necesse/.config/Necesse.before-restore && sudo tar -xzf "$F" -C / home/necesse/.config/Necesse && sudo test -e /home/necesse/.config/Necesse/saves/MyWorld.zip && sudo chown -R necesse:necesse /home/necesse/.config/Necesse && echo restored`. Without restored, do not start the service; read the error first.
  5. Start it with sudo systemctl start necesse and join. If Necesse.before-restore was never created, the restore stopped before touching anything: just start the service. If the world is wrong, or the restore failed after the move, roll back to the set-aside data (this also works when the unpack left no Necesse folder): `sudo systemctl stop necesse && sudo test -d /home/necesse/.config/Necesse.before-restore && sudo test ! -e /home/necesse/.config/Necesse.failed-restore && { ! sudo test -e /home/necesse/.config/Necesse || sudo mv /home/necesse/.config/Necesse /home/necesse/.config/Necesse.failed-restore; } && sudo mv /home/necesse/.config/Necesse.before-restore /home/necesse/.config/Necesse && sudo systemctl start necesse`. Delete the set-aside folder once you are satisfied.

Updates arrive with every start through ExecStartPre, so sudo systemctl restart necesse after a patch is enough. That matters: Fair Games' v1.3.3 notes say the patch requires servers and hosts to update. To hold a version, put a # before ExecStartPre in the unit, then sudo systemctl daemon-reload so the change takes.

Which of our machines fit

Any server in our game server range gives the Java process every core and all the memory, with root and an unmetered port: 1 Gbps on 10 of the 18 configurable lines and 500 Mbps on the other 8, with one IPv4 and IPv6 added at checkout at no charge. Nothing counts the traffic. Ubuntu installs in one click; other distributions are on our Linux servers page.

Pick a rack server or blade: each has an out-of-band controller (HPE iLO, Dell iDRAC or a Supermicro BMC) with a browser console once you add a console login, which is how you undo a bad firewall rule. Among Moonshot cartridges only the m510 and m710x have a console; the rest have power control. Fair Games' download page lists Windows64, MacOS and Linux64 builds, and the Steam store says M-chip Macs are not supported. Our inference from both, not a Fair Games statement: the bundled runtime is x86-64, so choose an x86 line, not an ARM one.

The machines and the network are ours, AS19624, in New York, Miami, San Francisco, Amsterdam and Bucharest; the data center page has a test IP to ping in each city. A ready, racked server is live about 30 minutes once payment is approved; builds to order take 4-24 hours.

When a whole machine is the wrong answer

The wiki is blunt about it: the one advantage of a dedicated server is that the world is always online. When everyone logs on together and the world's owner is always among them, hosting from inside the game does the job. The wiki also has a Docker recipe and lists community-maintained images; its SIGTERM warning applies to docker stop as well. For another sandbox world on the same pattern, see our Terraria server notes.

Questions

What is the SteamCMD app ID for the Necesse server?

1169370, the Necesse Dedicated Server tool, installed with login anonymous. The server machine needs no copy of the game; players need the game, app 1169040, to connect. Fair Games also offers the server files as direct downloads on necessegame.com.

Which port does the server use?

UDP 14159 by default, and that is the only one the wiki asks you to open. Change it with -port and open the new number in ufw instead. Where several IPv4 addresses are routed to the box, -ip pins the server to one of them.

Do I need to install Java?

No. The server ships its own runtime in a jre folder, and the wiki's process listing shows the start script running ./jre/bin/java -jar Server.jar -nogui. Fair Games' v0.21.27 notes moved the game to Java 17 OpenJDK.

Where does the server keep the world?

In ~/.config/Necesse/saves of the user running it, one zip per world, with server.cfg in the cfg folder beside it. -datadir or -localdir move all of it. Back up that whole folder.

How do I become owner on my own server?

From the server console, permissions set with your name and the role, for example owner. -owner does the same for anyone who joins under that name, which is why we avoid it. In game, /mypermissions shows your level.

Can one machine run two worlds?

Yes, as two instances: a second install folder and runscript, its own -datadir, its own -port (for example 14160, opened in ufw), and its own pipe and unit. Size memory for both.

Give the world its own machine

Pick the city nearest your players, install Ubuntu and run the steps above on a server with no other tenant.

See the game servers

Related on Server Room

Other use cases