RivalityFX Docsrivalityfx.com ↗

Security & hardening

Deploy on Linux gets a server running; this page gets it ready for the public internet. None of it is RivalityFX-specific plumbing — it's the standard hardening any exposed game server wants — but the defaults RivalityFX ships already cover several items, so most of the work is on the host, not the game.

You're protecting three things:

AssetThreatCovered in
The box (root, SSH)someone turns a game exploit into a rooted server§1, §5
Your secrets (cfx license key, API token)a leaked key gets reused / your write token is stolen§2
Your players (their IPs)IPs harvested from the listing → players get DDoSed§3

What RivalityFX already does for you. The shipped server.cfg disables ScriptHook (sv_scriptHookAllowed 0), keeps developer commands off unless you opt in (rfx_lab / rfx_dev_commands), pins the game build, and ships no RCON password (RCON is a classic brute-force vector — leaving it unset keeps that door shut). See §4.


1. Never run the game as root

If FXServer or a resource is ever exploited, the attacker gets the privileges of the process. Run it as root and that's a rooted box — your license key, your API token, and persistence, all gone. Run it as a dedicated unprivileged user and the blast radius is that user's files and nothing more.

Deploy on Linux §8 already runs the service under a dedicated fivem user (useradd --system, no login shell, no sudo). Keep it that way. Two refinements for a hardened box:

  • The service user needs no sudo at all. It only runs run.sh. Don't add it to the sudo group.

  • If your deploy user restarts the service (e.g. a scripted systemctl restart from CI or a deploy step), grant it only that, via a sudoers drop-in — never general sudo:

    # /etc/sudoers.d/rivalityfx   (install with: sudo install -m 440 -o root -g root … ; then: sudo visudo -cf)
    <deploy-user> ALL=(root) NOPASSWD: /usr/bin/systemctl restart rivalityfx, \
                                       /usr/bin/systemctl stop rivalityfx, \
                                       /usr/bin/systemctl start rivalityfx

    Now a scripted restart works non-interactively, but a compromise of that account can restart the game service — and nothing else.

440, root-owned, and validate. A sudoers file must be mode 440; a syntax error can lock you out of sudo, so always visudo -cf <file> before trusting it.


2. Protect your secrets

Everything sensitive lives in server_secrets.cfg — your cfx license key, the Steam Web API key, the stats-API write token — kept out of server.cfg on purpose (Server configuration §8).

  • It's gitignored — keep it that way. Never commit real keys. The repo ships server_secrets.cfg.example; your filled-in copy stays local to the box.

  • Lock the file down: it holds plaintext credentials, so it should be readable only by the user that runs the server.

    chmod 600 server_secrets.cfg      # owner-only
  • Lock the license key to your IP. In the cfx keymaster portal (portal.cfx.re), pin the server key to your server's static IP. A leaked key is then useless anywhere else.

  • Treat the API write token as a secret (rfx_api_token). It authenticates writes to your stats API; reads are public. If it leaks, rotate it on both sides (the server and the API's INGEST_TOKEN).


3. Player privacy & DDoS

The game port is UDP and inherently public — players have to reach it, so there's no firewall trick that hides it. Two things you can do:

  • Hide player IPs from the server listing. Set sv_endpointPrivacy true in server.cfg (§1). Without it, third parties can scrape your players' IP endpoints from the public listing and target them directly. This is a recommended default — the shipped config sets it.
  • Mitigate volumetric attacks at the provider. Application-level config can't absorb a UDP flood; that's a network-edge job. If your host offers DDoS protection (a "GAME" or anti-DDoS filtered IP), enable it for the game port.

4. Keep the FiveM surface minimal

The shipped server.cfg is already conservative — verify these stay set on your box:

SettingWantWhy
RCONunset (no rcon_password)RCON is UDP and brute-forceable — a top FiveM attack vector. If you don't need remote console, leave it off. If you do, use a long random password.
rfx_labfalse / unset in prodSolo-testing commands (/rfx lab …). Great locally, off in production.
rfx_dev_commandsfalse / unset in proddevtools hot-reload (/rfx reload); also the legacy fallback for rfx_lab. Off in production.
sv_scriptHookAllowed0Disables ScriptHook — keep off on a PvP server (anti-cheat hygiene).
sv_enforceGameBuildpinnedEvery client runs the build your arenas were built against.

Only run resources you trust. The fastest way to get backdoored on FiveM is a "leaked" or "nulled" script — they routinely ship obfuscated loaders. RivalityFX resources are first-party; audit anything third-party before you ensure it, especially anything that phones home or is obfuscated.


5. Lock down SSH & the host

The one inbound door that isn't the game port is SSH — the highest-value target on the box.

  • Key-only auth, no root login. On Ubuntu/Debian cloud images this is usually the default; confirm it:

    sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin'
    # want: passwordauthentication no   /   permitrootlogin no (or prohibit-password)
  • Restrict who can reach SSH. In both the cloud security group and a host firewall, scope port 22 to your admin IP — not 0.0.0.0/0.

  • Firewall — deny by default, open only two things. Mirror your cloud security group with a host firewall so a misconfig on one side is still caught by the other. Only SSH (from your IP) and the game port (TCP and UDP) are inbound; outbound stays open (the server pushes stats/heartbeat and downloads the runtime):

    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    sudo ufw allow from <admin-ip> to any port 22 proto tcp
    sudo ufw allow 30120/tcp          # match your endpoint_add_* port
    sudo ufw allow 30120/udp
    sudo ufw enable
  • Automatic security patches. Let the OS pull security updates unattended:

    sudo apt install -y unattended-upgrades && sudo dpkg-reconfigure -plow unattended-upgrades
  • Ban brute-forcers (cheap, optional): sudo apt install -y fail2ban.


Checklist

[ ] service runs as a dedicated unprivileged user   # never root; no sudo group
[ ] deploy user (if any) has ONLY a scoped systemctl sudoers rule
[ ] server_secrets.cfg is chmod 600 and never committed
[ ] cfx license key locked to the server's static IP
[ ] sv_endpointPrivacy true                          # player IPs hidden from the listing
[ ] no rcon_password · rfx_lab off · rfx_dev_commands off · scripthook 0
[ ] SSH: key-only, no root login, source-restricted to your IP
[ ] firewall: deny-in default; only SSH (your IP) + game port TCP+UDP
[ ] unattended-upgrades enabled
[ ] provider DDoS protection on (if available)

Once the box is hardened, day-to-day operations — ranks, /rfx commands, opening arenas — live in Operations & ranked.