Protecting a FiveM server from DDoS attacks

Published on 15 min read

Which ports a FiveM server really needs, how to secure the query endpoints, txAdmin, rate limits and the whitelist, and from which attack size on only upstream filtering helps.

A FiveM roleplay server that keeps disappearing for a few minutes every evening rarely has a hardware problem. Usually an attack is running, and it runs exactly when the most players are online. This article starts with what you can secure yourself at no extra cost, then shows where those measures technically end, and finally explains what has to happen in the network in front of the server.

Everything here refers to an FXServer on Debian 12, Debian 13, Ubuntu 22.04 LTS or Ubuntu 24.04 LTS. The commands are written for root. As a normal user, put sudo in front of them.

If the attack is running right now: do not change anything in the configuration and do not reboot the server. Capture the measurements first (see the section "Logging"), because once the attack is over they are gone.

Why FiveM servers in particular get attacked so often

FiveM projects combine several traits that make them a convenient target. First, a roleplay server publishes its address all by itself: the entry in the Cfx.re server list contains the IP address and the port in plain text, because otherwise players would never find the server. Second, the player base is tied to fixed hours, so an outage at 8 pm is as visible as it gets. Third, there is competition between projects, there are banned players and internal conflicts, and an attack costs whoever orders it neither skill nor any serious amount of money.

On top of that comes a technical detail: the game traffic runs over UDP. UDP has no connection setup you could insist on, and source addresses can be spoofed. So an attacker does not have to join your server, or even address it correctly, in order to create load. For the details of what a DDoS attack actually is, read What is a DDoS attack?.

The ports that actually matter

By default an FXServer binds to a single port, and it does so on both protocols. In server.cfg:

endpoint_add_tcp "0.0.0.0:30120"
endpoint_add_udp "0.0.0.0:30120"

These two lines are the entire attack surface of the game itself:

  • 30120 UDP carries the live game traffic: position data, synchronization, voice.
  • 30120 TCP carries the connection setup and the built-in HTTP endpoints of the FXServer: /info.json, /players.json and /dynamic.json.
  • 40120 TCP is the default for the txAdmin web interface.
  • 3306 TCP belongs to the database that every ESX or QBCore framework needs.
  • 22 TCP is your SSH access.

Of these five ports, exactly two belong on the open internet. The other three are the most common avoidable mistake on FiveM servers.

What you can do yourself before spending money

This section is the longest one, and that is deliberate. A cleanly configured server survives small and medium attacks under its own power, no matter who hosts it.

1. Take stock: what is listening at all?

Before you write a single rule, check what your server actually offers to the outside. Do not guess, look:

ss -lntup

The interesting column is the local address. 0.0.0.0:30120 and [::]:30120 mean "reachable from the entire internet", 127.0.0.1:3306 means "local only" and needs no firewall rule. Next to the game you will often find txAdmin, MariaDB, a web server and some long forgotten voice service in that list. A port scan from outside gives you the attacker's view:

nmap -Pn -p- --min-rate 1000 YOUR.SERVER.IP.ADDRESS

2. Leave open only what the game really needs

Two rules facing the outside are enough for FiveM, everything else gets restricted or is never published in the first place. With UFW it looks like this, and in exactly this order so that you do not lock yourself out:

ufw allow 22/tcp comment 'SSH'
ufw allow 30120/tcp comment 'FiveM'
ufw allow 30120/udp comment 'FiveM'
ufw allow from 203.0.113.10 to any port 40120 proto tcp comment 'txAdmin'
ufw default deny incoming
ufw default allow outgoing
ufw --force enable
ufw status verbose

Replace 203.0.113.10 with your own address. On a connection with a changing address this is impractical, and the better route is described further down. The full guide including the escape route is in Setting up the UFW firewall without locking yourself out.

The database has no business on the open internet under any circumstances. Check in /etc/mysql/mariadb.conf.d/50-server.cnf that it says:

bind-address = 127.0.0.1

3. Secure the query port and the HTTP endpoints

On the TCP side of 30120, the FXServer answers HTTP requests without anyone having to start the game. Have a look at what it serves there:

curl -s http://127.0.0.1:30120/info.json | head -c 600
curl -s http://127.0.0.1:30120/players.json | head -c 600

/players.json lists the connected players together with their identifiers. That is handy for status pages and Discord bots, but it is also an invitation: the endpoint can be queried as often as anyone likes, every query costs your server work, and the content tells an attacker when an attack is worth the effort. Two countermeasures cost nothing. First, the endpoints of your players do not belong in the response, and one line in server.cfg is enough for that:

sv_endpointPrivacy true

Second: if your Discord bot or your website shows the player count, do not query the endpoint from the visitor's browser, but cache the result at fixed intervals instead. That way a busy status page produces one query per interval instead of one per visitor.

4. Do not put txAdmin on the open internet

Port 40120 is a web interface with full access to your server. If you have no static IP address for an allow rule, keep the port closed to the outside and reach it through an SSH tunnel, then open http://127.0.0.1:40120 locally:

ssh -N -L 40120:127.0.0.1:40120 root@YOUR.SERVER.IP.ADDRESS

5. Limit connection and packet rates

Against small attacks and sloppy bots, an upper limit per source address helps:

iptables -I INPUT -p tcp --dport 30120 --syn -m connlimit --connlimit-above 12 --connlimit-mask 32 -j DROP
iptables -I INPUT -p udp --dport 30120 -m hashlimit --hashlimit-name fivem_udp --hashlimit-mode srcip --hashlimit-above 600/sec --hashlimit-burst 900 -j DROP

The first rule drops new TCP connections as soon as one address holds more than twelve of them open at the same time, the second one drops UDP packets once the same source sustains more than 600 packets per second. Both numbers are starting points, not truths: a full roleplay server produces far more packets than an empty one, and setting the limits too tight throws out your own players. Measure a week of normal operation first.

Two notes on this. Plain iptables rules are gone after a reboot, and on Debian and Ubuntu you save them like this:

apt-get install -y iptables-persistent
netfilter-persistent save

Under UFW, such rules belong in /etc/ufw/before.rules, because otherwise they disappear with the next ufw reload. Another bottleneck that is often overlooked is the connection tracking of the kernel: once it fills up, the server drops legitimate packets as well, and the log says "nf_conntrack: table full". The current value and the limit are shown by:

sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max

6. The entry in the server list

Honesty beats wishful thinking here: your IP address cannot be kept secret. Every player who has connected once knows it, and the list entry publishes it anyway. If you do not need the public entry, because the project runs purely through Discord and direct connections, you can switch it off with sv_master1 "". That costs you all visibility for new players, though, and it only helps against the laziest kind of attacker.

Two habits are more effective. Never publish the raw IP address yourself, so neither in the Discord channel nor on the project website. And connect your players through a hostname, so that you can change the address if it comes to that without breaking every reference. The classic pitfall here is old DNS records: a forgotten A record pointing at the previous address makes any change pointless.

7. Whitelist and join checks

A whitelist works against everything that uses the regular join path: trolls, cheat clients, botnets built from throwaway accounts. You implement it on the server side in the playerConnecting event, where you hold the connection with the deferral functions, check the identifier and only then let the player through. Add a strict account check, a realistic player limit and a disabled ScriptHook:

sv_authMaxVariance 1
sv_authMinTrust 5
sv_maxclients 48
sv_scriptHookAllowed 0

Set an RCON password only if you actually need RCON, because that access sits on the same open port. And one thing has to be clear: a whitelist protects your game logic, not your uplink. An attacker who floods your server does not want to join at all. His packets get rejected, but they have arrived all the same, and that is exactly the point.

8. Validate network events on the server side

Many outages that get reported as a DDoS attack come down to a single script. FiveM resources communicate through network events, and an event that the server executes without checking it is an open door: anyone who fires a TriggerServerEvent from the client with arbitrary values can create money, spawn vehicles or trigger database queries in a loop until the server grinds to a halt.

Three rules catch most of that. Register only those events with RegisterNetEvent that really are meant to come from the client. Never rely on values the client sends along, but determine the player on the server side from source. And limit how often a player may trigger the same event, especially for anything that hits the database. If the server stutters while the uplink is quiet, resmon 1 in the client console shows the processing time per resource, and the culprit is usually right at the top.

9. Logging, so that you have data when it counts

The most important step is the one almost nobody takes beforehand: build a baseline while everything is still normal. Without a normal value you cannot say after an incident whether 40,000 packets per second was a lot or simply a Tuesday evening. With apt-get install -y vnstat sysstat the measurement runs permanently in the background. During an incident four commands are enough: packet rates per second, the drop counters of the interface, kernel messages and a short sample of the traffic.

sar -n DEV 1 10
ip -s link show eth0
dmesg -T | tail -50
tcpdump -ni eth0 port 30120 -c 200 -q

One rule for tcpdump: always cap it with -c, because a capture under full load puts extra strain on a server that is already overloaded. How to read the numbers is covered in Detecting a DDoS attack.

Where these measures stop

Now the part that no configuration file can solve. Everything so far runs on your server, which means at the far end of the uplink. A firewall rule decides about a packet that has already travelled down the wire. You can drop it, but you cannot un-send it.

Do the math once. A typical game server sits on 1 Gbps, which is 125 megabytes per second, and the uplink is full as soon as somebody sends more. Attacks against FiveM projects usually range between 5 and 50 Gbps, so five to fifty times your uplink. Whether your iptables rule behind it is any good no longer matters, because the packets of your players stop getting through before that.

The second figure is the packet rate, and it often hits earlier than the bandwidth does. With small packets of 64 bytes, around 1.49 million packets per second fit into an uplink of 1 Gbps. Depending on CPU and network card, a normal server kernel handles a few hundred thousand of them before it starts dropping. So an attack that does not even fill a third of your uplink can still take your server down, because the processing time goes into the dropping. Operators experience this as "the utilization was not even high, and yet everything was gone".

For a sense of the magnitudes that really occur: on KernelHost servers we have filtered, among others, an attack of over 473.4 Gbps at over 41.5 million packets per second against a voice server, and a UDP flood of over 112.2 Gbps against a game server. There is no local setting for that. Volumetric attacks have to end in the network in front of the server.

What KernelHost puts up against it

The always-on protection included with every server

DDoS protection at KernelHost is built in two layers and permanently active, with nothing for you to switch on, order or configure:

  • Layer 1: 17 Tbps of mitigation capacity in the global scrubbing network. Volumetric attacks are scrubbed close to their source, before they reach the datacenter.
  • Layer 2: Arbor real-time filtering with 3.2 Tbps in Frankfurt am Main. Directly in front of the server, protocol-specific patterns are detected and dropped, packet by packet.

Two properties make the difference. The protection runs permanently and does not have to react to an attack first, so there are no opening minutes in which the server is gone. And no null-routing is used: your IP address stays on the network, only the malicious packets are dropped. Whoever takes the IP address off the network achieves the same result for you as the attacker does. The datacenter is maincubes in Frankfurt am Main, Germany. Which games and protocols are covered is listed in Game server DDoS protection with real-time filtering.

Advanced DDoS Protection for projects under constant fire

Some projects are attacked not occasionally, but deliberately and for weeks on end. For those there is Advanced DDoS Protection from €50.00 per month, PrePaid and with no minimum term. The difference is not more capacity, it is control:

  • A dedicated protected IP from the Frankfurt core, which your server is switched over to inside our own network. Nothing has to be rebuilt on your side.
  • Self-managed protection rules per port and protocol in the customer panel: you define what is allowed on 30120 UDP and what is allowed on 30120 TCP, without writing a ticket for it.
  • Changes take effect in real time, so you can fine-tune while an attack is still running.
  • A protection profile that matches the game. There is a ready-made profile for FiveM, and there are profiles for modified and custom applications on any TCP or UDP port.

The two tiers compared

Feature Included always-on DDoS protection Advanced DDoS Protection
Price included in every server package, at no surcharge from €50.00 per month, PrePaid
Filtering capacity 17 Tbps of global scrubbing plus Arbor real-time filtering with 3.2 Tbps in Frankfurt am Main the same two-layer filtering
IP address the IP address of your server an additional dedicated protected IP
Rule set automatic profiles, no configuration needed your own rules per port and protocol in the customer panel
Changes are applied automatically take effect in real time, even during an attack
Game profile optimized profiles for common games, FiveM included a profile matched to the game, also for modified applications
Null-routing no no
Term tied to the server package PrePaid, no minimum term, no notice period, no setup fee

For most FiveM projects the included always-on protection together with a clean server configuration is enough. Advanced DDoS Protection is the answer to somebody taking it personally.

Common mistakes and how to fix them

"I changed the IP address and was offline again two hours later": the attacker got the new address from the same source as the old one, usually the list entry, a Discord bot or an old DNS record. Changing the address buys time, it is not a solution.

"My iptables rules have no effect": three causes are common. The rules sit behind the UFW chains and are never reached, they were gone after the last reboot (then netfilter-persistent save or an entry in /etc/ufw/before.rules helps), or the attack is volumetric and the rule works correctly on an uplink that is already full. Use iptables -L INPUT -n -v to check whether the hit counters are rising. If they stay at zero, the rule is never reached.

"The server is running, but every player is rubber-banding": that is more often a script than an attack. First use resmon 1 to see whether one resource is eating the processing time. If sar -n DEV 1 10 stays unremarkable, it was not a DDoS attack.

"txAdmin shows hundreds of failed connection attempts": that is a join flood, and it hits the game logic, not the uplink. The whitelist, the account check and the connection limit per source address work against it.

"My previous provider blocked my IP address": that is null-routing. The provider protects its own network with it, and for you the result is identical to a successful attack, usually for hours afterwards. If in doubt, ask whether traffic is filtered or null-routed. The answer says more about your availability than any hardware spec.

"I do not see anything unusual in tcpdump": if the traffic is already filtered in the network upstream, nothing arrives on the server, exactly as expected. That is the normal case when the filtering works. The other way round applies as well: once the uplink is saturated, even the SSH session you wanted to measure with may no longer reach you. Use the VNC console in the customer panel then, which works independently of the network of the guest system.

In short

Close everything except 30120 TCP and UDP, keep txAdmin and the database off the open internet, limit connections and packet rates per source address, run a whitelist and validate network events on the server side. That covers you against everything that gets by without serious bandwidth. Beyond that, only the network in front of the server decides the outcome.

If your project already runs at KernelHost, the filtering is active without you having to do anything. If you still notice something unusual, open a support ticket so that we can fine-tune the filter rules for your IP address. During an ongoing attack you can also reach us through the WhatsApp emergency chat at +43 650 8209883.

Frequently asked questions

My FiveM server is offline right now. How do I tell whether it is a DDoS attack?
Look at the packet rate of the interface, not at the CPU load. sar -n DEV 1 10 shows packets and bytes per second, ip -s link show eth0 shows the drop counters. If the inbound packets climb far above your normal value while the server itself is barely working, it is an attack. If the network counters stay unremarkable and everything still stutters, check resmon 1 in the client console: in that case a single resource is usually eating the processing time.
Does it help to change the IP address quickly right now?
Only briefly. The attacker usually finds the new address again within minutes or hours, because it is in the server list entry, because a Discord bot with a status display publishes it, or because an old DNS record still exists. Changing the address buys you time, but it does not solve the problem.
Which ports do I have to leave open for FiveM?
Exactly two: 30120 TCP and 30120 UDP, set through endpoint_add_tcp and endpoint_add_udp in server.cfg. Port 40120 (txAdmin) and 3306 (the database) have no business on the open internet. Restrict 40120 to your own address or reach the interface through an SSH tunnel, and bind the database to 127.0.0.1.
Can I defend myself against a DDoS attack with iptables or UFW?
Against small attacks and sloppy bots yes, against volumetric attacks no. A firewall rule on the server decides about packets that have already travelled down your uplink. Once the uplink is saturated, the packets of your players stop getting through before that, no matter how good your rule set is. Volumetric attacks have to end in the network in front of the server.
At what size can my server no longer handle it on its own?
A typical game server sits on 1 Gbps, which is 125 megabytes per second. Attacks against FiveM projects usually range between 5 and 50 Gbps. The packet rate matters just as much: with packets of 64 bytes, around 1.49 million packets per second fit into 1 Gbps, while a normal server kernel handles only a few hundred thousand of them. So an attack can take you down even though the bandwidth is not exhausted.
Does my server at KernelHost go offline during an attack?
No. No null-routing is used. Your IP address stays on the network, only the malicious packets are dropped. The protection has two layers: 17 Tbps of mitigation capacity in the global scrubbing network and Arbor real-time filtering with 3.2 Tbps in Frankfurt am Main. It runs permanently and does not have to react to an attack first.
Does DDoS protection at KernelHost cost extra?
No. The two-layer always-on protection is included with every server package at no surcharge and is active from provisioning onwards. You do not have to order it, switch it on or configure it.
When do I additionally need Advanced DDoS Protection?
When your project is attacked not occasionally, but deliberately and for weeks on end, and you want to steer the filtering yourself. You get a dedicated protected IP and manage the protection rules per port and protocol yourself in the customer panel, with a protection profile for FiveM. Changes take effect in real time, so you can fine-tune while an attack is running. The price starts at €50.00 per month, PrePaid, with no minimum term and no setup fee.

FiveM FiveM DDoS protection GTA V roleplay game server protection txAdmin Port 30120 Advanced DDoS Protection real-time filtering