Add dedicated server packaging

This commit is contained in:
Alexander Sellite 2026-08-10 13:56:40 -04:00
commit b9c031dfab
13 changed files with 275 additions and 0 deletions

4
.dockerignore Normal file
View file

@ -0,0 +1,4 @@
.git
.gitignore
packages
dist/SHA256SUMS

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/dist/*
!/dist/.gitkeep
/packages/
/.env

26
Dockerfile Normal file
View file

@ -0,0 +1,26 @@
FROM debian:bookworm-slim
RUN groupadd --system --gid 10001 netfishing \
&& useradd --system --uid 10001 --gid netfishing \
--home-dir /var/lib/netfishing-server netfishing \
&& install -d -o netfishing -g netfishing \
/opt/netfishing-server /var/lib/netfishing-server
COPY --chown=netfishing:netfishing \
dist/NETfishingServer.x86_64 \
dist/NETfishingServer.pck \
/opt/netfishing-server/
COPY --chown=netfishing:netfishing \
config/server.cfg.example /etc/netfishing-server.cfg
RUN chmod 0555 /opt/netfishing-server/NETfishingServer.x86_64 \
&& chmod 0444 /opt/netfishing-server/NETfishingServer.pck \
/etc/netfishing-server.cfg
USER 10001:10001
WORKDIR /opt/netfishing-server
VOLUME ["/var/lib/netfishing-server"]
EXPOSE 7777/udp
ENTRYPOINT ["/opt/netfishing-server/NETfishingServer.x86_64"]
CMD ["--", "--config=/etc/netfishing-server.cfg"]

80
README.md Normal file
View file

@ -0,0 +1,80 @@
# NETfishing Dedicated Server
This repository packages the headless NETfishing server produced by the main
game project. Gameplay and networking code remain in the `netfishing`
repository so clients and servers use the same protocol implementation.
## Stage a build
Export the `Linux Dedicated Server` preset from the game project, then stage
its executable and PCK:
```sh
./scripts/stage-build.sh ../netfishing/builds/v0.6.4-alpha/server-linux-x86_64
```
The staged binaries under `dist/` are release inputs and are intentionally not
tracked by Git.
Create a deterministic native archive after staging:
```sh
./scripts/package-native.sh 0.6.4-alpha
```
## Run natively
Copy `dist/NETfishingServer.x86_64` and `dist/NETfishingServer.pck` into the
same directory, make the executable runnable, and start it with a persistent
data directory:
```sh
./NETfishingServer.x86_64 \
-- \
--config=/etc/netfishing-server.cfg \
--data-dir=/var/lib/netfishing-server
```
Copy `config/server.cfg.example` to `/etc/netfishing-server.cfg` and adjust the
room name, UDP port, player limit, and public-listing preference. Forward the
configured UDP port through the host firewall and router when accepting
Internet players.
The data directory contains the server identity and moderation state. Keep it
persistent and back it up; replacing it changes the server fingerprint shown
to returning players.
Configuration is applied in this order: config file, environment variables,
then command-line overrides. Supported command-line options are `--name`,
`--bind`, `--port`, `--max-players`, `--data-dir`, `--discovery-url`,
`--public`, and `--private`. Value options use `--option=value`. Keep the first
standalone `--` shown above; it separates Godot engine flags from server flags.
Public listing requires the discovery URL and a publicly reachable ENet UDP
port. Discovery makes a server findable but does not relay gameplay traffic.
For a systemd installation, create a dedicated `netfishing` system user, place
the two staged build files in `/opt/netfishing-server`, install the sample
configuration and environment files under `/etc`, and copy
`systemd/netfishing-server.service` to the system unit directory. The service
expects `/var/lib/netfishing-server` to be writable by that user.
## Run with Docker Compose
```sh
./scripts/stage-build.sh ../netfishing/builds/v0.6.4-alpha/server-linux-x86_64
docker compose build
docker compose up -d
```
Set values such as `NETFISHING_SERVER_NAME`, `NETFISHING_SERVER_PORT`,
`NETFISHING_SERVER_MAX_PLAYERS`, and `NETFISHING_SERVER_PUBLIC` in a local
`.env` file. The Compose service runs without Linux capabilities, uses a
read-only root filesystem, and stores persistent state in a named volume.
## Steam distribution
Publish the server as a separate Steam Tool AppID/depot linked to the base
game. Replace the placeholders in copies of the files under `steam/`, then use
SteamCMD to upload the staged `dist/` directory. Keep the example files free of
private Steam credentials.

27
compose.yaml Normal file
View file

@ -0,0 +1,27 @@
services:
netfishing-server:
build: .
restart: unless-stopped
init: true
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
ports:
- "${NETFISHING_SERVER_PORT:-7777}:${NETFISHING_SERVER_PORT:-7777}/udp"
environment:
NETFISHING_SERVER_NAME: "${NETFISHING_SERVER_NAME:-NETfishing Dedicated Server}"
NETFISHING_SERVER_BIND: "*"
NETFISHING_SERVER_PORT: "${NETFISHING_SERVER_PORT:-7777}"
NETFISHING_SERVER_MAX_PLAYERS: "${NETFISHING_SERVER_MAX_PLAYERS:-8}"
NETFISHING_SERVER_PUBLIC: "${NETFISHING_SERVER_PUBLIC:-false}"
NETFISHING_DISCOVERY_URL: "${NETFISHING_DISCOVERY_URL:-https://discovery.netfishing.org}"
NETFISHING_DATA_DIR: /var/lib/netfishing-server
volumes:
- netfishing-server-data:/var/lib/netfishing-server
tmpfs:
- /tmp:rw,noexec,nosuid,size=64m
volumes:
netfishing-server-data:

View file

@ -0,0 +1,7 @@
NETFISHING_SERVER_NAME="NETfishing Dedicated Server"
NETFISHING_SERVER_BIND=*
NETFISHING_SERVER_PORT=7777
NETFISHING_SERVER_MAX_PLAYERS=8
NETFISHING_SERVER_PUBLIC=false
NETFISHING_DISCOVERY_URL=https://discovery.netfishing.org
NETFISHING_DATA_DIR=/var/lib/netfishing-server

10
config/server.cfg.example Normal file
View file

@ -0,0 +1,10 @@
[server]
name="NETfishing Dedicated Server"
bind_address="*"
port=7777
max_players=8
public=false
data_directory="/var/lib/netfishing-server"
[discovery]
url="https://discovery.netfishing.org"

1
dist/.gitkeep vendored Normal file
View file

@ -0,0 +1 @@

40
scripts/package-native.sh Executable file
View file

@ -0,0 +1,40 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 1 || -z "$1" ]]; then
echo "Usage: $0 VERSION" >&2
exit 2
fi
version="$1"
repository_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
dist_dir="${repository_dir}/dist"
packages_dir="${repository_dir}/packages"
package_name="netfishing-dedicated-server-${version}-linux-x86_64"
staging_dir="$(mktemp -d)"
trap 'rm -rf -- "${staging_dir}"' EXIT
for filename in NETfishingServer.x86_64 NETfishingServer.pck; do
if [[ ! -f "${dist_dir}/${filename}" ]]; then
echo "Run scripts/stage-build.sh before packaging." >&2
exit 1
fi
done
install -d "${staging_dir}/${package_name}"
install -m 0755 "${dist_dir}/NETfishingServer.x86_64" \
"${staging_dir}/${package_name}/NETfishingServer.x86_64"
install -m 0644 "${dist_dir}/NETfishingServer.pck" \
"${staging_dir}/${package_name}/NETfishingServer.pck"
install -m 0644 "${repository_dir}/config/server.cfg.example" \
"${staging_dir}/${package_name}/server.cfg"
install -m 0644 "${repository_dir}/README.md" \
"${staging_dir}/${package_name}/README.md"
mkdir -p -- "${packages_dir}"
archive="${packages_dir}/${package_name}.tar.gz"
tar --sort=name --mtime=@0 --owner=0 --group=0 --numeric-owner \
-C "${staging_dir}" -czf "${archive}" "${package_name}"
cd -- "${packages_dir}"
sha256sum "${package_name}.tar.gz" > "${package_name}.tar.gz.sha256"
echo "Created ${archive}"

27
scripts/stage-build.sh Executable file
View file

@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 1 ]]; then
echo "Usage: $0 /path/to/server-linux-x86_64" >&2
exit 2
fi
source_dir="${1%/}"
repository_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
destination_dir="${repository_dir}/dist"
for filename in NETfishingServer.x86_64 NETfishingServer.pck; do
if [[ ! -f "${source_dir}/${filename}" ]]; then
echo "Missing ${source_dir}/${filename}" >&2
exit 1
fi
done
install -m 0755 "${source_dir}/NETfishingServer.x86_64" \
"${destination_dir}/NETfishingServer.x86_64"
install -m 0644 "${source_dir}/NETfishingServer.pck" \
"${destination_dir}/NETfishingServer.pck"
cd -- "${destination_dir}"
sha256sum NETfishingServer.x86_64 NETfishingServer.pck > SHA256SUMS
echo "Staged dedicated server build in ${destination_dir}"

View file

@ -0,0 +1,14 @@
"appbuild"
{
"appid" "<SERVER_TOOL_APP_ID>"
"desc" "NETfishing Dedicated Server"
"buildoutput" "output"
"contentroot" "../dist"
"setlive" ""
"preview" "0"
"local" ""
"depots"
{
"<SERVER_DEPOT_ID>" "depot_build.vdf"
}
}

View file

@ -0,0 +1,11 @@
"DepotBuildConfig"
{
"DepotID" "<SERVER_DEPOT_ID>"
"ContentRoot" "../dist"
"FileMapping"
{
"LocalPath" "*"
"DepotPath" "."
"recursive" "1"
}
}

View file

@ -0,0 +1,24 @@
[Unit]
Description=NETfishing Dedicated Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=netfishing
Group=netfishing
WorkingDirectory=/opt/netfishing-server
EnvironmentFile=-/etc/netfishing-server.env
ExecStart=/opt/netfishing-server/NETfishingServer.x86_64 -- --config=/etc/netfishing-server.cfg
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/netfishing-server
CapabilityBoundingSet=
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
[Install]
WantedBy=multi-user.target