RivalityFX Docsrivalityfx.com ↗

Server configuration (server.cfg)

server.cfg is the single file FXServer reads at boot. It does four jobs:

  1. opens the network endpoint players connect to,
  2. declares the server identity shown in the FiveM browser,
  3. lists which resources load (ensure), and
  4. sets the admin convars (set rfx_*) that tune gameplay.

This page walks the file top to bottom and explains every meaningful line: what it does and why you'd touch it. New to hosting? Deploy on Linux gets the box running first; Configuration recipes has copy-paste setups for common server shapes.

Two config tiers

Before changing a value, know which tier it lives in:

  • Static — design-time values an owner edits in a resource's files (arena spawns, loadouts, tick rates). Decentralized: each resource ships its own config.lua. Applied on resource (re)start.
  • Admin convars — a small, explicit subset exposed in server.cfg as set rfx_*. The value shipped in code is the default, so an unset convar = the documented default. This page is the reference for that tier.

Two files, one secret boundary. server.cfg is versioned and holds no secrets. Anything sensitive — the cfx license key, the API write token — lives in server_secrets.cfg, gitignored and exec'd from the end of server.cfg (see §8).

When a change takes effect. Convars are read at resource start. After editing one, restart <resource> that reads it (usually engine, sometimes a mode) or restart the whole server. Two exceptions: add_principal lines load only at full server start, and boot.cfg (§9) is replayed only on a full restart.


1. Network endpoint

endpoint_add_tcp "0.0.0.0:30120"
endpoint_add_udp "0.0.0.0:30120"
sv_endpointPrivacy true

The TCP+UDP port players connect on. Change it here and it must match three other places: the host firewall rule, the public connect address (rfx_connect, §5), and — if you hide the port behind a clean domain — the _cfx._udp SRV record for your host.

sv_endpointPrivacy true hides player IP endpoints from the server-list API, so third parties can't harvest your players' IPs through the listing and target them for DDoS. Recommended default — keep it on.


2. Server identity (the browser listing)

sv_hostname "^4RivalityFX ^7| PvP arena — round-based & instanced · ^41v1 Duel ^7live"
sets sv_projectName "RivalityFX — PvP Arena"
sets sv_projectDesc "Modular PvP arena engine: round-based game modes…"
sets tags     "pvp, arena, rounds, 1v1, duel, deathmatch, fps, instanced"
sets gametype  "PvP Arena"
sets mapname   "Los Santos"
sets locale    "us-US"
load_server_icon server-icon.png          # 96×96 PNG in the server data dir

How the server presents itself in the FiveM browser. sv_hostname supports ^n colour codes. Update the mode-specific tail of the hostname/description when the set of loaded modes changes.

set vs sets vs setr. set is server-only (not readable by client scripts). setr replicates to clients — readable via GetConvar, but not shown in the server info. sets is the opposite: listed in the server info (browser / info.json) but not readable by clients. The convars below are read by the NUI/client, so they use setr; add a matching sets line for anything you also want in the server listing (e.g. the Discord invite).

setr rfx_discord    "https://discord.gg/your-invite"
setr rfx_store_url  "https://yourstore.tebex.io"                      # optional — paid-pack checkout links
setr rfx_assets_url "https://storage.googleapis.com/your-assets"     # optional — cosmetic card thumbnails
ConvarDefaultWhat it doesWhy you'd change it
rfx_discord(empty)The community Discord invite, surfaced in the in-game NUI menu ("Join Discord").Point it at your server's invite. Shipped as setr (replicated) so the NUI client reads it. Empty hides the button — the default, so an unconfigured server never ships a link to somebody else's community. For the browser listing add a separate sets Discord "…": a sets key is printed verbatim on your info page, so give it a name a player can read. Issue the invite with "Expire after: Never".
rfx_store_url(empty)Your Tebex store base URL. The in-game cosmetics page builds a paid pack's checkout link from it (<store>/package/<sku>). setr (the NUI reads it). Empty → the Buy CTA just nudges players to the store.Set it to enable one-click checkout for standalone packs (sku), and see Selling VIP & packs.
rfx_assets_url(empty)Public assets CDN base URL (e.g. a GCS bucket). The Appearance page derives each cosmetic card thumbnail from it — <base>/peds/<model>.webp (skins), <base>/outfits/<id>.webp (outfits), <base>/weapons/<weapon>.webp (weapon textures). setr (the NUI reads it). Empty → cards fall back to a CSS silhouette / swatch.Point it at your bucket once you host thumbnails. See cosmetics SDK → Thumbnails.

3. Game build, OneSync, slots, chat

sv_enforceGameBuild 3258      # 3258 = mp2024_01 (Bottom Dollar Bounties)
set onesync on                # required: server-side state awareness
set onesync_population false  # PvP arena → no ambient AI peds/traffic
sv_maxclients 64              # 64 = Element Club Argentum ceiling (48 without a subscription)
set resources_useSystemChat true
sv_scriptHookAllowed 0        # 0 = disabled (recommended)
LineWhy it's set this way
sv_enforceGameBuild 3258Pins the GTA V build so every client runs the assets/natives the arenas were built against. Bump only when you intentionally move build (and re-test maps).
onesync onRequired. The engine is server-authoritative (scenes, buckets, kill dispatch) — that needs OneSync.
onesync_population falseKills ambient AI peds and traffic. An arena wants empty maps; also a small perf win.
sv_maxclientsHard cap on connected players. Size it to your VM and how many concurrent scenes you run (rfx_max_scenes, §6). Above 48 slots needs a Cfx.re Element Club subscription (Argentum = 64) — which any server above 8 slots also needs to stream freemode add-on clothing (outfit packs).
resources_useSystemChat true + ensure chatUse the chat resource shipped with the artifact.
sv_scriptHookAllowed 0Disables ScriptHook — keep off on a PvP server.

4. Resources — ensure (order matters)

Resources live under bracketed groups (resources/[platform]/, [modes]/, [packs]/, [systems]/); the brackets are organizational only — FXServer loads anything beneath them. Each is switched on with ensure <name>.

The minimum to boot a playable server: sdk, engine, ui, lobby, one mode (e.g. mode_duel), and one battleground pack (battleground_pack_base).

Load order is not cosmetic — later resources consume registries the earlier ones own:

# 1. CFX backbone (system_resources) — chat, mapmanager, spawnmanager, …
ensure chat
ensure mapmanager
ensure spawnmanager
ensure sessionmanager
ensure baseevents
ensure hardcap
 
# 2. Platform — the SDK contract catalogue, then its consumers
ensure loadscreen      # connecting splash (brand-only NUI)
ensure devtools        # dev hot-reload helper; inert unless rfx_dev_commands=true
add_ace resource.devtools command.refresh allow   # devtools runs under its OWN principal,
add_ace resource.devtools command.ensure  allow   #   so grant it exactly these two — nothing else
ensure sdk             # ← load FIRST: owns the mode / pack / arena registries
ensure ui
ensure customization   # consumes the SDK pack registry
ensure lobby
 
# 3. Store + identity convars — BEFORE `ensure engine` (see the warning below)
set rfx_store   kvp
set rfx_connect "play.example.com"
set rfx_season  alpha
 
ensure engine          # the platform; consumes the SDK mode + arena registries
 
# 4. Systems — attachable modules a mode opts into; AFTER engine, BEFORE modes
ensure system_zone     # EXAMPLE shrinking-zone skeleton
ensure system_loot     # EXAMPLE weapon-loot skeleton
 
# 5. Modes — each a self-contained resource
ensure mode_duel          # 1v1 Duel       — 2 teams × 1
ensure mode_squad         # 2v2 Duel       — 2 teams × 2 (friends join via groups)
ensure mode_rooftop       # 1v1 Rooftop    — 2 teams × 1 (close-quarters; ships its own arena)
ensure mode_battle_royale # Battle Royale  — N teams × 1 (solo)
ensure mode_squad_royale  # Squad Royale   — N teams × K (squads, group-only)
 
# 6. Packs — cosmetics + the shared battleground (map) pool
ensure cosmetic_pack_base  # example skins — registers via sdk:registerPack
ensure battleground_pack_base  # example battlegrounds (the map pool) — sdk:registerBattleground

⚠ Put the store/identity convars BEFORE ensure engine. The engine reads rfx_store, rfx_api_url, rfx_season, rfx_connect, rfx_region at first boot. The convar block at the bottom of the file (§6) only takes effect after a restart engine — so these few must sit above the ensure engine line to apply on a cold start.

  • devtools ACE grants. A resource's ExecuteCommand runs under its own principal (resource.devtools), which does not inherit the console's rights. The two add_ace lines grant it exactly refresh + ensure — nothing more.
  • Adding modes/maps is just an ensure. Drop in a new mode or battleground pack and ensure it; it registers itself with the SDK at start, no engine edit. Maps are the shared battleground pool — narrow the rotation with rfx_battlegrounds (the map allowlist) instead of unloading packs. See the battleground SDK.

5. Persistence & status

How stats persist and how a public website (if you run one) learns the server is alive.

ConvarDefaultWhat it doesWhy you'd change it
rfx_storekvpThe one backend the engine reads and writes through. kvp = self-contained FiveM KVP, no database (but no cross-player leaderboard — KVP can't enumerate keys). api = a web API (the RivalityFX stats stack) that unlocks the leaderboard and feeds a public site.Switch to api once you've deployed the web stack and want a leaderboard + website.
rfx_api_url(empty)Base URL of the API (no trailing slash). Required when store=api; empty → falls back to kvp with a warning.Set to your API URL.
rfx_api_token(empty)Write token for the API. A secret → set it in server_secrets.cfg, never here. Must equal the API's ingest token.See §8.
rfx_seasonalphaCurrent competitive season id. Bumping it (+ restart) routes new writes to a fresh, empty layer; the previous season is left in place as the archive.Roll the leaderboard forward (alpha → beta → …).
rfx_regionEU-WestRegion label shown on the public site. FiveM has no native region, so you declare it; shipped in the status heartbeat. Pure display.Set to your actual region.
rfx_connecta placeholder hostPublic connect address shown on the site's join card + fivem:// button. The server can't auto-detect its own public address, so you declare it — IP:port, a domain, or a cfx join code.Set to your address; for local dev, e.g. 127.0.0.1:30120.
rfx_server_id(empty)Stable slug identifying this server (e.g. eu-duel-1). Stamps every stat with its origin, so the site can promote several servers and the scoreboard can filter per server; shipped in the event envelope + status heartbeat. Empty → the server is anonymous: stats still count toward the global board, but can't be split per server and the server isn't listed on the site. Must match the id the site declares for this server.Set a unique slug once you run more than one server (or want per-server stats).

These (except the secret token) belong above ensure engine — see the warning in §4.


6. Gameplay tuning — the admin convars

The knobs that change how matches play, gated by tier. Each ships a sensible default in code (shown below). Uncomment, edit, restart <resource>.

Engine / platform

ConvarDefaultWhat it doesWhy you'd change it
rfx_max_scenes8Hard cap on concurrent scenes across all modes (a scene = one live match in its own bucket). Also the ceiling on how many arenas can be in a match at once (rfx_max_arenas separately caps how many can exist).Raise on a beefier box; lower to protect a small VM.
rfx_max_spectators6Max spectators per scene (combatants don't count).Tune the spectator load per match.
rfx_postmatch_timeout60Seconds the frozen scoreboard stays up after a match before lingering players are returned to the lobby — so a camper can't hold an arena open. 0 disables it. Applies to all arenas.Shorten for faster recycling; 0 to let players leave on their own.
rfx_stamina100Sprint stamina applied at match spawn (0 = always tired, 100 = never tires).Lower for a fatigue mechanic. Any arena can override per-arena with s<N> (§9).
rfx_group_max2Ceiling on a pre-match party (friends who join together). A party grows organically by invitation up to this; it's a cap, not a target. Floored at 2.Raise as larger team modes ship (3v3 → 3). Must be ≥ a squad mode's per_team.
rfx_battlegrounds(all)Battleground rotation allowlist — space/comma list of battleground ids (the SDK map pool, registerBattleground); empty = every loaded map. Not the match-container Arena.Narrow the map rotation without unloading a pack, e.g. "warehouse lot".

Arena creation

These map who may create an arena onto the tier ladder (all | vip | staff | admin). They're the levers behind a VIP value ladder — see Selling VIP & packs.

ConvarDefaultWhat it doesWhy you'd change it
rfx_arena_creationstaffMinimum tier allowed to create an arena (host a match container) at all (the global default). Reads the legacy rfx_room_creation as a fallback.Open hosting to everyone on a community server (set rfx_arena_creation all) — but then a creator can also delete their own arena in-game.
rfx_create_tier_<modeid>(global)Per-mode override of arena creation, keyed by the mode's descriptor id (e.g. rfx_create_tier_squad). Falls back to rfx_arena_creation.Reserve a premium mode to VIP while another stays open.
rfx_arena_privateallMinimum tier allowed to create a private (password) arena. Reads the legacy rfx_private_rooms as a fallback.Make private arenas a VIP/staff perk.
rfx_max_arenas32Server-wide cap on live arenas (waiting + in-match) — a backstop against a flood of empty player-created arenas. Console/boot.cfg arenas bypass it.Raise on a beefier box; lower to protect a small VM.
rfx_arena_empty_ttl60Seconds an empty player-created arena waits before it's garbage-collected. Persistent (ranked/staff) arenas are exempt — they wait empty for players.Shorten to recycle abandoned arenas faster; raise to let them linger.

Creation tier ≠ play access. These gate creating an arena, not joining one — any player can always join an open arena. Leaving or disconnecting frees only your slot; the arena itself persists (its lifecycle is detached from any player). The creator is a manager (a license-keyed role that survives reconnects) and can delete the arena in-game.

Ranked is system-only — no convar. An arena carries a ranked flag: a ranked arena records stats (the only match type that does — casual records nothing). Ranked arenas can be declared only from the console / boot.cfg (rfx ranked open <mode> …), never by a player — so no one can pick their opponent or run it back. There is no master switch and no ranked-tier convar: if you open ranked arenas, ranked is on.

Arena match settings are NOT convars. Scoring (casual|ranked), best-of, map, loadout and per-arena stamina are chosen per arena when you open it — /rfx queue open <mode> [loadout] [rounds] [map] [s<N>] [ranked] — see §9.

Put the creation/private convars BEFORE ensure engine. Like the store/identity convars (§4), rfx_arena_creation and rfx_arena_private are read at the engine's first boot — placed in the bottom block they only apply after a restart engine.

Stats display & dev

ConvarDefaultWhat it doesWhy you'd change it
rfx_career_statstrueShow the all-time career layer in the mode cover's record chips (Season⇄Career toggle). false shows season standing only. Display only — career totals keep recording regardless.Hide career for a season-only feel.
rfx_labfalseEnable the admin /rfx lab solo-testing commands (start/win/lose/round/hold/skip/loadout/hurt/kill/respawn/heal) plus the battleground-authoring helpers (here/goto). Falls back to rfx_dev_commands when unset.Turn on while testing; leave off in production.
rfx_dev_commandsfalseEnable the devtools hot-reload (/rfx reload + /rfxreload); also the legacy fallback for rfx_lab.Turn on while iterating locally; leave off in production.

Permissions / ACE mapping

These map a tier to an ACE object; who holds it is the add_principal lines in §7.

ConvarDefaultWhat it does
rfx_ace_admingroup.adminACE granting the admin tier (owners — full command access).
rfx_ace_staffgroup.staffACE granting the staff tier (moderators).
rfx_ace_vipgroup.vipACE granting the vip tier (perks).

Per-mode convars

Every round-based mode exposes the same three knobsrfx_<id>_enabled, rfx_<id>_round, rfx_<id>_best_of. Royale modes swap round/best-of for gather + drop tuning. (<id> is the mode's descriptor id, not the resource folder name.)

1v1 Duel (mode_duel)

ConvarDefaultWhat it does
rfx_duel_enabledtrueLoad the mode.
rfx_duel_round90Round duration (s).
rfx_duel_best_of5Round wins to take the match.

2v2 Duel (mode_squad) — friends form a party (key G) and join together.

ConvarDefaultWhat it does
rfx_squad_enabledtrueLoad the mode.
rfx_squad_round90Round duration (s).
rfx_squad_best_of5Round wins to take the match.

perTeam is fixed at 2 (the "2v2" is the product — not a convar). It needs rfx_group_max ≥ 2 so a full party can fill a team.

1v1 Rooftop (mode_rooftop) — a close-quarters duel variant that ships its own exclusive arena (one resource, two registrations). Loadouts are limited to pistols | smg.

ConvarDefaultWhat it does
rfx_rooftop_enabledtrueLoad the mode (+ its bundled arena).
rfx_rooftop_round90Round duration (s).
rfx_rooftop_best_of5Round wins to take the match.

Battle Royale (mode_battle_royale) — solo last-standing; players gather behind a drop countdown.

ConvarDefaultWhat it does
rfx_br_enabledtrueLoad the mode.
rfx_br_max_players32Players per drop (= N anonymous teams of 1).
rfx_br_min_players12Players waiting that arm the drop countdown.
rfx_br_countdown45Drop countdown (s) once min is reached.
rfx_br_time_cap600Safety match cap (s) — resolve by survivors at 0.

Squad Royale (mode_squad_royale) — squad last-standing; pre-formed parties only.

ConvarDefaultWhat it does
rfx_sqbr_enabledtrueLoad the mode.
rfx_sqbr_per_team2Squad size (players per team). Floored at 2.
rfx_sqbr_max_teams16Squads per drop (= teamCount). Max players = per_team × max_teams.
rfx_sqbr_min_teams4Squads waiting that arm the drop countdown.
rfx_sqbr_countdown45Drop countdown (s) once min is reached.
rfx_sqbr_time_cap600Safety match cap (s).

Squad Royale needs rfx_group_max ≥ rfx_sqbr_per_team — parties must be able to reach the squad size, or no team can ever fill. For trios/quads, raise both.


7. Player tiers & admins (ACE)

Permissions ride FiveM ACE, derived live (no database). The ladder, low → high — a higher tier passes every lower gate:

player  <  vip  <  staff  <  admin

§6 → Permissions / ACE chooses which ACE grants each tier; this section is who holds it and the one gotcha:

# Each group must self-grant its ace — on this build, group MEMBERSHIP alone does NOT
# satisfy IsPlayerAceAllowed(src, <ace>). Without these, a principal resolves 'player'.
add_ace group.admin group.admin allow
add_ace group.admin command      allow   # owners: all native/server commands…
add_ace group.admin command.quit deny    #   …except quit
add_ace group.staff group.staff allow
add_ace group.vip   group.vip   allow
 
# Then assign people (license:/fivem:/discord:/steam:):
add_principal identifier.license:xxxxxxxx group.admin   # server owner
# add_principal identifier.fivem:0000000  group.staff   # a moderator

add_principal loads at SERVER START only. A restart engine won't pick up a new one — do a full restart (or run the line live in the console), then have the player reconnect. Verify with /rfx whoami <id>.

The server console is always full admin — you can run any /rfx command from it without a principal.


8. Secrets (server_secrets.cfg)

exec'd from the end of server.cfg. Gitignored — never commit it.

sv_licenseKey "cfxk_…"          # cfx.re key (portal.cfx.re); lock it to your static IP
set steam_webApiKey "none"
#set rcon_password "CHANGE_ME"
set rfx_api_token "…"           # API write token — must equal the API's ingest token
KeyWhat it is
sv_licenseKeyYour cfx.re server key. Required to go public.
steam_webApiKeyOptional Steam identifier resolution; none is fine.
rcon_passwordRemote console password — leave unset unless you use RCON.
rfx_api_tokenWrite token for the api store. Pairs with rfx_api_url (§5).

The line at the bottom of server.cfg that pulls it in:

exec server_secrets.cfg

9. Boot script (boot.cfg)

exec'd last, after every resource is up. It's the server's "init.d": runtime commands you'd otherwise retype each boot — chiefly opening the public arenas (they live in the engine's memory and are wiped on a restart).

exec boot.cfg

One command per line; each runs as the server console (= admin). Because it runs after resources start, it's for commands — convars read at load time still belong in server.cfg.

Nothing opens by itself. A fresh server boots with zero arenas — the engine no longer auto-creates anything (the royale public arenas included). Whatever public arenas you want, you list here (or open live). Players can still create their own casual arenas in-game (subject to rfx_arena_creation) with no boot line; ranked arenas only ever come from here.

Replayed on a full restart only. A lone restart engine does not re-run it; reopen arenas with exec boot.cfg in the console.

The queue-declare command (the live signature):

rfx queue open <mode> [loadout] [rounds] [map] [s<N>] [ranked]
TokenMeaning
<mode>Descriptor id — e.g. duel (1v1) | squad (2v2) | battle_royalenot the resource name.
[loadout]A weapon-config key (pistols | smg | rifle | sniper | shotgun), or the literal random. Omit it for the RANDOM card — a fresh symmetric weapon each match, full variety with zero population split. Recommended default.
[rounds]Best-of (odd, 1–9). Default = the mode's best_of.
[map]A battleground id to pin; omit for a fresh map each match.
[s<N>]Stamina 0–100 (e.g. s50); default = the rfx_stamina convar.
[ranked]Record stats (career + season + leaderboard). Omit → Quick Play, records nothing. /rfx ranked open … is the same command with ranked pinned on. Console/admin only.

Tokens are order-independent and all optionalrfx queue open duel is valid.

rfx queue open duel 5 s0                      # Quick Play duel, RANDOM weapon, best-of 5, no fatigue
rfx ranked open duel 5 s0                     # the ranked ladder for the same mode
rfx queue open squad rifle 5                  # 2v2, pinned rifle
rfx ranked open duel sniper 5 warehouse       # ranked sniper on the pinned "warehouse" map
rfx queue open battle_royale                  # royale — fills, then launches on a gather countdown
rfx arena open duel smg 5 s50 pass:vip5       # a PRIVATE one-off arena, stamina 50, code "vip5"

x<N> is gone for public arenas. N identical browsable copies scatter joiners across empty containers — the defect a queue exists to prevent — so /rfx arena open … x3 on a public arena is refused and points you at rfx queue open. Private arenas are exempt (the join code is the rendezvous).


A minimal server.cfg

The smallest file that boots a playable 1v1 server (KVP store, no website):

endpoint_add_tcp "0.0.0.0:30120"
endpoint_add_udp "0.0.0.0:30120"
sv_hostname "RivalityFX | 1v1 Duel"
sv_enforceGameBuild 3258
set onesync on
sv_maxclients 32
 
# CFX backbone
ensure chat
ensure mapmanager
ensure spawnmanager
ensure sessionmanager
ensure baseevents
ensure hardcap
 
# Platform (sdk FIRST) + one mode + one arena pack
ensure sdk
ensure ui
ensure lobby
ensure engine
ensure mode_duel
ensure battleground_pack_base
 
# Owner
add_ace group.admin group.admin allow
add_ace group.admin command      allow
add_ace group.admin command.quit deny
add_principal identifier.license:xxxxxxxx group.admin
 
exec server_secrets.cfg     # sv_licenseKey lives here

Everything beyond this — a website/leaderboard (rfx_store api), more modes, ranked arenas, tier perks — is the optional surface documented above.