commit b9c031dfab9f280972110fa0274378092ce7d186 Author: Voyager Date: Mon Aug 10 13:56:40 2026 -0400 Add dedicated server packaging diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6947859 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.git +.gitignore +packages +dist/SHA256SUMS diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e189ea4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/dist/* +!/dist/.gitkeep +/packages/ +/.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..35da49d --- /dev/null +++ b/Dockerfile @@ -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"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..eb81c5f --- /dev/null +++ b/README.md @@ -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. diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..731d58a --- /dev/null +++ b/compose.yaml @@ -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: diff --git a/config/netfishing-server.env.example b/config/netfishing-server.env.example new file mode 100644 index 0000000..43eac1e --- /dev/null +++ b/config/netfishing-server.env.example @@ -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 diff --git a/config/server.cfg.example b/config/server.cfg.example new file mode 100644 index 0000000..a807b6a --- /dev/null +++ b/config/server.cfg.example @@ -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" diff --git a/dist/.gitkeep b/dist/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/dist/.gitkeep @@ -0,0 +1 @@ + diff --git a/scripts/package-native.sh b/scripts/package-native.sh new file mode 100755 index 0000000..4fcd8d5 --- /dev/null +++ b/scripts/package-native.sh @@ -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}" diff --git a/scripts/stage-build.sh b/scripts/stage-build.sh new file mode 100755 index 0000000..74158c3 --- /dev/null +++ b/scripts/stage-build.sh @@ -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}" diff --git a/steam/app_build.vdf.example b/steam/app_build.vdf.example new file mode 100644 index 0000000..4d4ce47 --- /dev/null +++ b/steam/app_build.vdf.example @@ -0,0 +1,14 @@ +"appbuild" +{ + "appid" "" + "desc" "NETfishing Dedicated Server" + "buildoutput" "output" + "contentroot" "../dist" + "setlive" "" + "preview" "0" + "local" "" + "depots" + { + "" "depot_build.vdf" + } +} diff --git a/steam/depot_build.vdf.example b/steam/depot_build.vdf.example new file mode 100644 index 0000000..0863a9b --- /dev/null +++ b/steam/depot_build.vdf.example @@ -0,0 +1,11 @@ +"DepotBuildConfig" +{ + "DepotID" "" + "ContentRoot" "../dist" + "FileMapping" + { + "LocalPath" "*" + "DepotPath" "." + "recursive" "1" + } +} diff --git a/systemd/netfishing-server.service b/systemd/netfishing-server.service new file mode 100644 index 0000000..984f993 --- /dev/null +++ b/systemd/netfishing-server.service @@ -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