<?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: Fredrick Anyanwu</title>
    <description>The latest articles on DEV Community by Fredrick Anyanwu (@ajebordev).</description>
    <link>https://dev.to/ajebordev</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%2F3904528%2F007fae01-42e3-49ca-a6f0-7024c5e5319e.png</url>
      <title>DEV Community: Fredrick Anyanwu</title>
      <link>https://dev.to/ajebordev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ajebordev"/>
    <language>en</language>
    <item>
      <title>Building a Real-Time HTTP Anomaly Detection Engine for Nextcloud with Python, Nginx, and iptables</title>
      <dc:creator>Fredrick Anyanwu</dc:creator>
      <pubDate>Wed, 29 Apr 2026 14:24:29 +0000</pubDate>
      <link>https://dev.to/ajebordev/building-a-real-time-http-anomaly-detection-engine-for-nextcloud-with-python-nginx-and-iptables-5770</link>
      <guid>https://dev.to/ajebordev/building-a-real-time-http-anomaly-detection-engine-for-nextcloud-with-python-nginx-and-iptables-5770</guid>
      <description>&lt;p&gt;For this project, I deployed Nextcloud behind Nginx and built a Python daemon that performs real-time anomaly detection on incoming HTTP traffic.&lt;/p&gt;

&lt;p&gt;The key requirement was to avoid static assumptions and instead learn “normal” traffic behavior continuously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack and deployment model
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;VPS: Linux (2 vCPU / 2 GB RAM minimum)&lt;/li&gt;
&lt;li&gt;Nextcloud container (provided image)&lt;/li&gt;
&lt;li&gt;Nginx reverse proxy&lt;/li&gt;
&lt;li&gt;Python detector daemon&lt;/li&gt;
&lt;li&gt;Slack Incoming Webhooks&lt;/li&gt;
&lt;li&gt;iptables for active mitigation&lt;/li&gt;
&lt;li&gt;Live dashboard (Flask)
Nginx writes JSON access logs to /var/log/nginx/hng-access.log, stored in a named Docker volume HNG-nginx-logs shared read-only with detector.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Structured logging
&lt;/h2&gt;

&lt;p&gt;Nginx access logs include at minimum:&lt;/p&gt;

&lt;p&gt;source_ip&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;timestamp&lt;/li&gt;
&lt;li&gt;method&lt;/li&gt;
&lt;li&gt;path&lt;/li&gt;
&lt;li&gt;status&lt;/li&gt;
&lt;li&gt;response_size
This simplifies parsing and keeps the detector robust under load.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sliding windows (deque-based)
&lt;/h2&gt;

&lt;p&gt;I maintain two 60-second windows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Global request timestamps&lt;/li&gt;
&lt;li&gt;Per-IP request timestamp deques
For each request:&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;append timestamp&lt;/li&gt;
&lt;li&gt;evict entries older than 60 seconds&lt;/li&gt;
&lt;li&gt;compute rate from deque length
This is a true rolling window implementation (not a minute bucket counter).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Rolling baseline implementation
&lt;/h2&gt;

&lt;p&gt;I keep a rolling 30-minute history of per-second counts and recalculate every 60 seconds.&lt;/p&gt;

&lt;p&gt;Computed metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mean request count&lt;/li&gt;
&lt;li&gt;standard deviation&lt;/li&gt;
&lt;li&gt;baseline error rate
I also maintain hourly slots and prefer current-hour baseline once that slot has sufficient points.
Floor values protect against near-zero baseline behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Detection logic
&lt;/h2&gt;

&lt;p&gt;An anomaly triggers when either condition is true:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;z_score &amp;gt; 3.0&lt;/li&gt;
&lt;li&gt;current_rate &amp;gt; 5 * baseline_mean
Error-surge path:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;if an IP’s error activity significantly exceeds baseline error behavior, per-IP thresholds are tightened automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mitigation workflow
&lt;/h2&gt;

&lt;p&gt;Per-IP anomaly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;insert firewall rule:&lt;/li&gt;
&lt;li&gt;iptables -I INPUT -s  -j DROP&lt;/li&gt;
&lt;li&gt;&lt;p&gt;send Slack BAN alert&lt;br&gt;
Global anomaly:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;send Slack GLOBAL alert&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;no broad blocking&lt;br&gt;
Unban policy (backoff):&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;10m&lt;/li&gt;
&lt;li&gt;30m&lt;/li&gt;
&lt;li&gt;2h&lt;/li&gt;
&lt;li&gt;permanent for repeated offenders
Every unban emits Slack and audit events.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Dashboard and audit trail
&lt;/h2&gt;

&lt;p&gt;Dashboard refreshes every 3 seconds and exposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;global req/s&lt;/li&gt;
&lt;li&gt;top source IPs&lt;/li&gt;
&lt;li&gt;banned IPs&lt;/li&gt;
&lt;li&gt;CPU/memory&lt;/li&gt;
&lt;li&gt;effective baseline stats&lt;/li&gt;
&lt;li&gt;uptime
Audit log format:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[timestamp] ACTION ip | condition | rate | baseline | duration&lt;/p&gt;

&lt;p&gt;Actions include: BAN, UNBAN, BASELINE, ALERT.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical outcomes
&lt;/h2&gt;

&lt;p&gt;This project demonstrates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;adaptive, data-driven detection&lt;/li&gt;
&lt;li&gt;automated mitigation with controlled unban policy&lt;/li&gt;
&lt;li&gt;full operational visibility (logs + dashboard + Slack)&lt;/li&gt;
&lt;li&gt;&lt;p&gt;production-style containerized deployment around an existing application&lt;br&gt;
Links&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Server IP: 134.209.68.49&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dashboard: (&lt;a href="http://detector.ajebodev.xyz:8080/" rel="noopener noreferrer"&gt;http://detector.ajebodev.xyz:8080/&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repository: (&lt;a href="https://github.com/fredrickray/hng-stage3-anomly-detector" rel="noopener noreferrer"&gt;https://github.com/fredrickray/hng-stage3-anomly-detector&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>python</category>
      <category>cybersecurity</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
