Skip to main content

Running the FigNet Server

This guide covers running the full FigNet dev stack - the EntangleServer master and node, the FnVoice module, the Persistence BaaS, and their supporting infrastructure - locally with Docker Compose. It is verified against docker-compose.full-dev.yml and docker/dev/master.ServerConfig.yaml. A more detailed walkthrough is available in docker/dev/README.md in the repository.

Quick start

# From the repo root. Docker Desktop must already be running.
docker compose -f docker-compose.full-dev.yml up -d
docker compose -f docker-compose.full-dev.yml ps # confirm all healthy

After the stack is up, load the FnVoice module (see Loading the FnVoice module) - without it, voice connects but no audio relays.

  • Once the fignet-server:dev and fignet-persistence:dev images already exist, up -d takes about 10 seconds.
  • Persistence auth is off in dev (EnablePersistenceAuth: false), so a Unity client (Entangle + FnVoice) connects without obtaining a JWT first. No --env-file is needed for game/voice testing.

Prerequisites

  • Docker Desktop running. Verify with docker info.
  • On Windows, Docker Desktop must have file-sharing access to the drive that contains the repo (Settings > Resources > File sharing) - the master container bind-mounts ServerConfig.yaml and AppKeys.xml from the repo.
  • Free host ports: 8080, 8090, 8180, 5432, 6379, 9000, 9100, 9200-9201, 5558-5559/udp, 5660/udp, 9001.
  • First-ever run only: cp docker/dev/.env.dev.example docker/dev/.env.dev (needed only for the Persistence-auth path, not for plain game/voice testing).

What comes up (full-dev stack)

ContainerRoleHost ports
fignet-masterEntangleServer Master + Admin UI8080 (admin), 5559/udp (Entangle ENet), 9000 (Entangle WSS), 5558/udp (FnVoice ENet), 9001 (FnVoice WSS)
fignet-nodeEntangleServer Node (game)8180, 5660/udp, 9100 (no FnVoice ports on the node)
fignet-persistence-apiBaaS REST + WSS8090 (8091 S2S internal, not mapped)
fignet-persistence-workerqueue consumer-
fignet-postgres / fignet-redis / fignet-miniopersistence store / cache / S35432 / 6379 / 9200-9201

Voice runs on the master only - the master is the only container that exposes 5558/udp and 9001. The node is game-only.

Loading the FnVoice module

docker/dev/master.ServerConfig.yaml's Modules: list ships with only EntangleServer (FNELobby) and EntangleLoadBalancer. The FnVoice sockets (5558/9001) are open, but the FnVoiceServer module is not loaded by default. There are two ways to load it:

Option A - admin-panel upload. Open http://localhost:8080 (admin / changeme) and upload the FnVoiceServer module manifest. Caveat: this lands inside the container, so a recreate (down then up, or up --build) loses it and it must be re-uploaded. A stop/start (see Bringing the stack down) preserves it.

Option B - auto-load via YAML (recommended; survives everything). Add to the Modules: list in docker/dev/master.ServerConfig.yaml, then recreate the master:

Modules:
- AssemblyName: EntangleServer
Type: EntangleServer.Modules.Lobby.FNELobby
- AssemblyName: EntangleLoadBalancer
Type: EntangleServer.Modules.LoadBalancer.FNELoadBalancer
- AssemblyName: FnVoiceServer # <-- add for voice
Type: FnVoiceServer.Modules.Lobby.FNELobby

FnVoiceServer.dll is a project reference of the host, so it already ships inside the fignet-server:dev image - no upload or rebuild needed, just recreate the master so it re-reads the YAML:

docker compose -f docker-compose.full-dev.yml up -d --force-recreate fignet-master

Verify it's up

docker compose -f docker-compose.full-dev.yml ps # all (healthy)
curl -s http://localhost:8080/healthz # master: {"Status":"ok",...}
curl -s http://localhost:8090/healthz # persist: {"status":"ok"}

To confirm FnVoice actually loaded, check the master log for the module load line, or the admin UI modules list:

docker compose -f docker-compose.full-dev.yml logs --tail=80 fignet-master | grep -iE "module|fnvoice|listening"

Connect a Unity client

  • Game (Entangle) - ENet UDP 127.0.0.1:5559 (master) / :5660 (node), or WSS ws://localhost:9000 (master) / :9100 (node).
  • Voice (FnVoice) - ENet UDP 127.0.0.1:5558, or WSS ws://localhost:9001 (master only).
  • Persistence (BaaS) - http://localhost:8090; in FNPConfig set BaseUrl=http://localhost:8090, AppId=default.
  • Auth: dev runs with EnablePersistenceAuth: false, so a client can connect without a JWT. Flip it to true in the master YAML and use the --env-file path only when testing the BaaS auth bridge.

Bringing the stack down

# Stops the containers but keeps them and their volumes.
# Fast restart with `start`, and an admin-uploaded FnVoice module survives.
docker compose -f docker-compose.full-dev.yml stop
docker compose -f docker-compose.full-dev.yml start # bring it back

# Full down - removes containers (keeps named volumes / DB state).
docker compose -f docker-compose.full-dev.yml down

# Nuke everything incl. Postgres/Redis/MinIO volumes (fresh slate).
docker compose -f docker-compose.full-dev.yml down -v

stop/start vs down/up: stop keeps the container, so an admin-uploaded module persists. down (or up --force-recreate) creates a fresh container, so the module needs to be re-uploaded (or loaded via the YAML approach above).

Rebuilding after server-code changes

The default up -d reuses the existing :dev images. If server-side C# changed (EntangleServer, FnVoiceServer, FigNet*, FigNet.Persistence), rebuild:

docker compose -f docker-compose.full-dev.yml up -d --build

Unity-client-only changes need no server rebuild.

Other compose files

FileUse
docker-compose.full-dev.ymlDefault - master + node + full Persistence + infra.
docker-compose.persistence.ymlJust the BaaS (Postgres + Redis + Persistence Api/Worker).
docker-compose.dev.yml / docker-compose.node.yml / docker-compose.cluster-dev.ymlSingle-server / node-only / multi-node cluster topologies.
docker-compose.ymlBase/prod-ish.

No Docker? Run locally instead:

cd EntangleServer && dotnet run

This reads EntangleServer/ServerConfig.yaml, which already lists FnVoiceServer in its Modules:, so voice works out of the box locally - unlike the Docker dev YAML.

Gotchas

  • No audio though voice "connects" - the FnVoice module isn't loaded (see Loading the FnVoice module). This is the most common cause.
  • up recreated the container and an uploaded module is gone - re-upload it, or use the YAML approach above, or stop/start instead of down/up.
  • Module loads but spams MissingFieldException (e.g. FigNet.Configuration.<field>) every tick, "isolating from tick" - the admin-uploaded module was built against a different FigNet version than the running :dev image (version skew). Fix by rebuilding the image from current source (up -d --build) and building the module from that same source, or use the in-image FnVoiceServer.dll (compiled with the image's core, so it can't skew) via the YAML approach.
  • [Fn][Admin][Cfg] config is read-only after a module upload - expected and harmless: the dev config is bind-mounted read-only, so admin module/game changes apply in-memory only and don't persist across restarts. Persist them by adding to the YAML Modules:/Games: list instead, or drop the read-only flag on the compose mount. The server logs this as a warning, not an error.
  • Master exits with Cannot load AppKeys.xml - Docker Desktop file-sharing for the repo's drive is off.
  • Persistence 401s / admin proxy 502s - only relevant when testing BaaS auth; usually a secret misalignment between .env.dev and the *.ServerConfig.yaml. Irrelevant to game/voice testing.
  • Node never attaches - FIGNET_CLUSTER_SECRET must match in the master YAML, the node YAML, and both containers' environment.