# Godot 4 dedicated server for NetCraftGames

> A copy-paste prompt that makes your AI add a headless server start path to a Godot 4 project (ENet or WebSocket), export it for Linux and add the health page. Copy it, paste it into your AI coding assistant, and read what it changes.

*NetCraftGames (NCG) by Charging Bull Software. Last updated: 2026-10-03. Canonical page: https://netcraftgames.com/can-you-host-my-game/prompts/godot-dedicated/*

## When to use this prompt

Your Godot 4 game already has working multiplayer with ENet or WebSocket, and you need a server that runs without a window on Linux.

If you are not sure this is the right prompt, answer the five questions on [the check](https://netcraftgames.com/can-you-host-my-game/) first: it names the one prompt that fits.

## The prompt


**Status:** Draft. The manifest is checked; the engine steps are not yet proven.

**Godot 4: run as a dedicated server**

```text
You are preparing an existing multiplayer game so a hosting service (NetCraftGames) can run its dedicated server on a Linux machine.
Rules for you:
- Make ONLY the changes listed below. Do not redesign game logic. Do not add multiplayer to a game that has none. If something below cannot be done without a redesign, stop and tell me instead of improvising.
- Never put a password, key or token in code or in any file. Read secrets from environment variables.
- Run every proof step at the end and show me the real output. If a proof step fails, fix it or tell me exactly why you cannot.
- If a step needs a tool you do not have, say so and stop at that step. Do not invent a substitute and do not pretend the step passed.

Facts about the host (exact):
- Linux x86-64, glibc 2.39 or older for every compiled program in the upload.
- The server starts as an unprivileged user in /game. Writable places: /game/saves and a 256 MB /tmp. Nothing is installed, downloaded or compiled on the host. The start command is a fixed list of arguments, not a shell string.
- The host (Ubuntu 24.04 LTS) provides these programs: sh, bash, dash, python3, node, node24 (Python 3.12, Node.js 24.21.0). There is no Java, .NET, Deno or Bun on the host unless you ship it inside the upload.
- Nothing is installed or downloaded on the host: packages travel inside the upload, built for Linux x64 on the owner's own computer.
- A game server cannot look up other websites by name (DNS is closed to it on purpose), so do not make the server depend on calling an outside address by name.
- The host does not set a PORT variable. The port your server uses by default must be the port written in the manifest.
- The host stops the server with SIGTERM and waits up to the number of seconds in the manifest (between 1 and 300).
- The upload is one .tar.gz of at most 512 MiB with at most 10,000 files, no symlinks and no setuid files.
- The host checks your server from outside with a 3 second timeout per request.

TASK: Make this Godot 4 project run as a dedicated server on Linux. Keep gameplay and networking code unchanged. If a step is already done, skip it and say so. Work out first whether the game uses ENet (UDP) or WebSocket.
1. Add a server start path used only when the game is launched with --headless and the user argument --server (the exported program receives it as: ./server.x86_64 --headless -- --server). Create the peer with ENetMultiplayerPeer.create_server(port, max_clients) or WebSocketMultiplayerPeer.create_server(port), where port is OS.get_environment("PORT") or 7777. A WebSocket server must accept connections at the root path "/" and its side HTTP listener (step 2) must use a different port. Load no player scene and no UI.
2. Add a side HTTP listener on TCP 8080 with TCPServer for R2 and R3, and a loopback listener for R4 that reports the peer count.
3. Shutdown (R5): handle NOTIFICATION_WM_CLOSE_REQUEST and prove with a real kill -TERM that Godot exits and your save is written. If SIGTERM does not trigger it on this Godot version, tell me and propose a safe alternative instead of guessing.
4. Export: godot --headless --export-release "Linux" build/server.x86_64 (an export preset for Linux x86-64 with the Dedicated Server feature if your version has one).

Server requirements (all exact):
R1  Listen on 0.0.0.0 (never 127.0.0.1 only, never a random port). The game port comes from the -port argument (or the PORT environment variable) and defaults to 7777.
R2  Health probe: a small side HTTP listener on TCP port 8080. GET /health answers HTTP 200 with the body exactly "ok" within 3 seconds. It must not touch game state. Return 503 if the server loop is stalled or shutting down.
R3  Join probe: GET /join-probe on the same side listener answers 200 with a body that contains "joinable" while a new player could be admitted, otherwise 503 with the body "full" or "stopping". It needs no login and exposes nothing private.
R4  Player count: a second HTTP listener bound to 127.0.0.1 only, port 9090. GET /players answers 200 with JSON {"players": N}, where N is the number of connected players, a whole number from 0 to 10,000, in a body under 4 KB. Do not count a health probe, a join probe or a player who is only in a reconnect grace window.
R5  Shutdown: on SIGTERM (and SIGINT) stop admitting players, tell connected clients, write the save atomically (write a temporary file in the same folder, flush it, then rename it) under /game/saves, close sockets and exit with code 0 within the grace seconds.
R6  Saves and every other file the server writes live under /game/saves only. Read the folder from an environment variable SAVE_DIR and default to /game/saves (use ./saves when running on your own computer).
R7  Log events (join, leave, error), not every tick. The host drops log lines above its rate limit.
Run the listeners on a background thread or task. Read the player count and the "accepting players" flag from values the main game loop updates.

5. Write ncg.json. For ENet:

----- ncg.json (start) -----
{
  "ncg": 1,
  "game": {
    "name": "My Game"
  },
  "version": "0.1.0",
  "build": {
    "dir": "./build"
  },
  "manifest": {
    "engine": "godot-enet",
    "transport": "udp",
    "platforms": [
      "windows"
    ],
    "mode": "dedicated",
    "networkingImplemented": true,
    "os": "linux",
    "arch": "x64",
    "command": [
      "/game/server.x86_64",
      "--headless",
      "--",
      "--server"
    ],
    "ports": [
      {
        "port": 7777,
        "protocol": "udp"
      },
      {
        "port": 8080,
        "protocol": "tcp"
      }
    ],
    "profile": "standard",
    "savePath": "/game/saves",
    "health": {
      "type": "http",
      "port": 8080,
      "path": "/health",
      "expected": "ok"
    },
    "playerProbe": {
      "type": "http",
      "port": 9090,
      "path": "/players"
    },
    "joinProbe": {
      "type": "http",
      "port": 8080,
      "path": "/join-probe",
      "expected": "joinable"
    },
    "shutdown": {
      "signal": "SIGTERM",
      "graceSeconds": 30
    },
    "idleSupported": true
  }
}
----- ncg.json (end) -----

For WebSocket (the WebSocket game port is listed first on purpose, because the gateway connects to the first TCP port):

----- ncg.json (start) -----
{
  "ncg": 1,
  "game": {
    "name": "My Game"
  },
  "version": "0.1.0",
  "build": {
    "dir": "./build"
  },
  "manifest": {
    "engine": "godot-websocket",
    "transport": "wss",
    "platforms": [
      "web"
    ],
    "mode": "dedicated",
    "networkingImplemented": true,
    "os": "linux",
    "arch": "x64",
    "command": [
      "/game/server.x86_64",
      "--headless",
      "--",
      "--server"
    ],
    "ports": [
      {
        "port": 7777,
        "protocol": "tcp"
      },
      {
        "port": 8080,
        "protocol": "tcp"
      }
    ],
    "profile": "standard",
    "savePath": "/game/saves",
    "health": {
      "type": "http",
      "port": 8080,
      "path": "/health",
      "expected": "ok"
    },
    "playerProbe": {
      "type": "http",
      "port": 9090,
      "path": "/players"
    },
    "joinProbe": {
      "type": "http",
      "port": 8080,
      "path": "/join-probe",
      "expected": "joinable"
    },
    "shutdown": {
      "signal": "SIGTERM",
      "graceSeconds": 30
    },
    "idleSupported": true
  }
}
----- ncg.json (end) -----

About ncg.json (the project file the ncg tool reads; it is never packed into the upload):
- Write it in the project root with exactly the content shown. Change only: "game.name" (the real name of the game, 1 to 100 characters), "build.dir" (the folder that holds the final Linux server files), "manifest.platforms" (the platforms the game's players really use) and, where a step says so, the program name in "manifest.command".
- Everything inside the build folder becomes /game on the host, so "/game/server" means the file "server" at the top of that folder.
- "ncg pack <folder>" only zips a folder into the upload and checks it. It does not build, bundle or install anything, so every step above that builds something is yours.

Proof (run these and show me the real output):
P1  Start the finished Linux server the way the host will: the exact command from ncg.json, in a Linux shell (WSL or an ubuntu:24.04 container if you are on Windows or Mac), with no environment variables set except PATH, LANG and HOME.
P2  curl -s -w " %{http_code}" http://127.0.0.1:8080/health  must print ok and 200.
P3  curl -s http://127.0.0.1:9090/players  must print {"players":0}. Connect one real client: it must become {"players":1}.
P4  Send SIGTERM (kill -TERM <pid>). The process must exit with code 0 inside the grace seconds and the save file must exist and parse.
P5  If the ncg tool is installed, run "ncg check" in the project folder and fix everything it lists. If it is not installed, say so; do not write a substitute.
```


## After your AI finishes

1. Read what it changed. It was told to change only what the prompt lists and to stop and ask when something needs a redesign.
2. Run the game with two real players. A prompt cannot prove your game plays well.
3. Come back to [the check](https://netcraftgames.com/can-you-host-my-game/) and answer again, or run the local check the prompt ends with when you have the ncg tool.

## Related pages

- [Can NetCraftGames host my game?](https://netcraftgames.com/can-you-host-my-game/): Five plain questions tell you if NetCraftGames can host your multiplayer game: Yes, Almost with the one change to make, or Not yet. Nothing is uploaded.
- [AI prompts to get your game ready for hosting](https://netcraftgames.com/can-you-host-my-game/prompts/): Copy-paste prompts for your AI coding assistant: add a server mode, a health page and a clean stop, and write the settings file NetCraftGames needs.
- [Multiplayer hosting glossary](https://netcraftgames.com/glossary/): Plain-English definitions of dedicated server, headless, UDP, WebSocket, WSS, WebRTC, STUN, TURN, ENet, KCP, manifest, join probe, weighted hour and more.
