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:
| Asset | Threat | Covered 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.cfgdisables 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 thesudogroup. -
If your deploy user restarts the service (e.g. a scripted
systemctl restartfrom 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 rivalityfxNow 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 mode440; a syntax error can lock you out of sudo, so alwaysvisudo -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'sINGEST_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 trueinserver.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:
| Setting | Want | Why |
|---|---|---|
| RCON | unset (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_lab | false / unset in prod | Solo-testing commands (/rfx lab …). Great locally, off in production. |
rfx_dev_commands | false / unset in prod | devtools hot-reload (/rfx reload); also the legacy fallback for rfx_lab. Off in production. |
sv_scriptHookAllowed | 0 | Disables ScriptHook — keep off on a PvP server (anti-cheat hygiene). |
sv_enforceGameBuild | pinned | Every 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
ensureit, 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.