Docker hosting

"The container came up on the first try. Nobody had a face, but it came up." — Depot Supervisor Rell Anka

The published StoryForce image runs a dedicated server on a NAS or a VPS without you building anything.

The image does not contain storyforce.pk3. You have to supply that file yourself. Without it the server runs with no models, no shaders, no sound, no interface files and no NPC definitions.


What it does

The image bundles an OpenJK dedicated server, the StoryForce game module and a copy of the shipped config file. It expects 2 folders from the host. One holds the base-game assets and is mounted read only. The other is writable and holds everything the server creates.

What the image leaves out is the asset pack and the llm/ folder. Both are built by the release packer, which never runs in the container build. Steps 4 and 5 of the setup put them in place.


Setting it up

  1. Make a folder on the host for the server, with base and homepath folders inside it.
  2. Copy assets0.pk3, assets1.pk3, assets2.pk3 and assets3.pk3 from a copy of Jedi Academy into base/.
  3. Make a StoryForce folder inside homepath.
  4. Download StoryForce - Server from the StoryForce releases, open the zip, and copy storyforce.pk3 into homepath/StoryForce/. Skip this and players connect to a server with no art, no interface and no NPCs.
  5. Copy the llm/ folder from the same zip into homepath/StoryForce/ if you intend to use AI NPCs. The image does not carry that folder either.
  6. Save the compose file at the end of these steps, changing the 2 host paths on the left of each colon to match step 1.
  7. Forward external UDP port 29070 to the host on your router or firewall.
  8. Run docker compose up -d.
services:
  storyforce:
    image: ghcr.io/wheezypipes/storyforce:latest
    restart: unless-stopped
    ports:
      - "29070:29070/udp"
    volumes:
      # Read-only: Jedi Academy base game assets
      - /volume1/StoryForce/base:/opt/openjk/cdpath/base:ro
      # Persistent: database, logs, config overrides and the mod pk3
      - /volume1/StoryForce/homepath:/opt/openjk/homepath

The database is created inside homepath/StoryForce/db/ on the first run, along with the log folder, the ban list and the scenes folder. Nothing outside those 2 mounts survives a redeploy.


Where the config and secrets go

The image already carries storyforce_server.cfg, and the container starts with +exec storyforce_server.cfg already on its command line. Homepath sits above the image's own copy in the file search order. A storyforce_server.cfg you place in homepath/StoryForce/ therefore shadows the baked-in one and is the file that actually runs.

That homepath copy is also where your 3 credentials belong: rconpassword, sf_d1token and sf_llmnpc_token. Homepath is a host folder you control, and the image is public. What each one does, and why the 2 tokens must be set on every boot, is covered under server configuration.

Start from the copy of storyforce_server.cfg in the server zip rather than writing one from nothing. It carries the permission values the compiled defaults are missing.


Updating

  1. Pull the new image with docker compose pull.
  2. Recreate the container with docker compose up -d.

Your database, config file and asset pack all live in homepath, so they survive the swap. Check whether the release also shipped a new storyforce.pk3. If it did, copy that over too, because the image will not do it for you.


Things to note

  • The image ships no asset pack. This is the most common failure, and it looks like a broken game rather than a missing file. Copy storyforce.pk3 into homepath/StoryForce/.
  • The image ships no llm/ folder. AI NPCs read their base prompt and write their persona files there. See LLM NPC setup.
  • Set an rcon password or shutdown is not clean. Stopping the container sends a quit over rcon, and that lookup reads rconpassword out of your config file. With no password set, nothing is sent and the container is killed instead.
  • The port is UDP. Forwarding TCP 29070 does nothing at all.
  • base is mounted read only on purpose. Everything the server writes has to land in homepath.
  • The server comes up on mp/ffa3. The shipped config ends with that map.
  • An unhealthy container usually means the game module failed. The healthcheck queries the running server every 10 seconds and only fails when nothing answers, so a network fault is rarely the cause.
  • The database and its backups are sensitive. They sit in homepath/StoryForce/db/, on the host. The database explains what they hold and why.

Next