Server configuration (server.cfg)
server.cfg is the single file FXServer reads at boot. It does four jobs:
- opens the network endpoint players connect to,
- declares the server identity shown in the FiveM browser,
- lists which resources load (
ensure), and - 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.cfgasset 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.cfgis versioned and holds no secrets. Anything sensitive — the cfx license key, the API write token — lives inserver_secrets.cfg, gitignored andexec'd from the end ofserver.cfg(see §8).
When a change takes effect. Convars are read at resource start. After editing one,
restart <resource>that reads it (usuallyengine, sometimes a mode) or restart the whole server. Two exceptions:add_principallines load only at full server start, andboot.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 trueThe 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 dirHow 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.
setvssetsvssetr.setis server-only (not readable by client scripts).setrreplicates to clients — readable viaGetConvar, but not shown in the server info.setsis 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 usesetr; add a matchingsetsline 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| Convar | Default | What it does | Why 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)| Line | Why it's set this way |
|---|---|
sv_enforceGameBuild 3258 | Pins 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 on | Required. The engine is server-authoritative (scenes, buckets, kill dispatch) — that needs OneSync. |
onesync_population false | Kills ambient AI peds and traffic. An arena wants empty maps; also a small perf win. |
sv_maxclients | Hard 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 chat | Use the chat resource shipped with the artifact. |
sv_scriptHookAllowed 0 | Disables 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 readsrfx_store,rfx_api_url,rfx_season,rfx_connect,rfx_regionat first boot. The convar block at the bottom of the file (§6) only takes effect after arestart engine— so these few must sit above theensure engineline to apply on a cold start.
devtoolsACE grants. A resource'sExecuteCommandruns under its own principal (resource.devtools), which does not inherit the console's rights. The twoadd_acelines grant it exactlyrefresh+ensure— nothing more.- Adding modes/maps is just an
ensure. Drop in a new mode or battleground pack andensureit; it registers itself with the SDK at start, no engine edit. Maps are the shared battleground pool — narrow the rotation withrfx_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.
| Convar | Default | What it does | Why you'd change it |
|---|---|---|---|
rfx_store | kvp | The 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_season | alpha | Current 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_region | EU-West | Region 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_connect | a placeholder host | Public 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
| Convar | Default | What it does | Why you'd change it |
|---|---|---|---|
rfx_max_scenes | 8 | Hard 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_spectators | 6 | Max spectators per scene (combatants don't count). | Tune the spectator load per match. |
rfx_postmatch_timeout | 60 | Seconds 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_stamina | 100 | Sprint 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_max | 2 | Ceiling 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.
| Convar | Default | What it does | Why you'd change it |
|---|---|---|---|
rfx_arena_creation | staff | Minimum 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_private | all | Minimum 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_arenas | 32 | Server-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_ttl | 60 | Seconds 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
rankedflag: 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_creationandrfx_arena_privateare read at the engine's first boot — placed in the bottom block they only apply after arestart engine.
Stats display & dev
| Convar | Default | What it does | Why you'd change it |
|---|---|---|---|
rfx_career_stats | true | Show 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_lab | false | Enable 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_commands | false | Enable 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.
| Convar | Default | What it does |
|---|---|---|
rfx_ace_admin | group.admin | ACE granting the admin tier (owners — full command access). |
rfx_ace_staff | group.staff | ACE granting the staff tier (moderators). |
rfx_ace_vip | group.vip | ACE granting the vip tier (perks). |
Per-mode convars
Every round-based mode exposes the same three knobs — rfx_<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)
| Convar | Default | What it does |
|---|---|---|
rfx_duel_enabled | true | Load the mode. |
rfx_duel_round | 90 | Round duration (s). |
rfx_duel_best_of | 5 | Round wins to take the match. |
2v2 Duel (mode_squad) — friends form a party (key G) and join together.
| Convar | Default | What it does |
|---|---|---|
rfx_squad_enabled | true | Load the mode. |
rfx_squad_round | 90 | Round duration (s). |
rfx_squad_best_of | 5 | Round 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.
| Convar | Default | What it does |
|---|---|---|
rfx_rooftop_enabled | true | Load the mode (+ its bundled arena). |
rfx_rooftop_round | 90 | Round duration (s). |
rfx_rooftop_best_of | 5 | Round wins to take the match. |
Battle Royale (mode_battle_royale) — solo last-standing; players gather behind a
drop countdown.
| Convar | Default | What it does |
|---|---|---|
rfx_br_enabled | true | Load the mode. |
rfx_br_max_players | 32 | Players per drop (= N anonymous teams of 1). |
rfx_br_min_players | 12 | Players waiting that arm the drop countdown. |
rfx_br_countdown | 45 | Drop countdown (s) once min is reached. |
rfx_br_time_cap | 600 | Safety match cap (s) — resolve by survivors at 0. |
Squad Royale (mode_squad_royale) — squad last-standing; pre-formed parties only.
| Convar | Default | What it does |
|---|---|---|
rfx_sqbr_enabled | true | Load the mode. |
rfx_sqbr_per_team | 2 | Squad size (players per team). Floored at 2. |
rfx_sqbr_max_teams | 16 | Squads per drop (= teamCount). Max players = per_team × max_teams. |
rfx_sqbr_min_teams | 4 | Squads waiting that arm the drop countdown. |
rfx_sqbr_countdown | 45 | Drop countdown (s) once min is reached. |
rfx_sqbr_time_cap | 600 | Safety 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_principalloads at SERVER START only. Arestart enginewon'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| Key | What it is |
|---|---|
sv_licenseKey | Your cfx.re server key. Required to go public. |
steam_webApiKey | Optional Steam identifier resolution; none is fine. |
rcon_password | Remote console password — leave unset unless you use RCON. |
rfx_api_token | Write 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.cfg9. 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.cfgOne 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 enginedoes not re-run it; reopen arenas withexec boot.cfgin the console.
The queue-declare command (the live signature):
rfx queue open <mode> [loadout] [rounds] [map] [s<N>] [ranked]| Token | Meaning |
|---|---|
<mode> | Descriptor id — e.g. duel (1v1) | squad (2v2) | battle_royale — not 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 optional — rfx 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 … x3on a public arena is refused and points you atrfx 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 hereEverything beyond this — a website/leaderboard (rfx_store api), more modes, ranked
arenas, tier perks — is the optional surface documented above.