Docker, Pterodactyl and Fly.io
Run the official Linux server image with Docker or Compose, give it a built gamemode, and host it on Fly.io or a Pterodactyl panel.
Every release publishes a Linux amd64 image,
ghcr.io/kingdomsconnected/kcdc-server:<version>, where <version> is the
release number without the v. Replace <version> in the examples with the
latest release’s tag. The registry does not provide a latest tag.
One command runs it:
docker run -d --name kcdc --init --restart unless-stopped \ -p 27015:27015/udp -p 27016:27016/tcp \ -v kcdc-data:/home/container 'ghcr.io/kingdomsconnected/kcdc-server:<version>'docker logs -f kcdcEverything the server writes (server.json, logs, crash data, .packages/,
resources/) lives in /home/container. On a named volume it survives
upgrades: recreate the container with the new tag. The server runs as UID and
GID 10001, so a bind-mounted directory must be writable by that user.
The game’s navigation mesh goes in the volume too, at
/home/container/files/<level>/recast.pak; see
mod.navmesh. The image does not include it.
Publishing the ports is not enough on its own: open them in the host or cloud firewall too (Let players connect).
Add the built gamemode
Section titled “Add the built gamemode”On every start, the entrypoint copies the default gamemode into
resources/kcdc-gamemode only if that folder does not exist. The copy is
TypeScript source with no dist/ and no ui/ (the F4 debug panel), and the
image has no Node.js to build it. So a fresh container accepts players but
runs no gamemode until you copy a built one in:
-
On your own machine, build the gamemode from the release (Install and run a server). You now have
server/resources/kcdc-gamemode/withdist/andui/. -
Copy both folders in and restart:
Host, in the release's server/ folder docker cp resources/kcdc-gamemode/dist kcdc:/home/container/resources/kcdc-gamemode/docker cp resources/kcdc-gamemode/ui kcdc:/home/container/resources/kcdc-gamemode/docker restart kcdc -
Check the log for the gamemode’s
ready with ... commandsline.
Your own resources go the same way: docker cp the built folder into
/home/container/resources/, then restart, or use refresh and start in
the console.
Compose
Section titled “Compose”Save this as compose.yaml, with a .env beside it holding
KCDC_VERSION=<version>:
services: server: image: ${KCDC_IMAGE:-ghcr.io/kingdomsconnected/kcdc-server}:${KCDC_VERSION:?Set KCDC_VERSION to a released version} platform: linux/amd64 restart: unless-stopped init: true ports: - "27015:27015/udp" - "27016:27016/tcp" volumes: - server-data:/home/container stop_grace_period: 30s
volumes: server-data:docker compose pulldocker compose up -ddocker compose logs -f serverKCDC_VERSION and the optional KCDC_IMAGE only pick the image; server
settings come from server.json in the volume or from arguments.
To edit resources on the host, mount a folder over resources/. The
entrypoint seeds the source gamemode there too if it is missing, so put your
built kcdc-gamemode in first:
volumes: - server-data:/home/container - ./resources:/home/container/resourcesChange the ports
Section titled “Change the ports”Anything after the image name goes to the server, so the command-line arguments work unchanged. Change a port and its mapping together:
docker run -d --name kcdc --init --restart unless-stopped \ -p 28015:28015/udp -p 28016:28016/tcp \ -v kcdc-data:/home/container 'ghcr.io/kingdomsconnected/kcdc-server:<version>' \ --port 28015 --apiport 28016In Compose, set the service’s command and ports:
command: ["--port", "28015", "--apiport", "28016"] ports: - "28015:28015/udp" - "28016:28016/tcp"Use the console
Section titled “Use the console”A detached container has no stdin, so typed console
commands go nowhere. Start it with
-it and attach:
docker run -dit --name kcdc --init --restart unless-stopped \ -p 27015:27015/udp -p 27016:27016/tcp \ -v kcdc-data:/home/container 'ghcr.io/kingdomsconnected/kcdc-server:<version>'docker attach kcdcIn Compose, add stdin_open: true and tty: true to the service, then
docker compose attach server. Detach with Ctrl+P then Ctrl+Q;
Ctrl+C shuts the server down. Without a console, docker restart kcdc
picks up every resource change but disconnects everyone.
Fly.io
Section titled “Fly.io”Deploy with the fly.toml from the mod’s repository, whose process command
passes Fly’s UDP bind address as --host. UDP on Fly needs a dedicated IPv4:
fly ips allocate-v4fly deploy --image 'ghcr.io/kingdomsconnected/kcdc-server:<version>'That fly.toml mounts no volume, so /home/container starts empty whenever
the machine is recreated. Add a Fly volume at /home/container, or build an
image that carries your built gamemode (with dist/ and ui/) in place of
the seeded source:
FROM ghcr.io/kingdomsconnected/kcdc-server:<version>COPY kcdc-gamemode/ /opt/kcdc/default-resources/kcdc-gamemode/The entrypoint seeds from there, so this image also works for Docker and Compose on a fresh volume.
Pterodactyl
Section titled “Pterodactyl”The image follows Pterodactyl’s conventions (user container, home
/home/container, Wings’ STARTUP variable), and each release embeds a
matching egg. Extract it:
IMAGE='ghcr.io/kingdomsconnected/kcdc-server:<version>'docker pull "$IMAGE"CONTAINER=$(docker create "$IMAGE")docker cp "$CONTAINER:/usr/share/kcdc/egg-kcdc.json" ./egg-kcdc.jsondocker rm -v "$CONTAINER"- In the Panel’s admin area, create a KCDC nest and Import Egg
egg-kcdc.jsoninto it. - On the node, add two free ports, for example 27015 (game) and 27016 (HTTP).
- Create a server from the egg, with the game port as primary allocation and the HTTP port as an additional one.
- Set the egg’s HTTP port variable to the additional allocation. The two must differ; the variable alone does not allocate a port.
- Start the server and wait for
KCDC Server successfully started. - Upload your built
dist/andui/intoresources/kcdc-gamemode/with the file manager or SFTP (Add the built gamemode), then restart.
The egg’s startup command sets bind addresses and ports, overriding those
keys in server.json. Everything else, including maxplayers (up to 512),
password, server-token and the mod keys, is yours to edit in the file
manager; keep the token and password in the file, not the egg, since eggs
get shared. The console tab writes to stdin, so console commands work as typed.
To upgrade: stop the server, back up its files (hidden ones included), import the new release’s egg, select the new image tag on the server, and start it. No reinstall is needed.
Related
Section titled “Related”- Run a dedicated server: ports, arguments and console commands.
- server.json settings: level and required DLCs.
- Server browser listing: list the container’s server.
- Let players connect: firewalls and the player checklist.