Hosting Guides

Offloading AI with Arma 3 Headless Clients via LinuxGSM

10 min readUbuntu 24.04LinuxGSMReal Virtuality
Once your server is online, jump to the Arma 3 command and config reference.

The Real Virtuality engine that powers Arma 3 is fundamentally single threaded for AI calculations, which means a mission with 200 AI units will drop the main server thread to single digit FPS even on a fast modern CPU. The fix is the headless client: a stripped down arma3server instance that connects to the main server as a player slot, accepts ownership of AI groups via scripting, and runs all of their pathfinding and behavior on its own CPU core.

This guide stands up the main Arma 3 server with LinuxGSM, spins up two headless clients on the same host, whitelists their loopback IP in server.cfg, and adds an init script that hands AI groups off to whichever headless client is least loaded.

Prerequisites

  • Ubuntu 24.04 LTS with at least 16 GB RAM and 8 modern CPU cores.
  • A non root user (LinuxGSM refuses to run as root).
  • UDP 2302 through 2306 open at the firewall.
  • A purchased Arma 3 license is not required for the dedicated server, but mods must be downloaded with a Steam account that owns the game.

Step 1: Install the Main Server

user@host
sudo adduser --disabled-password --gecos "" arma3
sudo machinectl shell arma3@
cd ~
wget -O linuxgsm.sh https://linuxgsm.sh
chmod +x linuxgsm.sh
bash linuxgsm.sh arma3server
./arma3server install

Step 2: Install the Headless Client Binary

The headless client is shipped as a separate instance of LinuxGSM, sharing the same SteamCMD install. We create two instances, listening on loopback only.

user@host
./linuxgsm.sh arma3server-hc1
./linuxgsm.sh arma3server-hc2
./arma3server-hc1 install
./arma3server-hc2 install

Step 3: Whitelist the Local Client IP

Without an entry in headlessClients[], the main server treats the connecting HC as a normal player, which means it counts against the slot limit and cannot receive script ownership.

~/serverfiles/cfg/server.cfg
headlessClients[] = {"127.0.0.1"};
localClient[] = {"127.0.0.1"};
battleyeLicense = 1;
verifySignatures = 2;
kickDuplicate = 1;

Step 4: Headless Client Startup Parameters

~/lgsm/config-lgsm/arma3server-hc1/arma3server-hc1.cfg
startparameters="-client -connect=127.0.0.1 -port=2302 \
-password=YOUR_SERVER_PASSWORD \
-profiles=/home/arma3/hc1 -name=hc1 \
-nosound -mod=@CBA_A3;@ace"

Repeat with hc2 in the second instance file, pointing at the same port. The main server will accept both because both originate from the loopback address listed in headlessClients[].

Step 5: Hand Off AI Groups in the Mission Init

mission init.sqf
if (!isServer) exitWith {};
_hcList = entities "HeadlessClient_F";
_idx = 0;
{
if (side _x == east) then {
_hc = _hcList select (_idx mod (count _hcList));
_x setGroupOwner (owner _hc);
_idx = _idx + 1;
};
} forEach allGroups;

Performance and Tuning

  • Pin each headless client to its own CPU set with taskset so the kernel scheduler does not bounce them across cores.
  • Cap each HC at one CPU core: AI logic is single threaded, more cores per HC are wasted.
  • Tune MaxMsgSend in basic.cfg upward (1024) so AI ownership transfer packets are not dropped.

Conclusion

A correctly configured headless client architecture moves Arma 3 from missions that visibly stutter at 80 AI to missions that hold a steady framerate at 400 AI. Whitelist the loopback IP, pin each HC to its own core, and distribute group ownership in the mission init.