π Run the FIKA dedicated client as a headless service, in a docker container! π
- π§ Features
- π» Dedicated Client
- π¦ Releases
- π€ Running
- π Environment variables
- π§° Troubleshooting
- Container immediately exits
- Stuck right after BepInEx preloader finished
- Crash with assertion in virtual.c
- Container stalls at wine: RLIMIT_NICE <= 20
- My container memory usage keeps going up until I run out of memory
- Server output shows
cannot read properties of undefined (reading info)
- I'm using esync but my client crashes
- π» Development
- π Run Fika Dedicated client fully headless in docker container, with or without GPU on the docker host.
- π Supports Corter-ModSync, to automatically keep dedicated client mods up to date
- π¨ Automatic restart on raid end, to manage container memory usage
- π Automatic purging of EFT
Logs/
dir, to clear out large logfiles due to logspam - π¬ Optionally use Nvidia GPU when running the client, still completely headless without a real display
A dedicated client in the context of FIKA and SPT is essentially a separate instance of the game client that runs in a headless mode to host raids. It acts as a "silent player" that hosts the raid, allowing other players to join without one of them having to host the raid on their own machine.
- Offloading Raid Hosting: By using a dedicated client, the computational load of hosting a raid is offloaded from the player's machine to the dedicated client. This can improve performance for players, especially those with less powerful hardware.
- Consistent Hosting: Ensures that the raid hosting environment is consistent, as it runs on a dedicated server with stable resources.
- Standardized Raid Settings: The dedicated client allows for centralized control over raid settings such as AI behavior, difficulty, and spawning. This ensures a uniform experience for all players, as these settings are managed in one place.
- Performance: Reduces the CPU and RAM load on the player's machine, potentially improving FPS and game performance.
- Stability: Provides a stable environment for hosting raids, reducing the risk of crashes or performance drops.
- Scalability: Allows for more players to join without impacting the host's performance.
- Resource Intensive: Requires a server with significant resources (CPU, RAM, and storage) to run effectively.
- Complex Setup: Involves setting up and maintaining a separate server environment, which can be complex for those unfamiliar with Docker or server management.
- Cost: Running a dedicated server may incur additional costs, especially if using cloud services.
The image build is triggered off git tags and hosted on ghcr. latest
will always point to the latest version.
docker pull ghcr.io/zhliau/fika-headless-docker:latest
I've only tested this on my linux hosts (Arch kernel 6.9.8 and Fedora 6.7.10). This won't work on Windows because of permission issues with WSL2. Probably will not work on ARM hosts either.
Tested with both SPT 3.8.3 and SPT 3.9.x and the associated Fika versions.
- An SPT backend server running somewhere reachable by your docker host. Best if running on the same host.
- You can use my other docker image for running SPT server + Fika: fika-spt-server-docker
- A host with a CPU capable of running EFT+SPT. This will be a disaster running on something like a Pi since the dedicated client is a full fledged client that will run all of the AI and raid logic.
- A directory on your host containing a working copy of the FIKA SPT Client.
- This is the folder including the
BepInEx
folder with all your plugins, and theEscapeFromTarkov.exe
binary. You can copy your working install from wherever you normally run your Fika client.
- This is the folder including the
- The
Fika.Dedicated.dll
plugin file in the FIKA SPT Client'sBepInEx/plugins
folder.
-
Prepare a Dedicated Client Installation
- Copy SPT Installation: Locate your existing SPT installation folder (where you play SPTarkov + Fika) and create a copy of it in another location. This will serve as the dedicated client's installation. For example, if your SPT install is at
D:\Games\SPT3.9
, copy it toD:\Games\SPT3.9Dedicated
. Or install a fresh SPT + Fika installation in a different directory.
- Copy SPT Installation: Locate your existing SPT installation folder (where you play SPTarkov + Fika) and create a copy of it in another location. This will serve as the dedicated client's installation. For example, if your SPT install is at
-
Install Fika Dedicated Client Plugin
-
Download Fika Dedicated Plugin: Download the
Fika.Dedicated.dll
plugin from the Fika Dedicated Releases. -
Install the Plugin: Place the
Fika.Dedicated.dll
plugin into the dedicated client'sBepInEx/plugins
folder. -
Ensure Fika Core Plugin is Installed: Verify that the
Fika.Core.dll
plugin is also present in the dedicated client'sBepInEx/plugins
folder.
-
-
Generate the Dedicated Client Profile and Launch Script
-
Stop the SPT Server: If your SPT + Fika server is running, close it.
-
Edit Fika Configuration: Open the
fika.jsonc
file located at<SPT server folder>/user/mods/fika-server/assets/configs/fika.jsonc
in a text editor.-
Find the
"dedicated"
section and set"amount"
to1
:"dedicated": { "profiles": { "amount": 1 // the amount of dedicated profiles to generate automatically }, "scripts": { "generate": true, // generate the launch script "forceIp": "" // set to your dedicated client's IP address if needed } }
-
-
Start the SPT Server: Launch the SPT + Fika server (e.g.
SPT.Server.exe
orfika-spt-server-docker
container) and wait until it fully loads. It should generate the dedicated client profile and launch script. Look for a message likeCreated 1 dedicated client profiles!
in the server logs. -
Retrieve Profile ID: The profile ID is the filename (excluding the
.json
extension) of the profile generated in the server'suser/profiles
directory. For example, if the profile is named670c0b1a00014a7192a983f9.json
, the profile ID is670c0b1a00014a7192a983f9
.
-
-
Configure the Dedicated Client
-
Edit Fika Core Configuration: Open the
com.fika.core.cfg
file located in the dedicated client'sBepInEx/config/
directory.-
Update values for
Force Bind IP
and/orForce IP
. It might be sufficient to setForce Bind IP
toDisabled
, and to setForce IP
to the IP of the host interface. If you are running a VPN, then this is your VPN IP.## Force Bind IP # Set to Disabled Force Bind IP = Disabled ## Force IP # Set to the IP address of your host interface (e.g., your LAN IP or VPN IP) Force IP = your.host.interface.ip
-
-
-
Run the Docker Image
-
Mount the Fika Client Directory: Ensure that your dedicated client installation directory is mounted to
/opt/tarkov
in the container. If you are running the dedicated client on a server, you will need to copy and transfer the dedicated client installation to the server (~40GB). -
Set Environment Variables: When running the docker image, set the following environment variables:
-
PROFILE_ID
to the profile ID obtained in step 3. -
SERVER_URL
to your server's URL or IP address. -
SERVER_PORT
to your server's port (usually6969
). -
Optionally, set
USE_MODSYNC
totrue
if you are using Corter-ModSync for plugin synchronization.
-
-
Run the Docker Container:
docker run --name fika_dedicated \ -v /path/to/fika:/opt/tarkov \ -e PROFILE_ID=blah \ -e SERVER_URL=your.spt.server.ip \ -e SERVER_PORT=6969 \ -p 25565:25565/udp \ ghcr.io/zhliau/fika-headless-docker:latest
With docker-compose file:
services: fika_dedicated: image: ghcr.io/zhliau/fika-headless-docker:latest container_name: fika_dedi volumes: - /host/path/to/fika:/opt/tarkov environment: - PROFILE_ID=adadadadadadaadadadad - SERVER_URL=your.spt.server.ip - SERVER_PORT=6969 - USE_MODSYNC=true # If you want to use modsync on this dedicated client ports: - 25565:25565/udp
If you are running the SPT server as a service in the same docker-compose stack, you can make use of docker-compose's network DNS to resolve the SPT server from the dedicated client:
services: fika: # See https://github.com/zhliau/fika-spt-server-docker image: ghcr.io/zhliau/fika-spt-server-docker:latest volumes: - /host/path/to/serverfiles:/opt/server ports: - 6969:6969 fika_dedicated: image: ghcr.io/zhliau/fika-headless-docker:latest # ... environment: # ... # Use service DNS name instead of IP - SERVER_URL=fika - SERVER_PORT=6969 # ...
-
-
Verify the Dedicated Client is Running
-
Check Server Logs: Look for messages in the server logs indicating that the dedicated client has connected. Note that this may take a few minutes to happen (~5 minutes).
-
Start a Raid Using Dedicated Host:
-
Launch your SPT + Fika client, log in, and go to the raid selection screen.
-
Click on
Host Raid
and ensure that theUse Dedicated Host
option is available (not greyed out). -
Proceed to host a raid using the dedicated client.
-
-
This image supports the unique plugin updater process that Corter-ModSync employs to update client plugins. To enable support:
- Copy the
Fika.Dedicated.dll
plugin file into the server's BepInEx directory (the directory that modsync treats as the source of truth). - (IMPORTANT) Ensure you have
"BepInEx/plugins/Fika.Dedicated.dll"
in thecommonModExclusions
list in the ModSync server configuration. It should already be there by default. This is to ensure that ModSync does not push the Dedicated plugin to clients nor delete it from the container, especially if you are enforcing theBepInEx/plugins
path on all connecting clients - Set the
USE_MODSYNC
env var totrue
when starting the container.
The start script will then:
- Start Xvfb in the background to make it available to all running container processes
- Anticipate that ModSync may close the dedicated client for an update
- On client plugin update, the script will restart the dedicated client.
Note
Enabling USE_MODSYNC
does NOT mean that the dedicated client will periodically restart to check for updates to plugins. If you wish to do this, you must build it
via a periodic restarter script or a cron job. You can mount the docker socket into a docker:cli
image and run a simple bash while loop or something.
See the example docker-compose.yml in this repo for details
Env var | Description |
---|---|
PROFILE_ID |
ProfileID of the dedicated client you created in step 1 |
SERVER_URL |
Server URL, or the name of the service that runs the Fika server if you have it in the same docker-compose stack |
SERVER_PORT |
Server port, usually 6969 |
Env var | Description |
---|---|
USE_DGPU |
If set to true , enable passing a GPU resource into the container with nvidia-container-toolkit . Make sure you have the required dependencies installed for your host |
DISABLE_NODYNAMICAI |
If set to true , removes the -noDynamicAI parameter when starting the client, allowing the use of Fika's dynamic AI feature. Can help with dedicated client performance if you notice server FPS dropping below 30 |
USE_MODSYNC |
If set to true , enables support for Corter-ModSync 0.8.1+ and the external updater. On container start, the dedicated client will close and start the updater the modsync plugin detects changes. On completion, the script will start the dedicated client up again |
ENABLE_LOG_PURGE |
If set to true , automatically purge the EFT Logs/ directory every 00:00 UTC, to clear out large logfiles due to logspam. |
AUTO_RESTART_ON_RAID_END |
If set to true , auto restart the client on raid end, freeing all memory that isn't cleared properly on raid end |
ESYNC |
If set to true , enable wine esync, to use eventfd based synchronization instead of wineserver. This can improve client performance. Check compatibility by ulimit -Hn . If this value is less than 524288 , you need to increase your system's process file descriptor limit. See this troubleshooting tip. |
FSYNC |
If set to true , enable wine fsync, to use futex based synchronization instead of wineserver. This can dramatically improve client performance. Takes precedence over ESYNC. Requires linux kernel version >= 5.16. Check compatibility via kernel syscall availability with cat /proc/kallsyms | grep futex_waitv . |
Env var | Description |
---|---|
USE_GRAPHICS |
If set to true , disables the -nographics parameter when starting the dedicated client. This will significantly increase resource usage. |
DISABLE_BATCHMODE |
If set to true , disable the -batchmode parameter when starting the client. This will significantly increase resource usage. |
XVFB_DEBUG |
If set to true , enables debug output for xvfb (the virtual framebuffer) |
SAVE_LOG_ON_EXIT |
If set to true , save a copy of the BepInEx LogOutput.log as LogOutput-$timestamp.log on client exit to preserve logs from previous client runs, since this file is truncated each time the client starts |
Crashing with stacktrace in container, permissions errors, wine unable to find EscapeFromTarkov.exe, or wine throwing a page fault on read access to 0000000000000000 exception?
- If you are using Corter-ModSync to keep plugin files up to date, make sure you set the
USE_MODSYNC
env var totrue
or the plugin updater will not be able to run properly and the container will keep exiting! - Make sure you do not have an invalid plugin in the Dedicated client's plugins folder. You can see the list of invalid plugins here
- Double check that you have both the
Fika.Core.dll
andFika.Dedicated.dll
plugins in the client'sBepInEx/plugins
folder! The game will crash in the container if you don't have both plugins! - Check your docker logs output. Maybe you haven't mounted your FIKA client directory properly? Verify the contents of the Fika Client directory to make sure all expected files are there. You must mount a working copy of the Fika client to
/opt/tarkov
. - Double check that your file permissions for the Fika client directory and its contents are correct. The container runs as the user
root
, so it should be able to read any mounted files as long as you don't have anything unusual with your file permissions. - If you have SELinux enabled on the host, the container may not be able to read the mounted directories unless you provide the :z option to re-label the mount with the correct SELinux context. Be VERY careful with this option! I will not be responsible for anything that happens if you choose to do this.
- Make sure your Fika client files have the winhttp.dll in the root folder. This is required for any plugins (even SPT) to run.
fika_dedi | [Message: BepInEx] Preloader finished
fika_dedi | (Filename: C:\buildslave\unity\build\Runtime/Export/Debug/Debug.bindings.h Line: 39)
fika_dedi |
fika_dedi | Fallback handler could not load library Z:/opt/tarkov/EscapeFromTarkov_Data/Mono/data-00007D86E24EA790.dll
- Double check your server is reachable at whatever you set
SERVER_URL
to. If the client can't reach the backend, it tends to hang here. - If you are using ProxMox to spin up a VM to run this image, make sure nested virtualization is enabled.
- Double check that you have both the
Fika.Core.dll
andFika.Dedicated.dll
plugins in the client'sBepInEx/plugins
folder! The game will crash in the container if you don't have both plugins! - Ensure your server contains a profile json file with filename matching the
PROFILE_ID
you provided to the container
../src-wine/dlls/ntdll/unix/virtual.c:1907: create_view: Assertion `!((UINT_PTR)base & page_mask)' failed.
If the dedicated client container crashes with this error, this usually means your max memory map count is too low.
-
Set the value higher and then try restarting the dedicated client
sudo sysctl -w vm.max_map_count=2147483642
Make this persist between reboots by creating a file
/etc/sysctl.d/80-vm-mmax.conf
with the following contents:vm.max_map_count = 2147483642
This happens sometimes on first boot or when the container is force-recreated e.g. by docker-compose up --force-recreate
. I have no idea why it happens, but to solve it you can
- Just wait. Almost exactly 5 minutes after this line is emitted, the client will resume starting normally
- Restart the container with
docker restart
ordocker-compose restart
. This will force the client to start up immediately.
- Try setting the
AUTO_RESTART_ON_RAID_END
env var totrue
, to have the client restart itself after each raid is completed and all players have extracted. This should effectively reset container memory usage back to the ~3Gb required on first boot, after each raid. - EFT is extremely memory hungry, if you are running out of memory while in raid, try to remove some mods that may be memory intensive to see if memory usage improves.
- There may be no better solution than to simply add more RAM to the docker host.
- This usually means your dedicated profile didn't generate properly. You can try deleting the dedicated profile and restarting the server to regenerate a new profile
- MAKE ABSOLUTELY SURE IT'S THE DEDICATED PROFILE. Its username will start with
dedicated_
with passwordfika-dedicated
- MAKE ABSOLUTELY SURE IT'S THE DEDICATED PROFILE. Its username will start with
- Increase your system file descriptor limit. See this doc for more information.
Run the build
script, optionally setting a VERSION
env var to tag the image. The image is tagged fika-dedicated:latest
, or whatever version is provided in the env var.
# image tagged as fika-dedicated:0.1
$ VERSION=0.1 ./build
If you want to pass in your host Nvidia GPU, make sure you have the following:
- set the env var
USE_DGPU=true
in the container - set the env var
USE_GRAPHICS=true
to disable headless mode nvidia-container-toolkit
installed on your host- set the
deploy
section in compose. - No X server running on host
services:
fika:
# My own SPT image but you can use any other
image: ghcr.io/zhliau/fika-spt-server-docker:latest
# ...
fika_dedicated:
image: ghcr.io/zhliau/fika-headless-docker:latest
container_name: fika_ded
volumes:
- /host/path/to/fika:/opt/tarkov
environment:
- PROFILE_ID=adadadadadadaadadadad
- SERVER_URL=fika
- SERVER_PORT=6969
# Set USE_DGPU to enable installation of nvidia drivers in container and start Xorg server on virtual tty
- USE_DGPU=true
# Do not run headless
- USE_GRAPHICS=true
ports:
- 25565:25565/udp
# Specify nvidia device to pass to the container
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]