How to Detect a DDoS Attack on a Linux Server Using Command-Line Tools

When your Linux server experiences a sudden, massive load spike, guessing the cause is not an option. Your websites slow down, APIs time out, and even your SSH connection might begin to lag. In these critical moments, you need to know immediately whether you are dealing with a legitimate traffic surge, a misbehaving internal application, or a Distributed Denial-of-Service (DDoS) attack.

This tutorial provides a hands-on, step-by-step guide to diagnosing malicious traffic using standard Linux command-line utilities. Instead of relying purely on third-party dashboards, you will learn exactly how to use tools like netstat, ss, tcpdump, and log-parsing commands to inspect your network interfaces, analyze active TCP states, and hunt down application-layer floods in real-time.

Phase 1 Prerequisites: Install Necessary Tools

Before starting, ensure you have the required monitoring tools installed on your server. Many minimal Linux distributions do not include them by default.

For Ubuntu/Debian:

Bash
sudo apt update && sudo apt install iftop sysstat -y
    

For CentOS/RHEL-based systems (AlmaLinux, Rocky):

Bash
sudo dnf install iftop sysstat -y
    
Note: yum may still be available as a compatibility command on some older systems

Phase 2 Check Network Interface Traffic (Volumetric Attacks)

The most common form of a DDoS attack is a volumetric flood (such as a UDP flood). The attacker's goal is to completely fill your server's network pipe. Before digging into your web server logs, you should check the raw traffic hitting your network interfaces.

1. Monitor Real-Time Bandwidth with iftop

The iftop utility provides a live visual display of network traffic by IP address. Run the following command:

Bash
sudo iftop -n
    
Note: The -n flag prevents DNS resolution, which is crucial during an attack because DNS lookups will severely slow down the tool

Watch the output. If you see your bandwidth capacity completely maxed out by hundreds of random IP addresses or a few specific IPs pulling massive amounts of data, your network pipe is being saturated. Use iftop to identify which peers are consuming bandwidth, but always compare the observed traffic against your interface capacity and normal baseline.

2. Check Packets Per Second (PPS) with sar

Sometimes an attack doesn't fill your bandwidth in gigabytes, but rather overloads the network card with millions of tiny packets. You can check your Packets Per Second (PPS) using sar:

Bash
sar -n DEV 1
    

This command refreshes network stats every 1 second. Look specifically at the rxpck/s (received packets per second) column. If this number is abnormally high compared to your baseline, and you are not running backups or heavy internal data transfers, it may indicate a packet flood.

What it means: If your inbound traffic (RX) or PPS is pinned to its absolute limit, yet your server's CPU usage remains relatively normal, this behavior is consistent with a Layer 3 network-level flood (though sudden legitimate flash traffic could also be a factor).

Phase 3 Analyze Active Connections and TCP States (Protocol Attacks)

If your bandwidth is not completely saturated but legitimate users are still failing to connect, the attacker is likely targeting your server's connection-handling capacity. These are known as protocol attacks (Layer 4), and they work by exhausting the server's TCP state tables.

1. Count Total Connections by IP Address

To see if a small group of IP addresses is opening an abnormal number of connections to your server, you can parse your active TCP network connections. Run this command:

Bash
ss -H -tn | awk '{print $5}' | sed 's/:[^:]*$//' | sort | uniq -c | sort -nr | head -10
    
Note: This command is intended for common IPv4 output. In IPv6-heavy environments, the field parsing might require adjustments depending on your OS version's exact ss output format

This outputs a list of the top 10 IP addresses currently connected to your server, along with their active connection counts. Important Context: Keep in mind that high connections from a single IP do not automatically mean an attack. Modern browsers, APIs, WebSockets, NAT gateways (where many users share one IP), or reverse proxies can also maintain many legitimate connections. Evaluate this against your baseline and endpoint patterns.

2. Detect a SYN Flood Attack

A SYN flood is a classic DDoS technique where an attacker repeatedly sends initial connection requests (SYN) but never completes the TCP handshake. This leaves connections in a "half-open" state (SYN_RECV), eventually filling the server's connection queue and locking out real users.

To count exactly how many connections are stuck in the SYN_RECV state, run:

Bash
ss -H -n -t state syn-recv | wc -l
    
Note: The -H flag removes the header row so the count is exact. If this number is in the hundreds or thousands, it may indicate a SYN flood, especially when it is significantly above your normal baseline.

3. Use ss for Heavily Loaded Servers

Pro-Tip: To get a rapid summary of your current TCP states without locking up your terminal, simply type:

Bash
ss -s
    

Look at the synrecv value in the output. If it is disproportionately high compared with your normal baseline, it may indicate a SYN flood or another condition causing excessive TCP connection-state usage.

Phase 4 Inspect Web Server Access Logs (Layer 7 HTTP Floods)

If your network bandwidth looks fine and your TCP connections are stable, but your server's CPU or memory is maxed out, you might be facing an Application-layer (Layer 7) attack. HTTP floods attempt to crash your server by forcing it to process thousands of resource-intensive requests, such as database queries or complex scripts.

Note: The examples below use the default Nginx log path. For Apache, common paths include /var/log/apache2/access.log on Debian/Ubuntu and /var/log/httpd/access_log on RHEL-based systems

1. Find the Most Hammered URLs

To see which URLs are being requested the most right now, run:

Bash
tail -n 10000 /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -10
    
Note: This assumes the default/common Nginx access-log format where the request target is the 7th field. If you use a custom log_format, the field position may differ. Additionally, $7 includes the query string, so requests to /api/login?user=test and /api/login?user=admin will be counted as separate URLs

2. Identify the Top Attacking IPs via Web Logs

To extract the top 10 source IPs from your recent access logs:

Bash
tail -n 10000 /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -10
    

3. Watch Traffic in Real-Time

To watch the traffic unfold live and spot patterns, use the tail command:

Bash
 tail -f /var/log/nginx/access.log
    

What it means: If you see a massive stream of requests hitting the exact same URL, bypassing cache, and originating from unknown IPs or suspicious User-Agents, it strongly points towards an automated HTTP flood. However, always ensure you rule out aggressive legitimate bots, monitoring systems, or API clients which can also generate repetitive traffic.

Phase 5 Capture Packets for Deep Analysis (Advanced)

Sometimes, application logs and connection tables do not give you the full picture. You can inspect the raw packets hitting your network interface using tcpdump:

Bash
sudo tcpdump -i eth0 -n -c 1000
    

(Replace eth0 with your primary network interface).

  • -n: Disables DNS resolution to keep the output fast.
  • -c 1000: Captures exactly 1,000 packets and stops. (Never run tcpdump without a limit during a DDoS attack).

What it means: Look at the captured packet output. It can help you identify traffic patterns associated with an attack, such as unusual packet rates, TCP flags, destination ports, or highly concentrated source distributions. (Note: packet length alone isn't enough to confirm an attack; you must analyze protocol, flags, and source distribution together).

Phase 6 You Suspect a DDoS Attack. What Now?

Once the observed traffic patterns are consistent with a DDoS attack, you can begin mitigation to stabilize your server.

1. Apply Immediate Local Mitigations

If the attack is originating from a small group of IP addresses, you can apply temporary rules:

Block specific attacking IPs using iptables:

Bash
sudo iptables -A INPUT -s ATTACKER_IP -j DROP
    
Note: On modern distributions like Ubuntu or RHEL, iptables might be a compatibility layer. You can use your OS's native firewall tool like ufw, nftables, or firewalld if preferred

Enable TCP SYN Cookies:

Bash
sudo sysctl -w net.ipv4.tcp_syncookies=1
    

(While useful for mitigating TCP state exhaustion during a SYN flood, remember this is not a complete solution. It won't stop the traffic from reaching and potentially saturating your server's network capacity).

Rate-limit HTTP requests: Add a limit_req_zone directive to your Nginx configuration to throttle excessive requests.

2. Understand the Limits of Local Server Defense

While commands like iptables or local firewalls are useful for blocking small-scale or targeted attacks, a software firewall on your server cannot stop a volumetric DDoS attack. If an attacker sends a 50Gbps flood to your 1Gbps interface, dropping packets at the OS level still means the pipe is clogged.

3. Move Defense Upstream with DDoS Protection

To survive large-scale volumetric or complex multi-vector DDoS attacks, malicious traffic must be filtered before it ever reaches your server. Consider upstream traffic scrubbing or migrating to DDoS Protected Dedicated Servers that feature always-on, high-capacity network-level mitigation.

What to Read Next

Ready to take your server security to the next level? Check out our related guides:

╰┈➤ Server Load Spiking? How to Identify a DDoS Attack
╰┈➤ 15 Essential Steps to Secure a New Linux Dedicated Server