<?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>Forem: Opatola Bolaji Prince</title>
    <description>The latest articles on Forem by Opatola Bolaji Prince (@prince27).</description>
    <link>https://forem.com/prince27</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%2F1200766%2F5acdc290-f042-4027-9d74-7a64cd99344f.png</url>
      <title>Forem: Opatola Bolaji Prince</title>
      <link>https://forem.com/prince27</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/prince27"/>
    <language>en</language>
    <item>
      <title>Building a Smart Security Guard for Your Server 🛡️</title>
      <dc:creator>Opatola Bolaji Prince</dc:creator>
      <pubDate>Tue, 28 Apr 2026 17:12:25 +0000</pubDate>
      <link>https://forem.com/prince27/building-a-smart-security-guard-for-your-server-3c6i</link>
      <guid>https://forem.com/prince27/building-a-smart-security-guard-for-your-server-3c6i</guid>
      <description>&lt;p&gt;This project is part of the HNG DevOps internship (Stage 3), and trust me, it sounds way more complicated than it actually is. Let's break it down together.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Are We Building?
&lt;/h2&gt;

&lt;p&gt;Think of it like hiring a smart security guard for your website who:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Watches the door&lt;/strong&gt; - Keeps track of everyone visiting your site&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learns the pattern&lt;/strong&gt; - Figures out what "normal" traffic looks like&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spots the troublemakers&lt;/strong&gt; - Detects when something fishy is happening&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Takes action&lt;/strong&gt; - Blocks suspicious visitors automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sends you alerts&lt;/strong&gt; - Notifies you on Slack when there's trouble&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shows a dashboard&lt;/strong&gt; - Gives you a live view of what's happening&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cool, right? Let's see how it all works!&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding the Key Concepts (No Jargon, I Promise!)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The Sliding Window (Think: Security Camera Footage)
&lt;/h3&gt;

&lt;p&gt;Imagine you have a camera recording your front door. Instead of keeping all footage forever, you only keep the last 60 seconds. When a new second is recorded, the oldest one gets deleted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In our system:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We track how many people visited in the last 60 seconds&lt;/li&gt;
&lt;li&gt;Every second, we add new data and remove the oldest&lt;/li&gt;
&lt;li&gt;This gives us a "rolling" view of recent activity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why is this useful?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It helps us spot sudden spikes in traffic that might indicate an attack!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Simple example (Python makes this easy!)
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;

&lt;span class="c1"&gt;# This automatically keeps only the last 60 items
&lt;/span&gt;&lt;span class="n"&gt;recent_traffic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxlen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Every second, we add new data
&lt;/span&gt;&lt;span class="n"&gt;recent_traffic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_visitors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Old data automatically disappears!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. The Baseline (Your "Normal" Traffic Pattern)
&lt;/h3&gt;

&lt;p&gt;Your baseline is like knowing your daily routine. If you usually get 10-15 visitors per second, that's your "normal."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How we calculate it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Watch traffic for 30 minutes&lt;/li&gt;
&lt;li&gt;Calculate the average (mean)&lt;/li&gt;
&lt;li&gt;Calculate how much it varies (standard deviation)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Normal traffic: 13 visitors/second ± 2&lt;/li&gt;
&lt;li&gt;This means 11-15 is totally normal&lt;/li&gt;
&lt;li&gt;But 50 visitors/second? That's suspicious!
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt;

&lt;span class="c1"&gt;# Collect 30 minutes of data
&lt;/span&gt;&lt;span class="n"&gt;traffic_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...]&lt;/span&gt;

&lt;span class="c1"&gt;# Calculate your "normal"
&lt;/span&gt;&lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;traffic_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Example: 13.5
&lt;/span&gt;&lt;span class="n"&gt;variation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stdev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;traffic_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Example: 2.1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. The Z-Score (How Weird is This Traffic?)
&lt;/h3&gt;

&lt;p&gt;The z-score is just a fancy way of asking: "How unusual is this compared to normal?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple formula:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;z-score = (current traffic - normal traffic) / variation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it means:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Z-score of 0 = Perfectly normal&lt;/li&gt;
&lt;li&gt;Z-score of 1-2 = A bit high, but okay&lt;/li&gt;
&lt;li&gt;Z-score of 3+ = &lt;strong&gt;ALERT! Something's wrong!&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;normal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;13.5&lt;/span&gt; &lt;span class="n"&gt;visitors&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;second&lt;/span&gt;
&lt;span class="n"&gt;variation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.1&lt;/span&gt;
&lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="n"&gt;visitors&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;second&lt;/span&gt;

&lt;span class="n"&gt;z_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;13.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;2.1&lt;/span&gt;
&lt;span class="c1"&gt;# Result: 7.86 — Definitely an attack!
&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;z_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🚨 ATTACK DETECTED!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. The 5x Rule (Backup Check)
&lt;/h3&gt;

&lt;p&gt;Sometimes the z-score isn't enough. The 5x rule is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If traffic is &lt;strong&gt;5 times higher&lt;/strong&gt; than normal, it's an attack — no matter what!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; If you normally get 2 visitors/second, even 10 might not trigger the z-score, but it's still 5x your normal traffic!&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting Up Your Project
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What You'll Need
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A Google Cloud account&lt;/strong&gt; (free tier works!)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Slack account&lt;/strong&gt; (to receive alerts)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Basic knowledge of:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Running commands in terminal&lt;/li&gt;
&lt;li&gt;What Docker is (even just a basic idea)&lt;/li&gt;
&lt;li&gt;Python basics (if statements, loops)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 1: Create Your Cloud Server
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://console.cloud.google.com" rel="noopener noreferrer"&gt;Google Cloud Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create a new VM (virtual machine):

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;hng-stage3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; e2-medium (2 CPU, 4GB RAM)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disk:&lt;/strong&gt; Ubuntu 22.04 LTS, 20GB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firewall:&lt;/strong&gt; Allow HTTP and HTTPS traffic&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click "Create" and wait a minute&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Don't forget:&lt;/strong&gt; Open port 8080 for your dashboard!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to VPC Network → Firewall&lt;/li&gt;
&lt;li&gt;Create a new rule called &lt;code&gt;allow-dashboard-8080&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Allow TCP port 8080 from anywhere (0.0.0.0/0)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Step 2: Connect to Your Server
&lt;/h3&gt;

&lt;p&gt;Click the "SSH" button next to your VM in Google Cloud Console. A terminal will open — this is where the magic happens!&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 3: Install the Tools
&lt;/h3&gt;

&lt;p&gt;Run these commands one by one:&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;# Update your system&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Install Docker (the easy way!)&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://get.docker.com &lt;span class="nt"&gt;-o&lt;/span&gt; get-docker.sh
&lt;span class="nb"&gt;sudo &lt;/span&gt;sh get-docker.sh

&lt;span class="c"&gt;# Install Docker Compose&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;docker-compose &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Install Python&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python3 python3-pip git &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Create your project folder&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/hng-stage3
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/hng-stage3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congrats! Your server is ready! 🎉&lt;/p&gt;




&lt;h2&gt;
  
  
  Building the Detection System
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Project Structure
&lt;/h3&gt;

&lt;p&gt;Here's how we'll organize everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hng-stage3/
├── docker-compose.yml          # Starts all our services
├── nginx/
│   └── nginx.conf              # Web server config
├── detector/
│   ├── main.py                 # Main program
│   ├── monitor.py              # Watches the logs
│   ├── baseline.py             # Calculates "normal"
│   ├── detector.py             # Spots attacks
│   ├── blocker.py              # Blocks bad IPs
│   ├── notifier.py             # Sends Slack alerts
│   ├── dashboard.py            # Web dashboard
│   ├── config.yaml             # Your settings
│   └── requirements.txt        # Python packages needed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Core Logic (In Plain English!)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Monitor the Traffic (monitor.py)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This script watches your web server logs and counts visitors every second.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Every second, check how many people visited
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;count_visitors&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Read the log file
&lt;/span&gt;    &lt;span class="c1"&gt;# Count new entries
&lt;/span&gt;    &lt;span class="c1"&gt;# Return the number
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;visitor_count&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Learn What's Normal (baseline.py)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After collecting data for 30 minutes, calculate your baseline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_baseline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Calculate how much traffic varies
&lt;/span&gt;    &lt;span class="n"&gt;variation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_standard_deviation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mean&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;average&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stddev&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;variation&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Detect Attacks (detector.py)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Compare current traffic to your baseline using the z-score.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_attack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_traffic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;baseline&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;z_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_traffic&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;baseline&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mean&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;baseline&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stddev&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Check z-score rule
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;z_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="c1"&gt;# Check 5x rule
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_traffic&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;baseline&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mean&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Block the Attacker (blocker.py)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;iptables&lt;/code&gt; (a firewall tool) to block the bad IP address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;block_ip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Add firewall rule to block this IP
&lt;/span&gt;    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iptables -A INPUT -s &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -j DROP&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🚫 Blocked &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Send an Alert (notifier.py)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Post a message to Slack so you know what's happening.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_slack_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;webhook_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_SLACK_WEBHOOK_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webhook_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Testing Your System
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Let It Learn (5-10 minutes)
&lt;/h3&gt;

&lt;p&gt;Generate some normal traffic so the system can build a baseline:&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 the testing tool&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;apache2-utils &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Send normal traffic (10 requests/second for 60 seconds)&lt;/span&gt;
ab &lt;span class="nt"&gt;-n&lt;/span&gt; 600 &lt;span class="nt"&gt;-c&lt;/span&gt; 1 &lt;span class="nt"&gt;-t&lt;/span&gt; 60 http://localhost/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch your detector logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs hng-detector &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see it learning and updating the baseline!&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 2: Simulate an Attack
&lt;/h3&gt;

&lt;p&gt;Now let's test if it can detect attacks:&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;# Send 100 requests/second for 60 seconds&lt;/span&gt;
ab &lt;span class="nt"&gt;-n&lt;/span&gt; 6000 &lt;span class="nt"&gt;-c&lt;/span&gt; 10 &lt;span class="nt"&gt;-t&lt;/span&gt; 60 http://localhost/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What should happen:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Detector spots the unusual traffic&lt;/li&gt;
&lt;li&gt; Calculates a high z-score&lt;/li&gt;
&lt;li&gt; Blocks the IP address&lt;/li&gt;
&lt;li&gt; Sends you a Slack alert&lt;/li&gt;
&lt;li&gt; Shows the attack on your dashboard&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you see all of this, you did it! 🎊&lt;/p&gt;




&lt;h2&gt;
  
  
  The Dashboard
&lt;/h2&gt;

&lt;p&gt;Your dashboard runs on port 8080 and shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Live traffic graph&lt;/strong&gt; - See requests per second&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Baseline tracker&lt;/strong&gt; - Your "normal" traffic pattern&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Recent alerts&lt;/strong&gt; - What attacks were detected&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Blocked IPs&lt;/strong&gt; - Who's been banned&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Problems (And How to Fix Them)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problem 1: "My logs are empty!"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&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;# Make sure the web server is running&lt;/span&gt;
docker ps

&lt;span class="c"&gt;# Test by visiting your site&lt;/span&gt;
curl http://localhost/

&lt;span class="c"&gt;# Check if logs are being created&lt;/span&gt;
docker &lt;span class="nb"&gt;exec &lt;/span&gt;hng-nginx &lt;span class="nb"&gt;tail&lt;/span&gt; /var/log/nginx/hng-access.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Problem 2: "The detector isn't blocking anything!"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&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;# Make sure the detector has permission to use the firewall&lt;/span&gt;
docker inspect hng-detector | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; privileged
&lt;span class="c"&gt;# Should show: "Privileged": true&lt;/span&gt;

&lt;span class="c"&gt;# If not, add this to your docker-compose.yml:&lt;/span&gt;
&lt;span class="c"&gt;# privileged: true&lt;/span&gt;
&lt;span class="c"&gt;# network_mode: "host"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Problem 3: "Dashboard won't load!"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&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;# Check if the port is open on GCP&lt;/span&gt;
&lt;span class="c"&gt;# Go to: VPC Network → Firewall → allow-dashboard-8080&lt;/span&gt;

&lt;span class="c"&gt;# Test from your computer:&lt;/span&gt;
curl http://YOUR_SERVER_IP:8080/api/metrics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Building this project taught me:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;How real security systems work&lt;/strong&gt; - It's not magic, just math!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The power of baselines&lt;/strong&gt; - Understanding "normal" helps you spot "abnormal"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why automation matters&lt;/strong&gt; - Blocking attacks manually would be impossible&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker makes deployment easy&lt;/strong&gt; - Everything runs in containers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring is crucial&lt;/strong&gt; - You can't fix what you can't see&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Start simple&lt;/strong&gt; - Build one piece at a time&lt;br&gt;&lt;br&gt;
 &lt;strong&gt;Test frequently&lt;/strong&gt; - Don't wait until the end to test&lt;br&gt;&lt;br&gt;
 &lt;strong&gt;Learn the concepts&lt;/strong&gt; - Understanding why &amp;gt; memorizing code&lt;br&gt;&lt;br&gt;
 &lt;strong&gt;Use tools wisely&lt;/strong&gt; - Python and Docker handle the heavy lifting&lt;br&gt;&lt;br&gt;
 &lt;strong&gt;Monitor everything&lt;/strong&gt; - Logs are your best friend  &lt;/p&gt;







&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐍 &lt;a href="https://docs.python.org/3/" rel="noopener noreferrer"&gt;Python Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🐳 &lt;a href="https://docs.docker.com/get-started/" rel="noopener noreferrer"&gt;Docker Getting Started&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔔 &lt;a href="https://api.slack.com/messaging/webhooks" rel="noopener noreferrer"&gt;Slack Webhooks Guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Good luck, and happy coding! 🚀&lt;/p&gt;




&lt;p&gt;&lt;em&gt;P.S. If you found this helpful, give it a ❤️ and follow me for more DevOps tutorials!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>monitoring</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Case Study: Deploying a Full-Stack MERN Application on AWS EC2 Using Docker &amp; GitHub Actions</title>
      <dc:creator>Opatola Bolaji Prince</dc:creator>
      <pubDate>Wed, 29 Oct 2025 12:54:37 +0000</pubDate>
      <link>https://forem.com/prince27/case-study-deploying-a-full-stack-mern-application-on-aws-ec2-using-docker-github-actions-4ea4</link>
      <guid>https://forem.com/prince27/case-study-deploying-a-full-stack-mern-application-on-aws-ec2-using-docker-github-actions-4ea4</guid>
      <description>&lt;p&gt;If you’ve ever built a full-stack app and asked yourself:&lt;/p&gt;

&lt;p&gt;“How do I deploy this professionally in production with DevOps best practices?”&lt;/p&gt;

&lt;p&gt;This case study walks through exactly how I achieved that — step-by-step — including the challenges, mistakes, and real fixes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Overview&lt;/strong&gt;  I built and deployed a production-grade full-stack note-taking application called Notify.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technologies involved:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React + Vite for the frontend&lt;/li&gt;
&lt;li&gt;Node.js + Express for the backend&lt;/li&gt;
&lt;li&gt;MongoDB as the database&lt;/li&gt;
&lt;li&gt;Docker &amp;amp; Docker Compose for containerization&lt;/li&gt;
&lt;li&gt;AWS EC2 for hosting&lt;/li&gt;
&lt;li&gt;GitHub Actions CI/CD for automated deployment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The goal:&lt;/strong&gt;  Push code → App auto-deploys to AWS → No manual server changes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Phase 1 — Dockerizing the MERN Application
The first step was packaging each part of the application into its own container.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Backend Dockerfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5000
CMD ["npm", "start"]

Frontend Dockerfile
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend is built and then served using Nginx — making it production-ready.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Phase 2 — Docker Compose for Multi-Service Orchestration
To run all three containers together and ensure they communicate properly:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  mongo:
    image: mongo:6
    container_name: mongo-db
    ports:
      - "27017:27017"
    restart: always

  backend:
    build: ./backend
    env_file: ./backend/.env
    environment:
      - MONGODB_URI=mongodb://mongo:27017/notifydb
    ports:
      - "5000:5000"
    depends_on:
      - mongo

  frontend:
    build: ./frontend
    ports:
      - "80:80"
    depends_on:
      - backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt;&lt;br&gt;
 The backend connects to MongoDB using the container name mongo, not localhost.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Phase 3 — Deploying to AWS EC2&lt;br&gt;
I launched an Amazon Linux 2023 EC2 instance and prepared it for containerized deployment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installed Docker&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installed Docker Compose&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Added ec2-user to Docker group&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security groups configured correctly&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Opened inbound ports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;80 → Web traffic&lt;/li&gt;
&lt;li&gt;5000 → Backend API&lt;/li&gt;
&lt;li&gt;22 → SSH Access&lt;/li&gt;
&lt;li&gt;Then deployed:&lt;/li&gt;
&lt;li&gt;git clone &lt;a href="https://github.com/emperorbj/notify.git" rel="noopener noreferrer"&gt;https://github.com/emperorbj/notify.git&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;cd notify&lt;/li&gt;
&lt;li&gt;docker compose up -d --build&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎉 Site instantly reachable via:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Phase 4 — Enabling CI/CD With GitHub Actions
The goal was zero manual deployments after setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📌 Every time I push to main:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; EC2 pulls new code&lt;/li&gt;
&lt;li&gt; Docker rebuilds&lt;/li&gt;
&lt;li&gt; Containers restart automatically&lt;/li&gt;
&lt;li&gt; Old images removed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GitHub Actions workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Deploy to EC2

on:
  push:
    branches: ["main"]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: SSH Agent
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Add Known Hosts
        run: ssh-keyscan -H ${{ secrets.EC2_HOST }} &amp;gt;&amp;gt; ~/.ssh/known_hosts

      - name: Deploy Over SSH
        run: |
          ssh ec2-user@${{ secrets.EC2_HOST }} &amp;lt;&amp;lt; 'EOF'
            cd ~/notify
            git pull origin main
            docker compose down || true
            docker compose up -d --build
            docker image prune -f
          EOF

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real-World Problems I Had to Solve&lt;/strong&gt; &lt;br&gt;
This wasn’t smooth — and that’s exactly the valuable part.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Problems + Fixes:
Backend couldn’t connect to MongoDB → switched URI to container name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deployment failing due to wrong Docker version → updated Docker + enabled compose&lt;/p&gt;

&lt;p&gt;Frontend wouldn’t load → exposed port 80, not Vite’s local 5173&lt;/p&gt;

&lt;p&gt;SSH denied → fixed key pairing and GitHub secrets&lt;/p&gt;

&lt;p&gt;Docker commands failing → added EC2 user to Docker group&lt;/p&gt;

&lt;p&gt;Every issue taught me lessons developers don’t learn until production ✨&lt;/p&gt;

&lt;p&gt;You can watch the process here :&lt;br&gt;
&lt;a href="https://www.loom.com/share/897f49af1b274e3fba6921c842d0653b" rel="noopener noreferrer"&gt;https://www.loom.com/share/897f49af1b274e3fba6921c842d0653b&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎯 What This Project Proved&lt;/p&gt;

&lt;p&gt;I now understand:&lt;/p&gt;

&lt;p&gt;🔥 Container orchestration with Docker&lt;br&gt;
🔥 Cloud deployment using AWS EC2&lt;br&gt;
🔥 Networking between services in production&lt;br&gt;
🔥 Continuous Deployment pipelines&lt;br&gt;
🔥 Debugging real infrastructure failures&lt;/p&gt;

&lt;p&gt;This project took me from “I can code this” to:&lt;/p&gt;

&lt;p&gt;✅ “I can run this in production — automatically.”&lt;/p&gt;

&lt;p&gt;✅ Final Result ✅&lt;/p&gt;

&lt;p&gt;✔ Full MERN App running live on AWS&lt;br&gt;
✔ 100% Dockerized microservices&lt;br&gt;
✔ Push-to-deploy automation&lt;br&gt;
✔ Secure, scalable architecture&lt;br&gt;
✔ Excellent DevOps experience gained&lt;/p&gt;

&lt;p&gt;This is now a foundation I can reuse for multiple future projects&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>docker</category>
      <category>devops</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
