<?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: Alexin</title>
    <description>The latest articles on Forem by Alexin (@alexindevs).</description>
    <link>https://forem.com/alexindevs</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%2F1417302%2Fb0e198e0-7738-4bdc-8f8a-30a95b996982.jpeg</url>
      <title>Forem: Alexin</title>
      <link>https://forem.com/alexindevs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/alexindevs"/>
    <language>en</language>
    <item>
      <title>How I Built My First Production-Grade AWS Infrastructure (And Almost Lost My Mind)</title>
      <dc:creator>Alexin</dc:creator>
      <pubDate>Sun, 15 Feb 2026 11:45:45 +0000</pubDate>
      <link>https://forem.com/alexindevs/how-i-built-my-first-production-grade-aws-infrastructure-and-almost-lost-my-mind-neh</link>
      <guid>https://forem.com/alexindevs/how-i-built-my-first-production-grade-aws-infrastructure-and-almost-lost-my-mind-neh</guid>
      <description>&lt;p&gt;&lt;em&gt;A brutally honest walkthrough of my AltSchool Cloud Engineering exam project&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Assignment That Humbled Me
&lt;/h2&gt;

&lt;p&gt;I'm a student at AltSchool Africa studying Cloud Engineering, and for our semester 2 exam, we got this assignment where we had to roleplay as a Junior Cloud Engineer hired by a company. The task? Deploy a secure, highly available web application on AWS.&lt;/p&gt;

&lt;p&gt;I thought "how hard could it be?" &lt;/p&gt;

&lt;p&gt;Spoiler alert: Pretty hard.&lt;/p&gt;

&lt;p&gt;But I learned more in those two days than I did in weeks of watching tutorials. This is my story of building real cloud infrastructure, breaking things, fixing them, breaking them again, and eventually getting it right.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Had to Build
&lt;/h2&gt;

&lt;p&gt;The assignment was clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 Bastion Host in a public subnet&lt;/li&gt;
&lt;li&gt;2 Web Servers in a private subnet (NO public IPs)&lt;/li&gt;
&lt;li&gt;Everything automated with Ansible&lt;/li&gt;
&lt;li&gt;An Application Load Balancer distributing traffic&lt;/li&gt;
&lt;li&gt;All access through the load balancer only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The catch? Web servers couldn't be directly accessible from the internet. Everything had to go through proper security layers.&lt;/p&gt;

&lt;p&gt;Here's what I ended up building:&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%2Fojlv2xpiiolkaqrgitu4.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%2Fojlv2xpiiolkaqrgitu4.png" alt="Architecture Diagram" width="800" height="825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Day 1: "This Should Be Easy"
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Starting with Security Groups
&lt;/h3&gt;

&lt;p&gt;I started by creating security groups because I figured I'd need those first. Three of them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;bastion-sg&lt;/strong&gt; - For my jump box&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow SSH from my IP&lt;/li&gt;
&lt;li&gt;That's it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;webserver-sg&lt;/strong&gt; - For the application servers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow SSH from bastion-sg only&lt;/li&gt;
&lt;li&gt;Allow HTTP from alb-sg only&lt;/li&gt;
&lt;li&gt;No direct access from internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;alb-sg&lt;/strong&gt; - For the load balancer&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow HTTP from anywhere (0.0.0.0/0)&lt;/li&gt;
&lt;li&gt;This is the only thing exposed to the internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This part actually went smoothly. I was feeling confident. Too confident.&lt;/p&gt;

&lt;h3&gt;
  
  
  Launching EC2 Instances
&lt;/h3&gt;

&lt;p&gt;Next up: spinning up instances. I created an SSH key pair (saved it as &lt;code&gt;cloud-assignment-key.pem&lt;/code&gt;) and launched:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bastion Host&lt;/strong&gt; - Ubuntu 24.04, t2.micro, in a public subnet with a public IP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web-Server-1&lt;/strong&gt; - Ubuntu 24.04, t2.micro, NO public IP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web-Server-2&lt;/strong&gt; - Ubuntu 24.04, t2.micro, NO public IP&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's where I made my first mistake: I put all three instances in the same subnet. I didn't think about the fact that a subnet is either public OR private, not both. This came back to bite me later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up SSH Access
&lt;/h3&gt;

&lt;p&gt;I tested SSH to the Bastion - worked fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/cloud-assignment-key.pem ubuntu@&amp;lt;bastion-public-ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But I needed to access the web servers through the Bastion. This is where ProxyJump saved my life. I created an SSH config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host bastion
    HostName &amp;lt;BASTION_PUBLIC_IP&amp;gt;
    User ubuntu
    IdentityFile ~/.ssh/cloud-assignment-key.pem
    ForwardAgent yes
    StrictHostKeyChecking no

Host webserver1
    HostName &amp;lt;WEB_SERVER_1_PRIVATE_IP&amp;gt;
    User ubuntu
    IdentityFile ~/.ssh/cloud-assignment-key.pem
    ProxyJump bastion
    StrictHostKeyChecking no

Host webserver2
    HostName &amp;lt;WEB_SERVER_2_PRIVATE_IP&amp;gt;
    User ubuntu
    IdentityFile ~/.ssh/cloud-assignment-key.pem
    ProxyJump bastion
    StrictHostKeyChecking no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I could just type &lt;code&gt;ssh webserver1&lt;/code&gt; and it would automatically jump through the Bastion. Magic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Day 1 Evening: The Ansible Disaster
&lt;/h2&gt;

&lt;p&gt;Okay, time for automation. I installed Ansible on my laptop and created an inventory 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;[webservers]&lt;/span&gt;
&lt;span class="err"&gt;webserver1&lt;/span&gt; &lt;span class="py"&gt;ansible_host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;172.31.x.x&lt;/span&gt;
&lt;span class="err"&gt;webserver2&lt;/span&gt; &lt;span class="py"&gt;ansible_host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;172.31.y.y&lt;/span&gt;

&lt;span class="nn"&gt;[webservers:vars]&lt;/span&gt;
&lt;span class="py"&gt;ansible_user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ubuntu&lt;/span&gt;
&lt;span class="py"&gt;ansible_ssh_private_key_file&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;~/.ssh/cloud-assignment-key.pem&lt;/span&gt;
&lt;span class="py"&gt;ansible_ssh_common_args&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'-o StrictHostKeyChecking=no -o ProxyJump=bastion'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tested connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible webservers &lt;span class="nt"&gt;-i&lt;/span&gt; inventory.ini &lt;span class="nt"&gt;-m&lt;/span&gt; ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Success! Both servers responded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;webserver1 | SUCCESS
webserver2 | SUCCESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, I thought. Time to run the actual playbook. Here's what it looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Web Application&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webservers&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;
  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update apt cache&lt;/span&gt;
      &lt;span class="na"&gt;apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;update_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;
        &lt;span class="na"&gt;cache_valid_time&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3600&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install NGINX&lt;/span&gt;
      &lt;span class="na"&gt;apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;present&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Start and enable NGINX&lt;/span&gt;
      &lt;span class="na"&gt;systemd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;started&lt;/span&gt;
        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get instance hostname&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hostname&lt;/span&gt;
      &lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;instance_hostname&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get private IP&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hostname -I | awk '{print $1}'&lt;/span&gt;
      &lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;private_ip&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy custom HTML page&lt;/span&gt;
      &lt;span class="na"&gt;copy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/www/html/index.html&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;html lang='en'&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;meta charset='UTF-8'&amp;gt;&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;title&amp;gt;Cloud Assignment - Alexin&amp;lt;/title&amp;gt;&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;body {&lt;/span&gt;
                      &lt;span class="s"&gt;font-family: 'Segoe UI', sans-serif;&lt;/span&gt;
                      &lt;span class="s"&gt;max-width: 800px;&lt;/span&gt;
                      &lt;span class="s"&gt;margin: 50px auto;&lt;/span&gt;
                      &lt;span class="s"&gt;padding: 20px;&lt;/span&gt;
                      &lt;span class="s"&gt;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);&lt;/span&gt;
                      &lt;span class="s"&gt;color: white;&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                  &lt;span class="s"&gt;.container {&lt;/span&gt;
                      &lt;span class="s"&gt;background: rgba(255, 255, 255, 0.1);&lt;/span&gt;
                      &lt;span class="s"&gt;padding: 40px;&lt;/span&gt;
                      &lt;span class="s"&gt;border-radius: 15px;&lt;/span&gt;
                      &lt;span class="s"&gt;backdrop-filter: blur(10px);&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                  &lt;span class="s"&gt;.info { &lt;/span&gt;
                      &lt;span class="s"&gt;background: rgba(255, 255, 255, 0.2); &lt;/span&gt;
                      &lt;span class="s"&gt;padding: 15px; &lt;/span&gt;
                      &lt;span class="s"&gt;border-radius: 8px; &lt;/span&gt;
                      &lt;span class="s"&gt;margin: 20px 0; &lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;div class='container'&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;&amp;lt;h1&amp;gt;🚀 Cloud Assignment&amp;lt;/h1&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;&amp;lt;div class='info'&amp;gt;&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Name:&amp;lt;/strong&amp;gt; Alexin&amp;lt;/p&amp;gt;&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Instance:&amp;lt;/strong&amp;gt; {{ instance_hostname.stdout }}&amp;lt;/p&amp;gt;&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Private IP:&amp;lt;/strong&amp;gt; {{ private_ip.stdout }}&amp;lt;/p&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;&amp;lt;div class='about'&amp;gt;&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;lt;h2&amp;gt;About Me&amp;lt;/h2&amp;gt;&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;lt;p&amp;gt;Backend engineer from Lagos, Nigeria. This was deployed with &lt;/span&gt;
                      &lt;span class="s"&gt;Ansible through a Bastion Host to demonstrate Infrastructure as Code.&amp;lt;/p&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0644'&lt;/span&gt;
      &lt;span class="na"&gt;notify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Restart NGINX&lt;/span&gt;

  &lt;span class="na"&gt;handlers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Restart NGINX&lt;/span&gt;
      &lt;span class="na"&gt;systemd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;restarted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ran it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible-playbook &lt;span class="nt"&gt;-i&lt;/span&gt; inventory.ini deploy-webserver.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IT FAILED.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The playbook started running, got to the "Install NGINX" task, and just... timed out. Connection errors everywhere. The servers were reachable via SSH, Ansible could ping them, but they couldn't download anything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TASK [Install NGINX] *****
fatal: [webserver1]: FAILED! =&amp;gt; {"changed": false, "msg": "Failed to update apt cache"}
fatal: [webserver2]: FAILED! =&amp;gt; {"changed": false, "msg": "Failed to update apt cache"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I spent an hour debugging this. Turns out my web servers couldn't reach the internet to download packages. They could talk to Ansible (via the Bastion), but they couldn't reach Ubuntu's package repositories.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Internet Access Problem
&lt;/h3&gt;

&lt;p&gt;Here's what I learned the hard way: My servers needed internet access to run &lt;code&gt;apt update&lt;/code&gt; and &lt;code&gt;apt install nginx&lt;/code&gt;. They were technically reachable via SSH, but they couldn't initiate outbound connections to the internet.&lt;/p&gt;

&lt;p&gt;The proper solution? &lt;strong&gt;NAT Gateway&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But I was already tired and the deadline was approaching, so I did a "quick fix": I kept everything in the same public subnet (with Internet Gateway access) so the servers could download packages. Not best practice, but it worked for getting Ansible running.&lt;/p&gt;

&lt;p&gt;After that fix, the playbook ran perfectly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PLAY RECAP *****
webserver1: ok=8 changed=6 unreachable=0 failed=0
webserver2: ok=8 changed=6 unreachable=0 failed=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both servers configured in under 2 minutes. This is when I understood why everyone talks about automation - imagine doing this manually on 10 or 100 servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Ansible Changed Everything
&lt;/h2&gt;

&lt;p&gt;Before this project, I'd always SSH'd into servers and ran commands manually. Copy-paste from StackOverflow, hope it works, repeat on the next server.&lt;/p&gt;

&lt;p&gt;Ansible made me realize:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt; - Both servers got the EXACT same config&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt; - 2 minutes vs 30 minutes of manual work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt; - My playbook IS my documentation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeatability&lt;/strong&gt; - I can run it again tomorrow and get the same result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The playbook grabs the hostname and private IP dynamically with shell commands, then injects them into the HTML template. Each server shows different info, proving load balancing works later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Day 2: Load Balancer Time
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating the Target Group
&lt;/h3&gt;

&lt;p&gt;First, I created a target group:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;webserver-tg&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Protocol: HTTP, Port: 80&lt;/li&gt;
&lt;li&gt;Registered both web servers&lt;/li&gt;
&lt;li&gt;Health checks: HTTP GET to /&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Creating the ALB
&lt;/h3&gt;

&lt;p&gt;Then the Application Load Balancer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;web-app-alb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Internet-facing&lt;/li&gt;
&lt;li&gt;Selected multiple availability zones&lt;/li&gt;
&lt;li&gt;Security group: alb-sg&lt;/li&gt;
&lt;li&gt;Forwarded traffic to: webserver-tg&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Waited for health checks... and both targets went healthy! &lt;/p&gt;

&lt;p&gt;Accessed the ALB DNS name in my browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://web-app-alb-xxxxxxxxx.eu-north-1.elb.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IT WORKED!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But I noticed it kept showing the same server. Turns out that's normal - it's called "sticky sessions". The load balancer keeps you on the same server for consistency. I verified it was actually load balancing by using curl:&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="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;1..10&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;curl http://alb-dns-name | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Instance:"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And boom - I saw both server hostnames appearing. Load balancing confirmed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Bastion Host?
&lt;/h2&gt;

&lt;p&gt;At first, I didn't get why we needed a Bastion Host. Why not just SSH directly to the servers?&lt;/p&gt;

&lt;p&gt;Here's what I learned:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without Bastion (Bad):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every server exposed to the internet&lt;/li&gt;
&lt;li&gt;More attack surface&lt;/li&gt;
&lt;li&gt;Hard to control who accesses what&lt;/li&gt;
&lt;li&gt;Each server needs its own public IP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;With Bastion (Good):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only ONE server exposed to internet&lt;/li&gt;
&lt;li&gt;Single point of entry I can monitor and secure&lt;/li&gt;
&lt;li&gt;Web servers hidden in private subnet&lt;/li&gt;
&lt;li&gt;I can log every SSH session&lt;/li&gt;
&lt;li&gt;If someone compromises the Bastion, web servers are still protected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real companies use this because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compliance&lt;/strong&gt; - Many regulations require it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; - Defense in depth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auditing&lt;/strong&gt; - Know who accessed what and when&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Bastion is like a security checkpoint. Everything goes through it, nothing bypasses it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Balancer vs Direct Access: Why It Matters
&lt;/h2&gt;

&lt;p&gt;When I started, I thought "why not just give each server a public IP and call it a day?"&lt;/p&gt;

&lt;p&gt;Here's why that's a terrible idea:&lt;/p&gt;

&lt;h3&gt;
  
  
  Direct EC2 Access (What NOT to Do):
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single Point of Failure&lt;/strong&gt; - Server goes down? Your app is offline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Failover&lt;/strong&gt; - Users get errors until you manually fix it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Risk&lt;/strong&gt; - Servers exposed directly to attacks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hard to Scale&lt;/strong&gt; - Adding servers means changing DNS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Health Checks&lt;/strong&gt; - You won't know a server died until users complain&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Load Balancer Access (The Right Way):
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High Availability&lt;/strong&gt; - One server dies? Traffic goes to the other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Failover&lt;/strong&gt; - Load balancer detects failures and reroutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Security&lt;/strong&gt; - Servers stay in private subnet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy Scaling&lt;/strong&gt; - Add/remove servers without DNS changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health Monitoring&lt;/strong&gt; - Load balancer constantly checks if servers are healthy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL Termination&lt;/strong&gt; - Handle HTTPS at the load balancer, not on each server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my setup, if Web-Server-1 crashes, the load balancer immediately stops sending traffic to it. Users never notice. That's production-grade architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Oh Shit" Moment: Realizing I Needed to Rebuild
&lt;/h2&gt;

&lt;p&gt;Later, I realized something: I had put all my instances in the same subnet. But the assignment specifically said "private subnet" for web servers.&lt;/p&gt;

&lt;p&gt;A subnet is either public (routes to Internet Gateway) or private (routes to NAT Gateway). You can't have both in the same subnet.&lt;/p&gt;

&lt;p&gt;So I had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a NAT Gateway (in a public subnet)&lt;/li&gt;
&lt;li&gt;Create a Private Route Table (routes outbound traffic through NAT)&lt;/li&gt;
&lt;li&gt;Associate that route table with a private subnet&lt;/li&gt;
&lt;li&gt;Terminate my web servers&lt;/li&gt;
&lt;li&gt;Launch new ones in the private subnet WITHOUT public IPs&lt;/li&gt;
&lt;li&gt;Update my inventory and SSH config&lt;/li&gt;
&lt;li&gt;Run Ansible again&lt;/li&gt;
&lt;li&gt;Update the target group&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This took another hour, but it was the right way to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The NAT Gateway Confusion
&lt;/h2&gt;

&lt;p&gt;Here's something that confused me: If web servers are in a private subnet with NO internet access, how do they download packages?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer: NAT Gateway.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A NAT Gateway allows &lt;strong&gt;outbound-only&lt;/strong&gt; internet access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Web Server: "I need to apt install nginx"
    ↓
Private Subnet Route Table: "Send to NAT Gateway"
    ↓
NAT Gateway: "I'll translate your private IP to my public IP"
    ↓
Internet: "Here's nginx"
    ↓
NAT Gateway: "I remember who asked, sending back to Web Server"
    ↓
Web Server: "Got it, thanks!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key: Outbound connections work, but the internet CANNOT initiate connections to your private servers. They're truly isolated.&lt;/p&gt;

&lt;p&gt;Without NAT Gateway, private servers are completely offline. Can't download anything, can't reach APIs, nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  All The Things That Went Wrong
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Issue 1: "Connection Timed Out"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Ansible couldn't connect to web servers. Ping returned UNREACHABLE.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Web servers had no internet access to download packages. They were in a public subnet, but they had no IP addresses themselves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Quick fix - made the instances public. Later rebuilt properly with NAT Gateway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Private instances = NO internet unless you add NAT Gateway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 2: All Instances in Same Subnet
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Assignment required private subnet for web servers, but I had everything in the same subnet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; I didn't understand that subnets are either public OR private, not both.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Created separate private subnet with route table pointing to NAT Gateway. Launched new web servers there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Network architecture planning matters. Can't just throw everything anywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 3: Can't curl from Bastion to Web Servers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Tried to test web servers from Bastion using curl. Connection refused.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Security group webserver-sg only allowed HTTP from alb-sg, not from bastion-sg.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Skipped this test. Verified through the load balancer instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Security groups are strict. They block everything not explicitly allowed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 4: Load Balancer Only Shows One Server
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Refreshing the page kept showing the same server. Thought load balancing was broken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Sticky sessions - the load balancer uses cookies to keep you on the same server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Used curl in a loop to verify both servers were getting traffic. They were.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Sticky sessions are a feature, not a bug. Keeps user sessions consistent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 5: Target Group Shows "Unused"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; After registering web servers in target group, status showed "Unused" with message "Target is in an Availability Zone that is not enabled for the load balancer"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; My web servers were in AZ eu-north-1c in a private subnet, but my load balancer wasn't configured to use that AZ since it couldn't use private subnets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Created a public subnet in AZ 1c and added it to the load balancer's network mapping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Load balancers need to span the availability zones where your targets are.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 6: NAT Gateway Not Appearing in Route Table
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; When trying to add route 0.0.0.0/0 =&amp;gt; NAT Gateway, it wasn't showing up in the dropdown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; NAT Gateway was still in "Pending" status. Hadn't finished creating yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Waited 2-3 minutes for status to become "Available", then refreshed the page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; AWS resources take time to provision. Be patient.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 7: New Subnet Not Showing in ALB Config
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Created a new public subnet for the ALB, but it didn't appear in the subnet dropdown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; New subnet wasn't associated with a route table that has Internet Gateway route.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Associated the subnet with the public route table (one with IGW route). Refreshed page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Subnets need proper route table associations to be recognized correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned About Cloud Security
&lt;/h2&gt;

&lt;p&gt;This project taught me security is about layers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1: Network Segmentation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public subnet: Only Bastion, NAT, Load Balancer&lt;/li&gt;
&lt;li&gt;Private subnet: Application servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 2: Security Groups&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each component has its own firewall rules&lt;/li&gt;
&lt;li&gt;Rules reference each other by security group ID&lt;/li&gt;
&lt;li&gt;Principle of least privilege&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 3: No Public IPs on App Servers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can't be attacked if they're not reachable&lt;/li&gt;
&lt;li&gt;All traffic forced through load balancer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 4: SSH Keys, Not Passwords&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cryptographic authentication&lt;/li&gt;
&lt;li&gt;Keys never leave my laptop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 5: Bastion Host&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single auditable entry point&lt;/li&gt;
&lt;li&gt;Can log all SSH sessions&lt;/li&gt;
&lt;li&gt;Additional barrier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what "defense in depth" means. You don't rely on one security measure, you stack them.&lt;/p&gt;

&lt;h2&gt;
  
  
  If I Did It Again
&lt;/h2&gt;

&lt;p&gt;Things I'd add for a real production system:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. HTTPS
&lt;/h3&gt;

&lt;p&gt;Right now it's just HTTP. In production, I'd:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get a free SSL cert from AWS Certificate Manager&lt;/li&gt;
&lt;li&gt;Configure ALB to handle HTTPS on port 443&lt;/li&gt;
&lt;li&gt;Redirect HTTP to HTTPS&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Auto Scaling
&lt;/h3&gt;

&lt;p&gt;Currently just 2 fixed servers. I'd add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto Scaling Group&lt;/li&gt;
&lt;li&gt;Scale up when CPU &amp;gt; 70%&lt;/li&gt;
&lt;li&gt;Scale down when CPU &amp;lt; 30%&lt;/li&gt;
&lt;li&gt;Minimum 2 instances for availability&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Multiple Availability Zones for Web Servers
&lt;/h3&gt;

&lt;p&gt;Right now both servers are in AZ 1c. For true high availability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Put Web-Server-1 in AZ 1b (since Bastion is in 1a)&lt;/li&gt;
&lt;li&gt;Put Web-Server-2 in AZ 1c&lt;/li&gt;
&lt;li&gt;Protected against entire data center failures&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Database Layer
&lt;/h3&gt;

&lt;p&gt;Currently no database. I'd add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon RDS in private subnet&lt;/li&gt;
&lt;li&gt;Separate database security group&lt;/li&gt;
&lt;li&gt;Automated backups&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Monitoring
&lt;/h3&gt;

&lt;p&gt;Zero visibility right now. I'd add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudWatch alarms (CPU, memory, disk)&lt;/li&gt;
&lt;li&gt;CloudWatch Logs (application logs)&lt;/li&gt;
&lt;li&gt;SNS notifications for alerts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. CI/CD Pipeline
&lt;/h3&gt;

&lt;p&gt;Manual deployments don't scale. I'd add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Actions or AWS CodePipeline&lt;/li&gt;
&lt;li&gt;Automated testing&lt;/li&gt;
&lt;li&gt;Blue/green deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7. Infrastructure as Code
&lt;/h3&gt;

&lt;p&gt;I clicked through the console for everything. Better approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terraform or CloudFormation&lt;/li&gt;
&lt;li&gt;Version control entire infrastructure&lt;/li&gt;
&lt;li&gt;Reproducible across environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real Talk: Was It Worth It?
&lt;/h2&gt;

&lt;p&gt;Two days. Countless errors. Almost gave up multiple times.&lt;/p&gt;

&lt;p&gt;But here's what I got out of it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical Skills:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Actually understand VPCs, subnets, route tables now&lt;/li&gt;
&lt;li&gt;Know how security groups work&lt;/li&gt;
&lt;li&gt;Can write Ansible playbooks&lt;/li&gt;
&lt;li&gt;Understand load balancer concepts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Problem-Solving:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learned to read error messages carefully&lt;/li&gt;
&lt;li&gt;Know how to debug connection issues&lt;/li&gt;
&lt;li&gt;Can think through network architecture&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Built something real, not a tutorial&lt;/li&gt;
&lt;li&gt;Can explain this in interviews&lt;/li&gt;
&lt;li&gt;Know I can figure things out when stuck&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The assignment said "If you can explain this project clearly, you can explain 70% of junior cloud interviews."&lt;/p&gt;

&lt;p&gt;They weren't lying. This project covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cloud networking fundamentals&lt;/li&gt;
&lt;li&gt;Security best practices&lt;/li&gt;
&lt;li&gt;Infrastructure automation&lt;/li&gt;
&lt;li&gt;High availability patterns&lt;/li&gt;
&lt;li&gt;Real-world troubleshooting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  For Anyone Doing This Assignment
&lt;/h2&gt;

&lt;p&gt;If you're an AltSchool student reading this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do's:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start early. This takes longer than you think&lt;/li&gt;
&lt;li&gt;Read error messages carefully&lt;/li&gt;
&lt;li&gt;Draw your architecture before building&lt;/li&gt;
&lt;li&gt;Test each component before moving to the next&lt;/li&gt;
&lt;li&gt;Take screenshots as you go (you'll need them)&lt;/li&gt;
&lt;li&gt;Ask for help when stuck&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don'ts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't put everything in the same subnet&lt;/li&gt;
&lt;li&gt;Don't skip the NAT Gateway (private servers need it)&lt;/li&gt;
&lt;li&gt;Don't give web servers public IPs (assignment requires private)&lt;/li&gt;
&lt;li&gt;Don't forget to delete resources after submission (AWS bills add up!)&lt;/li&gt;
&lt;li&gt;Don't just copy commands without understanding them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Documentation&lt;/li&gt;
&lt;li&gt;Ansible Documentation&lt;/li&gt;
&lt;li&gt;This article (seriously, refer back to it)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Architecture Checklist
&lt;/h2&gt;

&lt;p&gt;Before submitting, verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 EC2 instances running (1 Bastion, 2 Web Servers)&lt;/li&gt;
&lt;li&gt;Only Bastion has public IP&lt;/li&gt;
&lt;li&gt;Web servers in different subnet than Bastion&lt;/li&gt;
&lt;li&gt;NAT Gateway created and available&lt;/li&gt;
&lt;li&gt;Private route table routes through NAT Gateway&lt;/li&gt;
&lt;li&gt;Can SSH: laptop =&amp;gt; bastion =&amp;gt; web servers&lt;/li&gt;
&lt;li&gt;Ansible playbook runs successfully&lt;/li&gt;
&lt;li&gt;Both web servers show different hostnames/IPs&lt;/li&gt;
&lt;li&gt;Application Load Balancer is active&lt;/li&gt;
&lt;li&gt;Both targets healthy in target group&lt;/li&gt;
&lt;li&gt;ALB DNS shows your page&lt;/li&gt;
&lt;li&gt;Refreshing shows different servers (use curl to verify)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RESOURCES DELETED AFTER SUBMISSION&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is critical. NAT Gateway alone costs ~$32/month if you forget it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;This assignment kicked my ass, but in the best way possible.&lt;/p&gt;

&lt;p&gt;I went from "I've watched AWS tutorials" to "I've built AWS infrastructure". That's a huge difference.&lt;/p&gt;

&lt;p&gt;The frustration when Ansible couldn't connect. The confusion about subnets. The moment when the load balancer finally showed both servers. The relief when all health checks turned green.&lt;/p&gt;

&lt;p&gt;That's real learning.&lt;/p&gt;

&lt;p&gt;If you're reading this because you're about to start this assignment: good luck. You'll need it. But you'll also learn more than you expect.&lt;/p&gt;

&lt;p&gt;If you're reading this because you finished: congrats! We survived.&lt;/p&gt;

&lt;p&gt;If you're a recruiter: this is what I know now. Want to see if I can build something for you?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How I Built My First Production-Grade AWS Infrastructure (And Almost Lost My Mind)</title>
      <dc:creator>Alexin</dc:creator>
      <pubDate>Sun, 15 Feb 2026 11:45:45 +0000</pubDate>
      <link>https://forem.com/alexindevs/how-i-built-my-first-production-grade-aws-infrastructure-and-almost-lost-my-mind-2lm</link>
      <guid>https://forem.com/alexindevs/how-i-built-my-first-production-grade-aws-infrastructure-and-almost-lost-my-mind-2lm</guid>
      <description>&lt;p&gt;&lt;em&gt;A brutally honest walkthrough of my AltSchool Cloud Engineering exam project&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Assignment That Humbled Me
&lt;/h2&gt;

&lt;p&gt;I'm a student at AltSchool Africa studying Cloud Engineering, and for our semester 2 exam, we got this assignment where we had to roleplay as a Junior Cloud Engineer hired by a company. The task? Deploy a secure, highly available web application on AWS.&lt;/p&gt;

&lt;p&gt;I thought "how hard could it be?" &lt;/p&gt;

&lt;p&gt;Spoiler alert: Pretty hard.&lt;/p&gt;

&lt;p&gt;But I learned more in those two days than I did in weeks of watching tutorials. This is my story of building real cloud infrastructure, breaking things, fixing them, breaking them again, and eventually getting it right.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Had to Build
&lt;/h2&gt;

&lt;p&gt;The assignment was clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 Bastion Host in a public subnet&lt;/li&gt;
&lt;li&gt;2 Web Servers in a private subnet (NO public IPs)&lt;/li&gt;
&lt;li&gt;Everything automated with Ansible&lt;/li&gt;
&lt;li&gt;An Application Load Balancer distributing traffic&lt;/li&gt;
&lt;li&gt;All access through the load balancer only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The catch? Web servers couldn't be directly accessible from the internet. Everything had to go through proper security layers.&lt;/p&gt;

&lt;p&gt;Here's what I ended up building:&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%2Fojlv2xpiiolkaqrgitu4.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%2Fojlv2xpiiolkaqrgitu4.png" alt="Architecture Diagram" width="800" height="825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Day 1: "This Should Be Easy"
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Starting with Security Groups
&lt;/h3&gt;

&lt;p&gt;I started by creating security groups because I figured I'd need those first. Three of them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;bastion-sg&lt;/strong&gt; - For my jump box&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow SSH from my IP&lt;/li&gt;
&lt;li&gt;That's it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;webserver-sg&lt;/strong&gt; - For the application servers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow SSH from bastion-sg only&lt;/li&gt;
&lt;li&gt;Allow HTTP from alb-sg only&lt;/li&gt;
&lt;li&gt;No direct access from internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;alb-sg&lt;/strong&gt; - For the load balancer&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow HTTP from anywhere (0.0.0.0/0)&lt;/li&gt;
&lt;li&gt;This is the only thing exposed to the internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This part actually went smoothly. I was feeling confident. Too confident.&lt;/p&gt;

&lt;h3&gt;
  
  
  Launching EC2 Instances
&lt;/h3&gt;

&lt;p&gt;Next up: spinning up instances. I created an SSH key pair (saved it as &lt;code&gt;cloud-assignment-key.pem&lt;/code&gt;) and launched:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bastion Host&lt;/strong&gt; - Ubuntu 24.04, t2.micro, in a public subnet with a public IP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web-Server-1&lt;/strong&gt; - Ubuntu 24.04, t2.micro, NO public IP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web-Server-2&lt;/strong&gt; - Ubuntu 24.04, t2.micro, NO public IP&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's where I made my first mistake: I put all three instances in the same subnet. I didn't think about the fact that a subnet is either public OR private, not both. This came back to bite me later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up SSH Access
&lt;/h3&gt;

&lt;p&gt;I tested SSH to the Bastion - worked fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/cloud-assignment-key.pem ubuntu@&amp;lt;bastion-public-ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But I needed to access the web servers through the Bastion. This is where ProxyJump saved my life. I created an SSH config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host bastion
    HostName &amp;lt;BASTION_PUBLIC_IP&amp;gt;
    User ubuntu
    IdentityFile ~/.ssh/cloud-assignment-key.pem
    ForwardAgent yes
    StrictHostKeyChecking no

Host webserver1
    HostName &amp;lt;WEB_SERVER_1_PRIVATE_IP&amp;gt;
    User ubuntu
    IdentityFile ~/.ssh/cloud-assignment-key.pem
    ProxyJump bastion
    StrictHostKeyChecking no

Host webserver2
    HostName &amp;lt;WEB_SERVER_2_PRIVATE_IP&amp;gt;
    User ubuntu
    IdentityFile ~/.ssh/cloud-assignment-key.pem
    ProxyJump bastion
    StrictHostKeyChecking no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I could just type &lt;code&gt;ssh webserver1&lt;/code&gt; and it would automatically jump through the Bastion. Magic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Day 1 Evening: The Ansible Disaster
&lt;/h2&gt;

&lt;p&gt;Okay, time for automation. I installed Ansible on my laptop and created an inventory 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;[webservers]&lt;/span&gt;
&lt;span class="err"&gt;webserver1&lt;/span&gt; &lt;span class="py"&gt;ansible_host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;172.31.x.x&lt;/span&gt;
&lt;span class="err"&gt;webserver2&lt;/span&gt; &lt;span class="py"&gt;ansible_host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;172.31.y.y&lt;/span&gt;

&lt;span class="nn"&gt;[webservers:vars]&lt;/span&gt;
&lt;span class="py"&gt;ansible_user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ubuntu&lt;/span&gt;
&lt;span class="py"&gt;ansible_ssh_private_key_file&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;~/.ssh/cloud-assignment-key.pem&lt;/span&gt;
&lt;span class="py"&gt;ansible_ssh_common_args&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'-o StrictHostKeyChecking=no -o ProxyJump=bastion'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tested connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible webservers &lt;span class="nt"&gt;-i&lt;/span&gt; inventory.ini &lt;span class="nt"&gt;-m&lt;/span&gt; ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Success! Both servers responded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;webserver1 | SUCCESS
webserver2 | SUCCESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, I thought. Time to run the actual playbook. Here's what it looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Web Application&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webservers&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;
  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update apt cache&lt;/span&gt;
      &lt;span class="na"&gt;apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;update_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;
        &lt;span class="na"&gt;cache_valid_time&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3600&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install NGINX&lt;/span&gt;
      &lt;span class="na"&gt;apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;present&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Start and enable NGINX&lt;/span&gt;
      &lt;span class="na"&gt;systemd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;started&lt;/span&gt;
        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get instance hostname&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hostname&lt;/span&gt;
      &lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;instance_hostname&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get private IP&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hostname -I | awk '{print $1}'&lt;/span&gt;
      &lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;private_ip&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy custom HTML page&lt;/span&gt;
      &lt;span class="na"&gt;copy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/www/html/index.html&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;html lang='en'&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;meta charset='UTF-8'&amp;gt;&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;title&amp;gt;Cloud Assignment - Alexin&amp;lt;/title&amp;gt;&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;body {&lt;/span&gt;
                      &lt;span class="s"&gt;font-family: 'Segoe UI', sans-serif;&lt;/span&gt;
                      &lt;span class="s"&gt;max-width: 800px;&lt;/span&gt;
                      &lt;span class="s"&gt;margin: 50px auto;&lt;/span&gt;
                      &lt;span class="s"&gt;padding: 20px;&lt;/span&gt;
                      &lt;span class="s"&gt;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);&lt;/span&gt;
                      &lt;span class="s"&gt;color: white;&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                  &lt;span class="s"&gt;.container {&lt;/span&gt;
                      &lt;span class="s"&gt;background: rgba(255, 255, 255, 0.1);&lt;/span&gt;
                      &lt;span class="s"&gt;padding: 40px;&lt;/span&gt;
                      &lt;span class="s"&gt;border-radius: 15px;&lt;/span&gt;
                      &lt;span class="s"&gt;backdrop-filter: blur(10px);&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                  &lt;span class="s"&gt;.info { &lt;/span&gt;
                      &lt;span class="s"&gt;background: rgba(255, 255, 255, 0.2); &lt;/span&gt;
                      &lt;span class="s"&gt;padding: 15px; &lt;/span&gt;
                      &lt;span class="s"&gt;border-radius: 8px; &lt;/span&gt;
                      &lt;span class="s"&gt;margin: 20px 0; &lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;div class='container'&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;&amp;lt;h1&amp;gt;🚀 Cloud Assignment&amp;lt;/h1&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;&amp;lt;div class='info'&amp;gt;&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Name:&amp;lt;/strong&amp;gt; Alexin&amp;lt;/p&amp;gt;&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Instance:&amp;lt;/strong&amp;gt; {{ instance_hostname.stdout }}&amp;lt;/p&amp;gt;&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Private IP:&amp;lt;/strong&amp;gt; {{ private_ip.stdout }}&amp;lt;/p&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;&amp;lt;div class='about'&amp;gt;&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;lt;h2&amp;gt;About Me&amp;lt;/h2&amp;gt;&lt;/span&gt;
                      &lt;span class="s"&gt;&amp;lt;p&amp;gt;Backend engineer from Lagos, Nigeria. This was deployed with &lt;/span&gt;
                      &lt;span class="s"&gt;Ansible through a Bastion Host to demonstrate Infrastructure as Code.&amp;lt;/p&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
              &lt;span class="s"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0644'&lt;/span&gt;
      &lt;span class="na"&gt;notify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Restart NGINX&lt;/span&gt;

  &lt;span class="na"&gt;handlers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Restart NGINX&lt;/span&gt;
      &lt;span class="na"&gt;systemd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;restarted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ran it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible-playbook &lt;span class="nt"&gt;-i&lt;/span&gt; inventory.ini deploy-webserver.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IT FAILED.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The playbook started running, got to the "Install NGINX" task, and just... timed out. Connection errors everywhere. The servers were reachable via SSH, Ansible could ping them, but they couldn't download anything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TASK [Install NGINX] *****
fatal: [webserver1]: FAILED! =&amp;gt; {"changed": false, "msg": "Failed to update apt cache"}
fatal: [webserver2]: FAILED! =&amp;gt; {"changed": false, "msg": "Failed to update apt cache"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I spent an hour debugging this. Turns out my web servers couldn't reach the internet to download packages. They could talk to Ansible (via the Bastion), but they couldn't reach Ubuntu's package repositories.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Internet Access Problem
&lt;/h3&gt;

&lt;p&gt;Here's what I learned the hard way: My servers needed internet access to run &lt;code&gt;apt update&lt;/code&gt; and &lt;code&gt;apt install nginx&lt;/code&gt;. They were technically reachable via SSH, but they couldn't initiate outbound connections to the internet.&lt;/p&gt;

&lt;p&gt;The proper solution? &lt;strong&gt;NAT Gateway&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But I was already tired and the deadline was approaching, so I did a "quick fix": I kept everything in the same public subnet (with Internet Gateway access) so the servers could download packages. Not best practice, but it worked for getting Ansible running.&lt;/p&gt;

&lt;p&gt;After that fix, the playbook ran perfectly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PLAY RECAP *****
webserver1: ok=8 changed=6 unreachable=0 failed=0
webserver2: ok=8 changed=6 unreachable=0 failed=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both servers configured in under 2 minutes. This is when I understood why everyone talks about automation - imagine doing this manually on 10 or 100 servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Ansible Changed Everything
&lt;/h2&gt;

&lt;p&gt;Before this project, I'd always SSH'd into servers and ran commands manually. Copy-paste from StackOverflow, hope it works, repeat on the next server.&lt;/p&gt;

&lt;p&gt;Ansible made me realize:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt; - Both servers got the EXACT same config&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt; - 2 minutes vs 30 minutes of manual work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt; - My playbook IS my documentation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeatability&lt;/strong&gt; - I can run it again tomorrow and get the same result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The playbook grabs the hostname and private IP dynamically with shell commands, then injects them into the HTML template. Each server shows different info, proving load balancing works later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Day 2: Load Balancer Time
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating the Target Group
&lt;/h3&gt;

&lt;p&gt;First, I created a target group:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;webserver-tg&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Protocol: HTTP, Port: 80&lt;/li&gt;
&lt;li&gt;Registered both web servers&lt;/li&gt;
&lt;li&gt;Health checks: HTTP GET to /&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Creating the ALB
&lt;/h3&gt;

&lt;p&gt;Then the Application Load Balancer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;web-app-alb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Internet-facing&lt;/li&gt;
&lt;li&gt;Selected multiple availability zones&lt;/li&gt;
&lt;li&gt;Security group: alb-sg&lt;/li&gt;
&lt;li&gt;Forwarded traffic to: webserver-tg&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Waited for health checks... and both targets went healthy! &lt;/p&gt;

&lt;p&gt;Accessed the ALB DNS name in my browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://web-app-alb-xxxxxxxxx.eu-north-1.elb.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IT WORKED!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But I noticed it kept showing the same server. Turns out that's normal - it's called "sticky sessions". The load balancer keeps you on the same server for consistency. I verified it was actually load balancing by using curl:&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="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;1..10&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;curl http://alb-dns-name | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Instance:"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And boom - I saw both server hostnames appearing. Load balancing confirmed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Bastion Host?
&lt;/h2&gt;

&lt;p&gt;At first, I didn't get why we needed a Bastion Host. Why not just SSH directly to the servers?&lt;/p&gt;

&lt;p&gt;Here's what I learned:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without Bastion (Bad):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every server exposed to the internet&lt;/li&gt;
&lt;li&gt;More attack surface&lt;/li&gt;
&lt;li&gt;Hard to control who accesses what&lt;/li&gt;
&lt;li&gt;Each server needs its own public IP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;With Bastion (Good):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only ONE server exposed to internet&lt;/li&gt;
&lt;li&gt;Single point of entry I can monitor and secure&lt;/li&gt;
&lt;li&gt;Web servers hidden in private subnet&lt;/li&gt;
&lt;li&gt;I can log every SSH session&lt;/li&gt;
&lt;li&gt;If someone compromises the Bastion, web servers are still protected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real companies use this because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compliance&lt;/strong&gt; - Many regulations require it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; - Defense in depth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auditing&lt;/strong&gt; - Know who accessed what and when&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Bastion is like a security checkpoint. Everything goes through it, nothing bypasses it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Balancer vs Direct Access: Why It Matters
&lt;/h2&gt;

&lt;p&gt;When I started, I thought "why not just give each server a public IP and call it a day?"&lt;/p&gt;

&lt;p&gt;Here's why that's a terrible idea:&lt;/p&gt;

&lt;h3&gt;
  
  
  Direct EC2 Access (What NOT to Do):
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single Point of Failure&lt;/strong&gt; - Server goes down? Your app is offline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Failover&lt;/strong&gt; - Users get errors until you manually fix it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Risk&lt;/strong&gt; - Servers exposed directly to attacks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hard to Scale&lt;/strong&gt; - Adding servers means changing DNS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Health Checks&lt;/strong&gt; - You won't know a server died until users complain&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Load Balancer Access (The Right Way):
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High Availability&lt;/strong&gt; - One server dies? Traffic goes to the other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Failover&lt;/strong&gt; - Load balancer detects failures and reroutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Security&lt;/strong&gt; - Servers stay in private subnet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy Scaling&lt;/strong&gt; - Add/remove servers without DNS changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health Monitoring&lt;/strong&gt; - Load balancer constantly checks if servers are healthy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL Termination&lt;/strong&gt; - Handle HTTPS at the load balancer, not on each server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my setup, if Web-Server-1 crashes, the load balancer immediately stops sending traffic to it. Users never notice. That's production-grade architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Oh Shit" Moment: Realizing I Needed to Rebuild
&lt;/h2&gt;

&lt;p&gt;Later, I realized something: I had put all my instances in the same subnet. But the assignment specifically said "private subnet" for web servers.&lt;/p&gt;

&lt;p&gt;A subnet is either public (routes to Internet Gateway) or private (routes to NAT Gateway). You can't have both in the same subnet.&lt;/p&gt;

&lt;p&gt;So I had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a NAT Gateway (in a public subnet)&lt;/li&gt;
&lt;li&gt;Create a Private Route Table (routes outbound traffic through NAT)&lt;/li&gt;
&lt;li&gt;Associate that route table with a private subnet&lt;/li&gt;
&lt;li&gt;Terminate my web servers&lt;/li&gt;
&lt;li&gt;Launch new ones in the private subnet WITHOUT public IPs&lt;/li&gt;
&lt;li&gt;Update my inventory and SSH config&lt;/li&gt;
&lt;li&gt;Run Ansible again&lt;/li&gt;
&lt;li&gt;Update the target group&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This took another hour, but it was the right way to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The NAT Gateway Confusion
&lt;/h2&gt;

&lt;p&gt;Here's something that confused me: If web servers are in a private subnet with NO internet access, how do they download packages?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer: NAT Gateway.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A NAT Gateway allows &lt;strong&gt;outbound-only&lt;/strong&gt; internet access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Web Server: "I need to apt install nginx"
    ↓
Private Subnet Route Table: "Send to NAT Gateway"
    ↓
NAT Gateway: "I'll translate your private IP to my public IP"
    ↓
Internet: "Here's nginx"
    ↓
NAT Gateway: "I remember who asked, sending back to Web Server"
    ↓
Web Server: "Got it, thanks!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key: Outbound connections work, but the internet CANNOT initiate connections to your private servers. They're truly isolated.&lt;/p&gt;

&lt;p&gt;Without NAT Gateway, private servers are completely offline. Can't download anything, can't reach APIs, nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  All The Things That Went Wrong
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Issue 1: "Connection Timed Out"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Ansible couldn't connect to web servers. Ping returned UNREACHABLE.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Web servers had no internet access to download packages. They were in a public subnet, but they had no IP addresses themselves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Quick fix - made the instances public. Later rebuilt properly with NAT Gateway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Private instances = NO internet unless you add NAT Gateway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 2: All Instances in Same Subnet
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Assignment required private subnet for web servers, but I had everything in the same subnet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; I didn't understand that subnets are either public OR private, not both.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Created separate private subnet with route table pointing to NAT Gateway. Launched new web servers there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Network architecture planning matters. Can't just throw everything anywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 3: Can't curl from Bastion to Web Servers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Tried to test web servers from Bastion using curl. Connection refused.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Security group webserver-sg only allowed HTTP from alb-sg, not from bastion-sg.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Skipped this test. Verified through the load balancer instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Security groups are strict. They block everything not explicitly allowed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 4: Load Balancer Only Shows One Server
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Refreshing the page kept showing the same server. Thought load balancing was broken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Sticky sessions - the load balancer uses cookies to keep you on the same server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Used curl in a loop to verify both servers were getting traffic. They were.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Sticky sessions are a feature, not a bug. Keeps user sessions consistent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 5: Target Group Shows "Unused"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; After registering web servers in target group, status showed "Unused" with message "Target is in an Availability Zone that is not enabled for the load balancer"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; My web servers were in AZ eu-north-1c in a private subnet, but my load balancer wasn't configured to use that AZ since it couldn't use private subnets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Created a public subnet in AZ 1c and added it to the load balancer's network mapping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Load balancers need to span the availability zones where your targets are.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 6: NAT Gateway Not Appearing in Route Table
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; When trying to add route 0.0.0.0/0 =&amp;gt; NAT Gateway, it wasn't showing up in the dropdown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; NAT Gateway was still in "Pending" status. Hadn't finished creating yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Waited 2-3 minutes for status to become "Available", then refreshed the page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; AWS resources take time to provision. Be patient.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 7: New Subnet Not Showing in ALB Config
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Created a new public subnet for the ALB, but it didn't appear in the subnet dropdown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; New subnet wasn't associated with a route table that has Internet Gateway route.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Associated the subnet with the public route table (one with IGW route). Refreshed page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Subnets need proper route table associations to be recognized correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned About Cloud Security
&lt;/h2&gt;

&lt;p&gt;This project taught me security is about layers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1: Network Segmentation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public subnet: Only Bastion, NAT, Load Balancer&lt;/li&gt;
&lt;li&gt;Private subnet: Application servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 2: Security Groups&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each component has its own firewall rules&lt;/li&gt;
&lt;li&gt;Rules reference each other by security group ID&lt;/li&gt;
&lt;li&gt;Principle of least privilege&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 3: No Public IPs on App Servers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can't be attacked if they're not reachable&lt;/li&gt;
&lt;li&gt;All traffic forced through load balancer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 4: SSH Keys, Not Passwords&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cryptographic authentication&lt;/li&gt;
&lt;li&gt;Keys never leave my laptop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 5: Bastion Host&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single auditable entry point&lt;/li&gt;
&lt;li&gt;Can log all SSH sessions&lt;/li&gt;
&lt;li&gt;Additional barrier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what "defense in depth" means. You don't rely on one security measure, you stack them.&lt;/p&gt;

&lt;h2&gt;
  
  
  If I Did It Again
&lt;/h2&gt;

&lt;p&gt;Things I'd add for a real production system:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. HTTPS
&lt;/h3&gt;

&lt;p&gt;Right now it's just HTTP. In production, I'd:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get a free SSL cert from AWS Certificate Manager&lt;/li&gt;
&lt;li&gt;Configure ALB to handle HTTPS on port 443&lt;/li&gt;
&lt;li&gt;Redirect HTTP to HTTPS&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Auto Scaling
&lt;/h3&gt;

&lt;p&gt;Currently just 2 fixed servers. I'd add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto Scaling Group&lt;/li&gt;
&lt;li&gt;Scale up when CPU &amp;gt; 70%&lt;/li&gt;
&lt;li&gt;Scale down when CPU &amp;lt; 30%&lt;/li&gt;
&lt;li&gt;Minimum 2 instances for availability&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Multiple Availability Zones for Web Servers
&lt;/h3&gt;

&lt;p&gt;Right now both servers are in AZ 1c. For true high availability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Put Web-Server-1 in AZ 1b (since Bastion is in 1a)&lt;/li&gt;
&lt;li&gt;Put Web-Server-2 in AZ 1c&lt;/li&gt;
&lt;li&gt;Protected against entire data center failures&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Database Layer
&lt;/h3&gt;

&lt;p&gt;Currently no database. I'd add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon RDS in private subnet&lt;/li&gt;
&lt;li&gt;Separate database security group&lt;/li&gt;
&lt;li&gt;Automated backups&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Monitoring
&lt;/h3&gt;

&lt;p&gt;Zero visibility right now. I'd add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudWatch alarms (CPU, memory, disk)&lt;/li&gt;
&lt;li&gt;CloudWatch Logs (application logs)&lt;/li&gt;
&lt;li&gt;SNS notifications for alerts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. CI/CD Pipeline
&lt;/h3&gt;

&lt;p&gt;Manual deployments don't scale. I'd add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Actions or AWS CodePipeline&lt;/li&gt;
&lt;li&gt;Automated testing&lt;/li&gt;
&lt;li&gt;Blue/green deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7. Infrastructure as Code
&lt;/h3&gt;

&lt;p&gt;I clicked through the console for everything. Better approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terraform or CloudFormation&lt;/li&gt;
&lt;li&gt;Version control entire infrastructure&lt;/li&gt;
&lt;li&gt;Reproducible across environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real Talk: Was It Worth It?
&lt;/h2&gt;

&lt;p&gt;Two days. Countless errors. Almost gave up multiple times.&lt;/p&gt;

&lt;p&gt;But here's what I got out of it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical Skills:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Actually understand VPCs, subnets, route tables now&lt;/li&gt;
&lt;li&gt;Know how security groups work&lt;/li&gt;
&lt;li&gt;Can write Ansible playbooks&lt;/li&gt;
&lt;li&gt;Understand load balancer concepts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Problem-Solving:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learned to read error messages carefully&lt;/li&gt;
&lt;li&gt;Know how to debug connection issues&lt;/li&gt;
&lt;li&gt;Can think through network architecture&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Built something real, not a tutorial&lt;/li&gt;
&lt;li&gt;Can explain this in interviews&lt;/li&gt;
&lt;li&gt;Know I can figure things out when stuck&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The assignment said "If you can explain this project clearly, you can explain 70% of junior cloud interviews."&lt;/p&gt;

&lt;p&gt;They weren't lying. This project covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cloud networking fundamentals&lt;/li&gt;
&lt;li&gt;Security best practices&lt;/li&gt;
&lt;li&gt;Infrastructure automation&lt;/li&gt;
&lt;li&gt;High availability patterns&lt;/li&gt;
&lt;li&gt;Real-world troubleshooting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  For Anyone Doing This Assignment
&lt;/h2&gt;

&lt;p&gt;If you're an AltSchool student reading this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do's:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start early. This takes longer than you think&lt;/li&gt;
&lt;li&gt;Read error messages carefully&lt;/li&gt;
&lt;li&gt;Draw your architecture before building&lt;/li&gt;
&lt;li&gt;Test each component before moving to the next&lt;/li&gt;
&lt;li&gt;Take screenshots as you go (you'll need them)&lt;/li&gt;
&lt;li&gt;Ask for help when stuck&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don'ts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't put everything in the same subnet&lt;/li&gt;
&lt;li&gt;Don't skip the NAT Gateway (private servers need it)&lt;/li&gt;
&lt;li&gt;Don't give web servers public IPs (assignment requires private)&lt;/li&gt;
&lt;li&gt;Don't forget to delete resources after submission (AWS bills add up!)&lt;/li&gt;
&lt;li&gt;Don't just copy commands without understanding them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Documentation&lt;/li&gt;
&lt;li&gt;Ansible Documentation&lt;/li&gt;
&lt;li&gt;This article (seriously, refer back to it)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Architecture Checklist
&lt;/h2&gt;

&lt;p&gt;Before submitting, verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 EC2 instances running (1 Bastion, 2 Web Servers)&lt;/li&gt;
&lt;li&gt;Only Bastion has public IP&lt;/li&gt;
&lt;li&gt;Web servers in different subnet than Bastion&lt;/li&gt;
&lt;li&gt;NAT Gateway created and available&lt;/li&gt;
&lt;li&gt;Private route table routes through NAT Gateway&lt;/li&gt;
&lt;li&gt;Can SSH: laptop =&amp;gt; bastion =&amp;gt; web servers&lt;/li&gt;
&lt;li&gt;Ansible playbook runs successfully&lt;/li&gt;
&lt;li&gt;Both web servers show different hostnames/IPs&lt;/li&gt;
&lt;li&gt;Application Load Balancer is active&lt;/li&gt;
&lt;li&gt;Both targets healthy in target group&lt;/li&gt;
&lt;li&gt;ALB DNS shows your page&lt;/li&gt;
&lt;li&gt;Refreshing shows different servers (use curl to verify)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RESOURCES DELETED AFTER SUBMISSION&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is critical. NAT Gateway alone costs ~$32/month if you forget it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;This assignment kicked my ass, but in the best way possible.&lt;/p&gt;

&lt;p&gt;I went from "I've watched AWS tutorials" to "I've built AWS infrastructure". That's a huge difference.&lt;/p&gt;

&lt;p&gt;The frustration when Ansible couldn't connect. The confusion about subnets. The moment when the load balancer finally showed both servers. The relief when all health checks turned green.&lt;/p&gt;

&lt;p&gt;That's real learning.&lt;/p&gt;

&lt;p&gt;If you're reading this because you're about to start this assignment: good luck. You'll need it. But you'll also learn more than you expect.&lt;/p&gt;

&lt;p&gt;If you're reading this because you finished: congrats! We survived.&lt;/p&gt;

&lt;p&gt;If you're a recruiter: this is what I know now. Want to see if I can build something for you?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Alexin</dc:creator>
      <pubDate>Mon, 28 Jul 2025 18:23:33 +0000</pubDate>
      <link>https://forem.com/alexindevs/-224e</link>
      <guid>https://forem.com/alexindevs/-224e</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/abubakersiddique771/7-habits-that-quietly-made-me-a-10x-developer-no-not-chatgpt-13c4" class="crayons-story__hidden-navigation-link"&gt;7 Habits That Quietly Made Me a 10x Developer (No, Not ChatGPT)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/abubakersiddique771" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3222877%2F84195f25-85c0-49d4-905e-cc184f8a8000.png" alt="abubakersiddique771 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/abubakersiddique771" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Abubakersiddique771
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Abubakersiddique771
                
              
              &lt;div id="story-author-preview-content-2694723" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/abubakersiddique771" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F3222877%2F84195f25-85c0-49d4-905e-cc184f8a8000.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Abubakersiddique771&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/abubakersiddique771/7-habits-that-quietly-made-me-a-10x-developer-no-not-chatgpt-13c4" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 16 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/abubakersiddique771/7-habits-that-quietly-made-me-a-10x-developer-no-not-chatgpt-13c4" id="article-link-2694723"&gt;
          7 Habits That Quietly Made Me a 10x Developer (No, Not ChatGPT)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/java"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;java&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/productivity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;productivity&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/abubakersiddique771/7-habits-that-quietly-made-me-a-10x-developer-no-not-chatgpt-13c4" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;154&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/abubakersiddique771/7-habits-that-quietly-made-me-a-10x-developer-no-not-chatgpt-13c4#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              1&lt;span class="hidden s:inline"&gt; comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>programming</category>
      <category>java</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Technical Debt: The Hidden Cost Of Shipping Fast And Thinking Later</title>
      <dc:creator>Alexin</dc:creator>
      <pubDate>Mon, 16 Jun 2025 13:00:00 +0000</pubDate>
      <link>https://forem.com/alexindevs/technical-debt-the-hidden-cost-of-shipping-fast-and-thinking-later-587d</link>
      <guid>https://forem.com/alexindevs/technical-debt-the-hidden-cost-of-shipping-fast-and-thinking-later-587d</guid>
      <description>&lt;p&gt;Ever shipped a tiny change and somehow broken six unrelated features you didn’t even touch? That, dear friends, is tech debt doing what it does best: lurking in the corners of the codebase you refused to refactor. You know exactly what I mean; those files stuffed with spaghetti logic, the ancient functions no one fully understands, that one part of the product that "just works" (but no one knows how - the code is unreadable). Have you ever spent hours tracing a bug, only to realize the real issue was a shortcut someone took nine months ago under deadline pressure? You’re not alone. Most of us have wrestled with tech debt left behind by old teammates, past versions of ourselves, or a product roadmap that prized speed over sustainability. Tech debt is the compounding interest of rushed decisions, and today, we’re unpacking what it is, why it doesn’t &lt;em&gt;totally&lt;/em&gt; suck, and why it’s way more dangerous than most engineers realize.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Technical Debt, really?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Technical debt&lt;/strong&gt; is the cost of choosing speed over long-term code quality. It happens when teams ship fast by making subpar technical decisions, knowing their process isn’t ideal. In the short term, this helps hit deadlines and prove value. But over time, the code becomes harder to understand, slower to change, and more expensive to maintain, just like financial debt accrues interest if you don’t pay it back.&lt;/p&gt;

&lt;p&gt;Ward Cunningham, who coined the term &lt;em&gt;technical debt&lt;/em&gt; back in 1992, said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Shipping first-time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite. The danger occurs when the debt is not repaid. Every minute spent on code that is not quite right for the programming task of the moment counts as interest on that debt.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In plain English, when you create tech debt in your codebase, you're buying time to ship features faster. This quick-and-dirty code is fine &lt;em&gt;if&lt;/em&gt; you revisit and fix it soon. When you don't, however, problems start to pile up. The longer you leave that messy code in place, the more time and effort you waste working around it.&lt;/p&gt;

&lt;p&gt;Not all tech debt is created equal. Sometimes, you create intentional debt. This is the kind you take on knowingly - sprinting through features on an MVP checklist, building a demo overnight, or hacking together a prototype for a pitch. You know the code isn't great, but you accept the tradeoff to move fast, planning (hopefully) to clean it up later. Accidental debt, on the other hand, creeps in when no one's looking. It's what happens when specs change mid-sprint, when junior devs copy outdated patterns for core modules, or when your app is still running on a framework the internet forgot. One is strategic. The other is the programming equivalent of finding mold behind your wall.&lt;/p&gt;

&lt;p&gt;Picture this: your team needs to ship a new onboarding flow by Friday. The designer mocks up a slick multi-step signup form, and the backend team realizes they’ll need to touch one ancient login module, written four years ago by someone who’s since moved to Canada and started a farm.&lt;/p&gt;

&lt;p&gt;Ideally, this is the moment to refactor the login logic: separate concerns, clean up those 300-line functions, maybe even add some tests. But there’s no time. So instead, someone hacks in a workaround. It works for the deadline. But every new feature added to auth starts to break something else: session handling gets messy, error states become unpredictable, and adding social login becomes a full-blown crisis.&lt;/p&gt;

&lt;p&gt;Months later, that one decision to “just patch it” means every auth-related ticket takes three times longer, and new engineers onboard with a warning: &lt;em&gt;“DON'T TOUCH THE LOGIN SERVICE!”&lt;/em&gt; That’s tech debt in a production codebase in today's world.&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%2Figiuv2cle34unafzrtpv.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%2Figiuv2cle34unafzrtpv.png" alt="Tech Debt Spectrum" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Tech Debt Happens
&lt;/h2&gt;

&lt;p&gt;You don't just owe a bank 4x the amount you borrowed right off the bat (at least, I'd like to think so). You end up heavily in debt when you allow loans to rack up interest without paying them off in time. Similarly, in software production, tech debt slowly rises, disguised as "just one more quick fix" or a &lt;code&gt;// TODO: clean this up&lt;/code&gt; comment. Over time, these small decisions start compounding, until you’re debugging a system that feels more like an archaeological excursion than a codebase. Here’s how it usually happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ship-or-die deadlines:&lt;/strong&gt; You had five days to do three weeks of work, so you cut corners to ship on time. The shortcut worked. The code stayed. No one circled back like they said they would.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Missing docs and tests:&lt;/strong&gt; What starts as “we’ll document this later” quickly becomes a game of telephone, where future devs are forced to reverse-engineer your decisions from vague commit messages and test cases that haven't been updated in months.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Team churn and knowledge silos:&lt;/strong&gt; The one engineer who understood how the invoicing system worked just rage-quit and joined a fintech startup. Now you’re stuck with brittle logic, zero documentation, and multiple Slack threads that end in “nevermind, fixed it” and no explanation on what the code does.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Partial migrations:&lt;/strong&gt; Half your service uses Paystack, the other half uses Flutterwave, and now someone’s suggesting “let's try Monnify” for virtual accounts. Meanwhile, your original payment logic is still tangled up in custom webhook handlers from 2020. No tests, no docs, and no one brave enough to refactor it during working hours.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Copy-paste cargo culting:&lt;/strong&gt; You found a working snippet on StackOverflow and dropped it in. It solved your problem, but now no one knows what it actually does. Worse, it’s breaking edge cases that nobody tested for.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Technical or Requirements Constraints:&lt;/strong&gt; Not all tech debt is born from poor decisions. Sometimes, it’s the result of working within immovable limits. Maybe you’re forced to use an outdated API because the vendor hasn’t released v2 yet. Maybe the infrastructure team won’t approve a new database engine, so you’re stuck bending your current one into unnatural shapes. Or maybe the product spec just changed again mid-sprint, and your only option was to duct-tape the new logic onto whatever already existed.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Many Faces of Tech Debt
&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not all debt is code and not all of it is your fault. Tech debt can show up in different layers of your system:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Debt Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;What It Looks Like&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Architecture Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sluggish performance, fragile systems, and bottlenecks baked into your foundations.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Build Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Builds that take forever, randomly fail, or require arcane rituals to pass.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Spaghetti logic, inconsistent naming, and functions that do too much.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Defect Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Known bugs that no one has time to fix until they trigger outages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Design Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Inheritance gone wild, singletons used like global duct tape.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Documentation Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;README files that are out of date or simply nonexistent.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Infrastructure Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deploy pipelines that break if you breathe wrong, or environments that drift constantly.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;People Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One person knows how this works and they’re going on leave.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Process Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Clunky sprint planning, manual QA, or unclear review workflows.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Requirement Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Half-baked features that “technically shipped” but don’t meet user needs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Service Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;External services that need replacing but are too entwined to remove.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Test Automation Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tests are manual, flaky, or missing for critical paths.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Test Debt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Planned test cases that were skipped or tools that can’t support new functionality.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Tech debt isn’t just messy code. It’s every inefficiency your team pays for, over and over again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spotting Tech Debt
&lt;/h2&gt;

&lt;p&gt;Tech debt isn't always apparent. Unlike loan apps threatening your entire lineage if you don't pay up, tech debt often hides in plain sight, quietly draining your team’s velocity and morale until you realize you’ve spent three days fixing a bug that should’ve taken twenty minutes. You just had to fix one more thing, one more broken module that the original one was dependent on, until you ended up rewriting the entire feature, and you missed the deadline. So how do you know when your codebase is quietly screaming for help?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;h3&gt;
  
  
  Quantitative Red Flags
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pull requests that drag on forever:&lt;/strong&gt; If simple changes start taking days (or weeks) to finish, chances are you're wrestling with hidden messes under the hood.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code that’s too complex to follow:&lt;/strong&gt; When a single function has so many “if this, then that” cases, it feels like reading a legal contract. That’s a sign the logic has gotten out of hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Barely any tests:&lt;/strong&gt; If less than half your code is covered by automated tests, you're flying without a safety net. Every new change becomes a gamble.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;h3&gt;
  
  
  Qualitative Smells
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;“Don’t touch that part of the system.”&lt;/strong&gt; If your team avoids certain files because they always break something, you’ve got serious baggage there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TODO comments from the BC Era:&lt;/strong&gt; Notes left behind like “fix this later” that were never touched again, usually by people who’ve already left the company.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code reviews full of confusion:&lt;/strong&gt; When teammates constantly ask, “What does this even do?” or “Why was it written this way?”, you’re probably looking at bad code that needs an update.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;h3&gt;
  
  
  Tools That Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code scanners&lt;/strong&gt; (like SonarQube or DeepSource) that point out messy areas automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health scores&lt;/strong&gt; that rank your files based on how hard they are to maintain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decision logs&lt;/strong&gt; that explain why something weird was built that way (instead of guessing).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incident history&lt;/strong&gt; that shows which parts of your system are always breaking at the worst times.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Impact of Technical Debt on Software Systems
&lt;/h2&gt;

&lt;p&gt;Tech debt isn’t just an “engineering problem.” It’s a &lt;em&gt;business&lt;/em&gt; problem. Left unmanaged, it silently bleeds time, money, morale, and momentum across the entire organization. The features get slower to build. The bugs get harder to trace. The outages get more frequent. And the developers? They start burning out. Here’s what that looks like in real life:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Slower Development:&lt;/strong&gt; New features start taking forever, not because your team isn’t skilled, but because every change means wading through a minefield of brittle, undocumented code. You want to add a “forgot password” feature, but it turns into a three-day saga because it touches legacy auth logic that hasn’t been touched since 2019.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More Outages:&lt;/strong&gt; Remember that one cron job nobody understood but everyone hoped would keep working? It didn’t. Tech debt creates fragile systems that break at the worst times, usually on weekends, during a promo launch, or when your lead dev is on vacation. Suddenly, your team is spending more time fixing fires than actually shipping features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Higher Costs:&lt;/strong&gt; Every patch, workaround, and unexplained bug adds up. Engineers burn more hours. Customers encounter more issues. Infra teams over-provision to compensate for bloated, inefficient logic. That’s real money leaking out of the product, disguised as "normal delays."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team Burnout:&lt;/strong&gt; No one enjoys working on a broken foundation. When your smartest engineers are spending half their time fixing the same parts of the system over and over, they’ll either check out or check LinkedIn. Tech debt is the silent morale killer that makes even small wins feel exhausting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business Blockers:&lt;/strong&gt; Sometimes, the tech debt is so bad you simply &lt;em&gt;can’t&lt;/em&gt; build what the business wants. “We can’t add multi-currency support yet” or “That will take three months instead of two weeks” becomes a regular thing in product planning. And no matter how strong the roadmap looks, delivery suffers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Strategies to manage and repay tech debt
&lt;/h2&gt;

&lt;p&gt;Tech debt isn’t the root of all evil. But like any loan, you have to track it, manage it, and eventually pay it down. Here’s how to do that while still staying on top of your roadmap.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start a Debt Register:&lt;/strong&gt; You can’t fix what you don’t track. Maintain a running list of known debt across the codebase - what it is, where it lives, how often it causes problems, and how painful those problems are. Think of it like a credit card statement, but for your repo. High-interest debt (frequent bugs, blockers) should always rise to the top.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Follow the Boy Scout Rule:&lt;/strong&gt; Whenever you touch a file, refactor a little. Rename variables. Break down bloated functions. Add a comment. Leave it cleaner than you found it. These micro-improvements compound over time and help shift the codebase from survival mode to sustainable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refactor Within Features:&lt;/strong&gt; Don't schedule refactoring for "someday." When working on a feature that touches janky code, bake cleanup into the story. That way, you get new functionality &lt;em&gt;and&lt;/em&gt; better maintainability in one go, and no one has to justify a separate “tech debt ticket” that product will ignore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schedule Dedicated Debt Time&lt;/strong&gt;: Set aside regular time to tackle known issues: maybe it’s “Clean-Up Fridays” or a full debt sprint every quarter. You’ll never eliminate debt entirely, but routine pay-down keeps it from spiraling into a crisis. Treat it like maintenance on your house. You can either patch the leak now or replace the roof later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate Testing &amp;amp; CI Gates:&lt;/strong&gt; The best way to prevent new tech debt? Don’t let it merge. Use automated tests, linters, and CI rules to catch bad patterns early. Every broken test or failed check is a helpful "nope" from your future self.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document Your Shortcuts:&lt;/strong&gt; If you take a shortcut, explain &lt;em&gt;why&lt;/em&gt;. Use docs, inline comments, or ADRs (Architecture Decision Records) to give future devs context. "This is janky, but we did it to hit the Q2 deadline, and here’s what we’d like to change when we revisit it." Now your tech debt has a paper trail and a plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Have Kill-Switch Courage:&lt;/strong&gt; Sometimes the most efficient refactor is a delete key. If a module is causing more pain than value, and no one knows why it still exists, just rip it out and rewrite it. Legacy systems, abandoned features, or duplicate services deserve a graceful exit, not eternal babysitting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When It’s &lt;em&gt;Actually&lt;/em&gt; Worth It
&lt;/h2&gt;

&lt;p&gt;Not all tech debt is bad. Sometimes, it's the smartest move. Early in most software engineering projects (when you're testing ideas, racing toward product-market fit, or building a one-off demo), speed matters more than spotless architecture. Taking on debt &lt;em&gt;intentionally&lt;/em&gt; can help you move fast, learn quickly, and prove value. The key is doing it with your eyes open: track it, cap it, and set a date to pay it back. Debt becomes dangerous not when you borrow, but when you forget you ever did.&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%2F7874fbjhov9slk5tyk7v.jpg" 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%2F7874fbjhov9slk5tyk7v.jpg" alt="Tech Debt" width="715" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.researchgate.net/publication/286010286_Towards_an_Ontology_of_Terms_on_Technical_Debt" rel="noopener noreferrer"&gt;Towards an Ontology of Terms on Technical Debt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://c2.com/doc/oopsla92.html" rel="noopener noreferrer"&gt;Cunningham, W. (1992). The WyCash Portfolio Management System. OOPSLA '92 Experience Report&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Have you dealt with painful tech debt before? Maybe you’ve left behind a shortcut you wish you hadn’t, or inherited code that made no sense. Share your stories, your worst TODOs, or that one file everyone avoids. Let’s talk about it!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>technicaldebt</category>
      <category>programming</category>
      <category>architecture</category>
      <category>refactoring</category>
    </item>
    <item>
      <title>A Backend Engineer's Guide to Not Getting Hacked</title>
      <dc:creator>Alexin</dc:creator>
      <pubDate>Mon, 16 Jun 2025 11:00:00 +0000</pubDate>
      <link>https://forem.com/alexindevs/a-backend-engineers-guide-to-not-getting-hacked-7jd</link>
      <guid>https://forem.com/alexindevs/a-backend-engineers-guide-to-not-getting-hacked-7jd</guid>
      <description>&lt;p&gt;So there I was at 3AM, frantically joining an emergency Google Meet call because someone was trying to casually walk away with millions from our production environment. Not exactly how I planned to spend my night, but what choice did I have? We caught the breach in time, and by implementing some pre-determined incident response measures, we prevented what could have been a complete disaster.&lt;/p&gt;

&lt;p&gt;Here's the thing about backend infrastructure: it's the backbone of everything we build. It's where we keep the crown jewels - user data, financial records, business logic, everything that makes our applications more than just pretty interfaces. When frontend fails, users get annoyed. When backend security fails? Companies die. Careers end. People get thrown in jail. Legal teams get that special twitch in their eyes. And yet, looking at some codebases out there, you'd think we were building toy projects instead of mission-critical infrastructure. I've seen production systems with security that wouldn't stop a determined teenager, let alone skilled attackers. I've watched companies pour millions into flashy features while treating security like an optional checkbox on their deployment checklist.&lt;/p&gt;

&lt;p&gt;Here's everything I wish someone had drilled into my head about security before I found myself panic-googling "how to stop hackers" at 3AM. Consider this your "please don't let this be you" guide to backend security.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Input Validation: Trust Issues as a Service
&lt;/h2&gt;

&lt;p&gt;Remember that time your mom told you to never trust strangers? Turns out she would've made a great security engineer. Every input is potentially malicious until proven otherwise. This isn't paranoia; it's just good engineering.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InputValidator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;validateAndSanitize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserInput&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ValidatedUserInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Your mom was right - trust no one&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isValidEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Nice try, but no.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sanitizeEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sanitizeMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;sanitizeMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Convert all values to strings and sanitize&lt;/span&gt;
    &lt;span class="c1"&gt;// Because someone will try to inject code here, I guarantee it&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;sanitized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;sanitized&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sanitizeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sanitized&lt;/span&gt;&lt;span class="p"&gt;;&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;h2&gt;
  
  
  2. Key Management: Your Crown Jewels Aren't for GitHub
&lt;/h2&gt;

&lt;p&gt;API keys are like your passwords - they don't belong on GitHub, in your DMs, in your CHatGPT debugging session or in that Slack message you swear no one will ever find. I don't care if it's a private repo that only you and your best friend has access to. No. Just no.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;SecretConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;staging&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;keyPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecretManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;secretsClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SecretsManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;secretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fullSecretName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keyPrefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;secretName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secretsClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSecretValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;SecretId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fullSecretName&lt;/span&gt;
      &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SecretString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Secret value is empty&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SecretString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Log the error, but don't expose secret paths&lt;/span&gt;
      &lt;span class="c1"&gt;// Because security through obscurity is bad,&lt;/span&gt;
      &lt;span class="c1"&gt;// but security through transparency is worse&lt;/span&gt;
      &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to retrieve secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt; 
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to retrieve secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;rotateSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;secretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Rotate your keys more often than you rotate your tires&lt;/span&gt;
    &lt;span class="c1"&gt;// Implementation details here&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;h2&gt;
  
  
  3. Logging: Your 3AM Detective Work Helper
&lt;/h2&gt;

&lt;p&gt;When things go wrong (and they will), logs are like security cameras for your application. The difference between good logging and bad logging becomes painfully clear at 3AM when you're trying to figure out why money is disappearing from user accounts. Proper logging isn't just about dumping data - it's about telling a story that your sleep-deprived future self can understand. Every log entry should answer the who, what, when, where, and how of each critical operation, because when you're in crisis mode, you won't have time to play detective with vague log messages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;SecurityEvent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data_access&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;modification&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deletion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;critical&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;ipAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecurityLogger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;logSecurityEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SecurityEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enrichedEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enrichEventWithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logstashClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enrichedEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requiresImmedateAlert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enrichedEvent&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alertingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;triggerAlert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;enrichedEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formatAlertMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enrichedEvent&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;enrichedEvent&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;requiresImmedateAlert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SecurityEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;criticalPatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;severity&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;critical&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deletion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;database&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;escalate_privileges&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isOutsideBusinessHours&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="c1"&gt;// Because nobody with good intentions really needs admin access at 3AM&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;criticalPatterns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&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;h2&gt;
  
  
  4. Rate Limiting: Because Your API Isn't an All-You-Can-Eat Buffet
&lt;/h2&gt;

&lt;p&gt;If someone's hitting your API faster than you can say "distributed denial of service," maybe they shouldn't be hitting it at all. Rate limiting is your API's immune system against both malicious attacks and poorly written client code. I've seen production servers brought to their knees not by sophisticated attacks, but by an intern's script stuck in an infinite loop. Think of rate limiting as your application's bouncer - it makes sure nobody's hogging the dance floor, and it can tell the difference between enthusiastic dancing and someone trying to start a riot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;RateLimitConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;windowMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxRequests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;keyGenerator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RateLimiter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RedisStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;checkRateLimit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RateLimitInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;windowMs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;windowKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentWindow&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;windowKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;windowKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;windowMs&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&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="na"&gt;isAllowed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxRequests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;remaining&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxRequests&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;resetTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentWindow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;windowMs&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage example:&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;rateLimiter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkRateLimit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAllowed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Someone's being greedy&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Too many requests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Take a break, have a coffee ☕&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;next&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;h2&gt;
  
  
  5. Authentication: Because "Admin1234" Isn't a Valid Password
&lt;/h2&gt;

&lt;p&gt;Authentication is more than just checking if a password matches - it's about maintaining the sanctity of your entire system. Modern authentication should handle session management, role-based access control, brute force protection, and secure password storage. The difference between good and bad authentication often becomes apparent only after a breach, when you're trying to explain to your users why their data is being sold on the dark web.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Session&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;expiresAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;validateSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UnauthorizedError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Nice try, but no&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expiresAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UnauthorizedError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Time to log in again, friend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;validatePassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If your password is in this list, we need to talk&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commonPasswords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin1234&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;letmein&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;qwerty&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commonPasswords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please choose a password that took longer than 2 seconds to think up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&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;h2&gt;
  
  
  6. Encryption: Where "It's Fine in Plaintext" Goes to Die
&lt;/h2&gt;

&lt;p&gt;If you're storing sensitive data in plaintext, we need to have a serious conversation about life choices. Proper encryption is your last line of defense when all other security measures fail. Think of it as your application's panic room; even if the bad guys get in, they still can't access what matters most. The key (pun intended) is doing it right: using strong algorithms, proper key management, and understanding that "security through obscurity" is not encryption.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EncryptionService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;algorithm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aes-256-gcm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EncryptedData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomBytes&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomBytes&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deriveKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;masterKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCipheriv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;final&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAuthTag&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="na"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Because one day, quantum computers will make us regret weak encryption&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;deriveKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;masterKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pbkdf2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;masterKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&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;h2&gt;
  
  
  7. Proper Error Handling: Keep Your Secrets Secret
&lt;/h2&gt;

&lt;p&gt;Nothing says "please hack me" quite like a stack trace in production.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ErrorHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Log the full error for debugging&lt;/span&gt;
    &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Internal error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// But send a sanitized version to the client&lt;/span&gt;
    &lt;span class="c1"&gt;// Because they don't need to know our life story&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// Give them just enough to file a support ticket&lt;/span&gt;
      &lt;span class="c1"&gt;// But not enough to exploit anything&lt;/span&gt;
    &lt;span class="p"&gt;});&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;h2&gt;
  
  
  8. Monitoring: Because Nobody Wants a 3AM Surprise
&lt;/h2&gt;

&lt;p&gt;Good monitoring is like having security cameras, motion sensors, and a team of guards all watching your application 24/7. It's not just about collecting metrics. It's about understanding what's normal for your system and being able to spot when something's off. The goal is to be alerted about potential issues before they become actual problems, and before your users start tweeting about how your service is down. If something moves in your system, you should know about it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SystemMonitor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;checkSystemHealth&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HealthStatus&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkDatabaseConnections&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkApiLatency&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkErrorRates&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkMemoryUsage&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="c1"&gt;// The more paranoid, the better&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;healthy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;healthy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unhealthy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lastChecked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;All systems operational (until they're not)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;alertOnAnomaly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAnomalous&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notificationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Anomaly Detected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Metric &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is acting sus`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;actionRequired&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&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;h2&gt;
  
  
  9. Dependency Management: Your Supply Chain Is Only as Strong as Its Weakest npm Package
&lt;/h2&gt;

&lt;p&gt;Remember that time you npm installed half the internet to use one function? Each of those dependencies is a potential security nightmare waiting to happen. One compromised package, and suddenly your secure application is about as trustworthy as a phishing email.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DependencyManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;allowList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;trusted-package&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;verified-module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;  

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;blockList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;definitely-not-malware&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto-miner-utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;  

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;auditDependencies&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuditResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAllDependencies&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;vulnerabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Vulnerability&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;  

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dep&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// Check against known vulnerability databases  &lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;npmAudit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkNpmVulnerabilities&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dep&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snykReport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkSnykVulnerabilities&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dep&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// Check for suspicious behavior  &lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;suspicious&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkSuspiciousPatterns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dep&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;npmAudit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;snykReport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;suspicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;vulnerabilities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dep&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;npmAudit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;snykReport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;suspicious&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calculateSeverity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;npmAudit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;snykReport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;suspicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;vulnerabilities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateAuditSummary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vulnerabilities&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;recommendations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateRemediation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vulnerabilities&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;checkSuspiciousPatterns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Package&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;SuspiciousPattern&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;patterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasObfuscatedCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checksForDebugger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makesUnexpectedNetworkCalls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessesSensitiveAPIs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;  

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="err"&gt; &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;h2&gt;
  
  
  10. Incident Response: Because Hope Is Not a Strategy
&lt;/h2&gt;

&lt;p&gt;Having a solid incident response plan is like having insurance - you hope you never need it, but you'll be really glad you have it when things go wrong. And in security, things will go wrong.  Here's a practical example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### The "Oh No" Plan: A Practical Guide to Not Panicking  &lt;/span&gt;

&lt;span class="gu"&gt;#### Level 1: Something's Fishy  &lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Suspicious login attempts
&lt;span class="p"&gt;-&lt;/span&gt; Weird API usage patterns  
&lt;span class="p"&gt;-&lt;/span&gt; That gut feeling something's off  

&lt;span class="gs"&gt;**Action Plan:**&lt;/span&gt;  
&lt;span class="p"&gt;1.&lt;/span&gt; Enhanced logging mode: ON
&lt;span class="p"&gt;2.&lt;/span&gt; Block suspicious IPs/users  
&lt;span class="p"&gt;3.&lt;/span&gt; Wake up the on-call engineer (sorry)  
&lt;span class="p"&gt;4.&lt;/span&gt; Start documenting everything  

&lt;span class="gu"&gt;#### Level 2: We Have a Problem &lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Successful unauthorized access  
&lt;span class="p"&gt;-&lt;/span&gt; Failed deployment flood  
&lt;span class="p"&gt;-&lt;/span&gt; Service degradation  
&lt;span class="p"&gt;-&lt;/span&gt; Money moving at 3AM  

&lt;span class="gs"&gt;**Action Plan:**&lt;/span&gt;  
&lt;span class="p"&gt;1.&lt;/span&gt; Lock down admin access  
&lt;span class="p"&gt;2.&lt;/span&gt; Freeze suspicious transactions  
&lt;span class="p"&gt;3.&lt;/span&gt; Wake up the security team  
&lt;span class="p"&gt;4.&lt;/span&gt; Start incident response channel  
&lt;span class="p"&gt;5.&lt;/span&gt; Pull recent logs and backups  

&lt;span class="gu"&gt;#### Level 3: All Hands on Deck 🚨  &lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Active financial theft  
&lt;span class="p"&gt;-&lt;/span&gt; System compromise  
&lt;span class="p"&gt;-&lt;/span&gt; Data breach in progress  
&lt;span class="p"&gt;-&lt;/span&gt; Complete service outage  

&lt;span class="gs"&gt;**Action Plan:**&lt;/span&gt;  
&lt;span class="p"&gt;1.&lt;/span&gt; Pull the emergency brake  
   - Freeze ALL transactions  
   - Revoke ALL access tokens  
   - Lock ALL admin accounts  
&lt;span class="p"&gt;2.&lt;/span&gt; Wake up EVERYONE  
   - Security team  
   - Engineering leads  
   - CEO (yes, really)  
&lt;span class="p"&gt;3.&lt;/span&gt; Document EVERYTHING  
   - Screenshots  
   - Log entries  
   - System states  
&lt;span class="p"&gt;4.&lt;/span&gt; Start recovery  
   - Deploy backup systems  
   - Rotate ALL credentials  
   - Enable forensic logging  

&lt;span class="gu"&gt;### The Communication Playbook  &lt;/span&gt;

&lt;span class="gu"&gt;#### Internal:  &lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Use secure channels only  
&lt;span class="p"&gt;-&lt;/span&gt; No sensitive info in public workspace  
&lt;span class="p"&gt;-&lt;/span&gt; Document decisions as they happen  
&lt;span class="p"&gt;-&lt;/span&gt; Keep a timeline of events  

&lt;span class="gu"&gt;#### External:  &lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Single spokesperson only  
&lt;span class="p"&gt;-&lt;/span&gt; No tweets about the incident  
&lt;span class="p"&gt;-&lt;/span&gt; Prepared statements only  
&lt;span class="p"&gt;-&lt;/span&gt; Legal review required  

&lt;span class="gu"&gt;### Post-Incident Checklist  &lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="gs"&gt;**What Happened**&lt;/span&gt;  
   - Timeline of events  
   - Systems affected  
   - Data compromised  
   - Attack vector  
&lt;span class="p"&gt;
2.&lt;/span&gt; &lt;span class="gs"&gt;**What We Did**&lt;/span&gt;  
   - Actions taken  
   - Effectiveness  
   - Response time  
   - Resources used  
&lt;span class="p"&gt;
3.&lt;/span&gt; &lt;span class="gs"&gt;**What We Learned**&lt;/span&gt;  
   - Security gaps  
   - Process failures  
   - Tool inadequacies  
   - Training needs  
&lt;span class="p"&gt;
4.&lt;/span&gt; &lt;span class="gs"&gt;**What We're Changing**&lt;/span&gt;  
   - New controls  
   - Updated procedures  
   - Additional monitoring  
   - Team training
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Bottom Line: Security Is Not a Feature, It's a Mindset
&lt;/h2&gt;

&lt;p&gt;Security isn't just a checkbox on your deployment checklist. It's not something you can just sprinkle on top of your application like debugging console.logs. It needs to be baked into every line of code you write, every system you design, and every process you implement.  &lt;/p&gt;

&lt;p&gt;Each of these practices serves a crucial purpose:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input validation prevents injection attacks and data corruption
&lt;/li&gt;
&lt;li&gt;Key management protects your crown jewels from exposure
&lt;/li&gt;
&lt;li&gt;Logging gives you the breadcrumbs to track down issues
&lt;/li&gt;
&lt;li&gt;Rate limiting protects your resources from abuse
&lt;/li&gt;
&lt;li&gt;Authentication ensures only the right people have access
&lt;/li&gt;
&lt;li&gt;Encryption keeps your sensitive data secure even if other measures fail
&lt;/li&gt;
&lt;li&gt;Error handling prevents information leakage
&lt;/li&gt;
&lt;li&gt;Monitoring helps you catch issues before they become incidents
&lt;/li&gt;
&lt;li&gt;Dependency management prevents supply chain attacks
&lt;/li&gt;
&lt;li&gt;Incident response helps you handle the inevitable with grace
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because trust me, explaining to your CEO at 3AM why all the company's money is now buying someone a yacht in Hawaii is not a conversation you want to have.  &lt;/p&gt;

&lt;p&gt;Remember:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validate everything like your paranoid aunt checking expiry dates at the grocery store
&lt;/li&gt;
&lt;li&gt;Encrypt always, because what's safely encrypted today might still be safely encrypted when quantum computers arrive
&lt;/li&gt;
&lt;li&gt;Log extensively, because future you will thank past you for the detailed logs
&lt;/li&gt;
&lt;li&gt;Monitor religiously, because the alternative is finding out about problems from your users
&lt;/li&gt;
&lt;li&gt;Manage your dependencies like you're checking ingredients for allergens
&lt;/li&gt;
&lt;li&gt;Have an incident response plan that doesn't start with "panic"
&lt;/li&gt;
&lt;li&gt;And for the love of all things holy, keep your API keys out of GitHub
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay vigilant, folks. The hackers aren't sleeping, but that doesn't mean you have to lose sleep too.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;P.S. If you're reading this because you're currently dealing with a security incident, STOP READING AND GO FIX IT! This article will still be here after you've contained the breach.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>programming</category>
      <category>softwareengineering</category>
      <category>devops</category>
    </item>
    <item>
      <title>Cloud Buzzwords every Software Engineer needs to know</title>
      <dc:creator>Alexin</dc:creator>
      <pubDate>Sun, 14 Jul 2024 22:23:48 +0000</pubDate>
      <link>https://forem.com/alexindevs/cloud-buzzwords-every-software-engineer-needs-to-know-57k0</link>
      <guid>https://forem.com/alexindevs/cloud-buzzwords-every-software-engineer-needs-to-know-57k0</guid>
      <description>&lt;p&gt;&lt;em&gt;In 2024, "Cloud" is a big thing. It's a fancy word. Developers everywhere are buzzing about it, feeling like it's a badge of honor to be involved with cloud technology. But what exactly is all the hype about? Why is "Cloud" so special? What even is "Cloud"? And why does everyone keep mentioning EC2 instances?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Cloud Engineering is very important in today's tech space. As more companies move their servers to cloud-based infrastructure, having a solid grasp of these concepts is critical for any software engineer looking to stay relevant and competitive in the field. In this article, we'll break down key cloud computing terms and concepts every software engineer should know. From basic cloud principles to advanced topics like containerization and infrastructure as code, this guide aims to provide a comprehensive understanding of essential cloud technologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is cloud computing?
&lt;/h2&gt;

&lt;p&gt;Cloud computing refers to the delivery of computing services—such as servers, storage, databases, networking, software, and more—over the internet ("the cloud"). This essentially means that companies no longer need massive data centers and on-premises servers to manage their operations. Instead, they can "rent" these services from other companies, known as &lt;strong&gt;cloud providers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The cloud's fast growth is driven by its flexibility, cost efficiency, and the ability to innovate without being bogged down by infrastructure worries. Instead of making large upfront investments in infrastructure (databases, storage, software, and hardware), companies can choose to utilize their computing power over the internet—the cloud—and pay based on usage. &lt;/p&gt;

&lt;p&gt;Companies pay &lt;strong&gt;cloud engineers&lt;/strong&gt; to manage their infrastructure in the cloud, just like they paid IT administrators to manage their infrastructure on premises in traditional setups. Cloud engineers oversee the deployment, maintenance, and security of applications and services hosted on cloud platforms. &lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Service Models
&lt;/h3&gt;

&lt;p&gt;Cloud service models categorize the types of services provided by cloud computing providers, offering different levels of control, management, and responsibility over computing resources. Here are the main cloud service models:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Infrastructure as a Service (IaaS):&lt;/strong&gt;&lt;br&gt;
IaaS provides virtualized computing resources over the internet. Users manage the operating systems, applications, and data hosted on these virtual resources, while the cloud provider maintains the physical hardware and underlying infrastructure. A well-known IaaS platform is Amazon Web Services Elastic Compute Cloud (AWS EC2).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Platform as a Service (PaaS):&lt;/strong&gt;&lt;br&gt;
PaaS offers a platform allowing customers to develop, run, and manage applications without the complexity of building and maintaining the underlying infrastructure. It typically includes tools for application development, testing, deployment, and hosting. PaaS is well-suited for developers focusing on application development rather than managing hardware and software infrastructure. Commonly used examples include Heroku, Vercel and Render.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Software as a Service (SaaS):&lt;/strong&gt;&lt;br&gt;
Software as a Service (SaaS) applications are software solutions hosted and maintained by third-party providers, accessible over the internet via web browsers. Users subscribe to SaaS applications on a recurring basis, which includes updates and support. SaaS applications are highly customizable within predefined configurations and integrate seamlessly with other applications through APIs. Software engineers are often most familiar with SaaS due to its prevalence across various tools and platforms they use daily, from collaboration tools like Slack to enterprise solutions like Salesforce CRM.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Containerization, Virtualization, and Orchestration in Cloud Computing
&lt;/h2&gt;

&lt;p&gt;These three terms are distinct but interrelated when it comes to cloud computing. These technologies play critical roles in optimizing resource usage, enhancing application portability and scalability, and automating complex operational tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Virtualization
&lt;/h3&gt;

&lt;p&gt;This is the process of creating virtual versions of computing resources such as servers, storage, and networks. Virtual Machines (VMs) are software-based simulations of physical computers. They allow multiple operating systems (OS) to run simultaneously on a single physical machine, known as the host machine. Each VM operates independently, with its own virtualized hardware resources, including CPU, memory, storage, and network interfaces. IaaS providers like Amazon EC2 utilize virtualization to provide resizable compute capacity in the cloud. AWS uses a hypervisor, a software layer that abstracts physical hardware and enables multiple VMs (instances) to run on a single physical server. The hypervisor manages and allocates hardware resources to EC2 instances, ensuring efficient use of underlying physical infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Containerization
&lt;/h3&gt;

&lt;p&gt;Containerization goes a step further than virtualization by packaging applications and their dependencies into containers. Containers encapsulate everything needed to run an application, including code, runtime, libraries, and settings. &lt;strong&gt;Docker&lt;/strong&gt;, a leading container platform, allows developers to build, ship, and run applications consistently across different environments. Containers are lightweight, portable, and provide a standardized way to deploy applications, making them ideal for cloud environments where scalability and agility are crucial.&lt;/p&gt;

&lt;h4&gt;
  
  
  Differences Between Containers and Virtual Machines
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Abstraction Level:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Virtual Machines (VMs):&lt;/strong&gt; VMs emulate physical hardware, including a full OS, on a host machine using a hypervisor. Each VM runs its own guest OS, which consumes more resources and takes longer to start compared to containers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Containers:&lt;/strong&gt; Containers abstract at the application level, packaging applications and their dependencies into isolated units. They share the host OS kernel and resources, making them more lightweight and efficient than VMs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resource Utilization:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Virtual Machines:&lt;/strong&gt; VMs allocate dedicated resources (CPU, memory, storage) to each instance, regardless of actual usage, which can lead to underutilization of resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Containers:&lt;/strong&gt; Containers only allocate resources as needed, leading to better resource utilization and higher density of applications per host.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Portability and Deployment:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Virtual Machines:&lt;/strong&gt; VMs are less portable because they include a full guest OS, making them larger in size and more complex to move between environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Containers:&lt;/strong&gt; Containers are highly portable due to their lightweight nature. They encapsulate everything needed to run an application, ensuring consistency across different environments from development to production.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Orchestration
&lt;/h3&gt;

&lt;p&gt;Orchestration in cloud computing, particularly with tools like Kubernetes (K8s), automates the management of containerized applications across multiple servers (nodes). It handles tasks such as deployment, scaling, and monitoring, ensuring applications run efficiently and reliably. Think of it as a system that coordinates and optimizes how your software operates in the cloud, simplifying complex processes like scaling up during traffic spikes or ensuring consistent performance across different environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Deployment Models
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Public Cloud
&lt;/h3&gt;

&lt;p&gt;Public clouds are operated by third-party providers and offer computing resources and services over the internet. They are accessible to anyone who wants to use or purchase them. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Web Services (AWS)&lt;/strong&gt;: AWS provides a wide range of cloud services globally, including computing power, storage options, and databases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft Azure&lt;/strong&gt;: Azure offers services for computing, analytics, and networking, widely used by enterprises and developers worldwide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Cloud Platform (GCP)&lt;/strong&gt;: GCP provides cloud computing services with a focus on data analytics and machine learning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Public clouds are ideal for startups, small businesses, and large enterprises that need scalable infrastructure without upfront investment in hardware.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Private Cloud
&lt;/h3&gt;

&lt;p&gt;Private clouds are dedicated to a single organization and are hosted either internally or by a third-party provider. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VMware Cloud&lt;/strong&gt;: &lt;a href="https://www.vmware.com/" rel="noopener noreferrer"&gt;VMware&lt;/a&gt; offers private cloud solutions that businesses can deploy in their own data centers or through VMware's infrastructure partners.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenStack&lt;/strong&gt;: An open-source platform that enables organizations to build and manage private clouds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Private clouds are preferred by organizations with stringent security and compliance requirements, such as financial institutions and government agencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Hybrid Cloud
&lt;/h3&gt;

&lt;p&gt;Hybrid clouds integrate private and public cloud environments, allowing data and applications to be shared between them. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Outposts&lt;/strong&gt;: &lt;a href="https://aws.amazon.com/outposts/" rel="noopener noreferrer"&gt;AWS Outposts&lt;/a&gt; extend AWS infrastructure, services, APIs, and tools to virtually any datacenter, co-location space, or on-premises facility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure Stack&lt;/strong&gt;: Microsoft Azure Stack extends Azure services and capabilities to on-premises environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hybrid clouds are suitable for businesses that want the flexibility to run certain workloads on-premises while leveraging the scalability of the public cloud for other applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Multi-cloud
&lt;/h3&gt;

&lt;p&gt;Multi-cloud involves using services from multiple public cloud providers, avoiding dependence on a single vendor. Multi-cloud strategies are adopted by organizations seeking to avoid vendor lock-in, optimize costs, and leverage specific strengths of different cloud providers for different parts of their infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serverless Computing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Serverless computing&lt;/strong&gt; is a cloud computing execution model where the cloud provider dynamically manages the allocation and provisioning of servers. In simpler terms, it allows developers to run code without having to manage the underlying infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Use Serverless Computing?
&lt;/h3&gt;

&lt;p&gt;Serverless computing offers several benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Applications automatically scale with demand. You don't have to worry about provisioning servers or managing scaling policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Efficiency&lt;/strong&gt;: You pay only for the actual compute time used, rather than paying for idle servers. This can lead to significant cost savings, especially for applications with variable workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Operational Complexity&lt;/strong&gt;: Developers can focus more on writing code and less on managing infrastructure. &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Serverless Computing Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS Lambda&lt;/strong&gt;: Allows you to run code in response to events without provisioning or managing servers. It supports a variety of programming languages and integrates seamlessly with other AWS services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Azure Functions&lt;/strong&gt;: Provides serverless compute to run event-triggered code without managing infrastructure. It supports multiple programming languages and integrates well with Azure services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Google Cloud Functions&lt;/strong&gt;: Similar to AWS Lambda and Azure Functions, it allows you to run event-driven functions in a serverless environment.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Infrastructure as Code (IaC)
&lt;/h2&gt;

&lt;p&gt;Infrastructure as Code (IaC) refers to the practice of managing and provisioning computing infrastructure (such as servers, databases, networks, and storage) through machine-readable script files, rather than physical hardware configuration or interactive configuration tools. This means that instead of manually configuring servers and infrastructure components, developers and operations teams use code to automate the provisioning, configuration, and management of infrastructure resources. Here are some popular IaC tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terraform&lt;/strong&gt;: A widely adopted tool that allows you to define and provision infrastructure using a declarative configuration language. It supports multiple cloud providers and on-premises environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ansible&lt;/strong&gt;: Ansible automates configuration management, application deployment, and task automation across multiple nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS CloudFormation&lt;/strong&gt;: Specifically designed for AWS, CloudFormation enables you to model and set up your AWS resources as code. It supports a wide range of AWS services and integrates well with other AWS offerings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benefits of IaC tools include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;IaC enables automation of infrastructure management tasks, reducing human error and ensuring consistency across environments.&lt;/li&gt;
&lt;li&gt;It facilitates the rapid deployment and scaling of infrastructure resources, allowing organizations to respond quickly to changing demands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version Control&lt;/strong&gt;: Infrastructure configurations are versioned alongside application code, providing a clear audit trail and enabling rollback to previous states if needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration&lt;/strong&gt;: Teams can collaborate more effectively by sharing and iterating on infrastructure code, enhancing productivity and reducing deployment bottlenecks.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In 2024, "Cloud" has become more than just a buzzword—it's a fundamental shift in how we build and manage technology. From understanding what "Cloud" actually means to diving into advanced topics like containerization and infrastructure as code, you've embarked on a journey to demystify these crucial concepts. Now, when someone mentions EC2 instances or Kubernetes, you'll nod knowingly rather than feeling left out of the conversation.&lt;/p&gt;

&lt;p&gt;If you're eager to dive deeper into cloud engineering, there are plenty of resources to help you get started. Online platforms like Coursera, Udemy, and Pluralsight offer courses ranging from beginner to advanced levels. Additionally, certifications from AWS, Microsoft Azure, and Google Cloud can provide valuable credentials to showcase your expertise. Hands-on experience through personal projects or &lt;a href="https://engineering.altschoolafrica.com/programs/cloud-engineering" rel="noopener noreferrer"&gt;joining a cloud engineering program&lt;/a&gt; can also accelerate your learning journey. Thank you for reading!&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>aws</category>
      <category>azure</category>
      <category>devops</category>
    </item>
    <item>
      <title>Why Appwrite Is Your Ideal BaaS in 2024</title>
      <dc:creator>Alexin</dc:creator>
      <pubDate>Wed, 03 Jul 2024 19:00:00 +0000</pubDate>
      <link>https://forem.com/alexindevs/why-appwrite-is-your-ideal-baas-in-2024-im-5aom</link>
      <guid>https://forem.com/alexindevs/why-appwrite-is-your-ideal-baas-in-2024-im-5aom</guid>
      <description>&lt;p&gt;In the competitive world of Software as a Service (SaaS) products, speed to market can make or break your startup. You're racing against time to build, test, and deploy your application before your competitors do. However, building or integrating various backend services eats up valuable development hours and resources. What if there was a way to handle all your backend needs with a single, cohesive platform? This is where Appwrite comes in. Appwrite enables entrepreneurs to focus on what truly matters – building and scaling their product. In this article, you'll learn about Appwrite's history, features, and why it's the best choice for any entrepreneur building to scale in 2024.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F7si9fyh8z7as3uh4qr29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F7si9fyh8z7as3uh4qr29.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7si9fyh8z7as3uh4qr29.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Appwrite?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://appwrite.io/" rel="noopener noreferrer"&gt;Appwrite&lt;/a&gt; is a comprehensive Backend as a Service (BaaS) platform designed to help developers build and scale applications quickly and efficiently. Whether you're a solo indie hacker or part of a growing startup, Appwrite provides the essential features you need—database management, authentication, storage, and cloud functions—all in one unified platform.&lt;/p&gt;

&lt;p&gt;Appwrite was founded in 2019 by Eldad Fux, a software engineer and entrepreneur. The initial vision was to create an open-source platform that simplifies backend development, making it more accessible and efficient for developers of all skill levels. Eldad noticed that many developers struggled with setting up and managing backend services, often juggling multiple tools and services to meet their needs. He envisioned Appwrite as an all-in-one solution that would streamline this process, enabling developers to focus on building their applications rather than dealing with the complexities of backend development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;p&gt;Appwrite's main selling point is its comprehensive suite of backend services. Here is a list of its features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: Think about the time and effort it takes to set up a secure and flexible authentication system for your users. Appwrite simplifies this process by providing built-in support for multiple authentication methods, including email/password, Magic URL, JWT, OAuth providers (like Google, Facebook, and GitHub), and even anonymous login. This means you can offer your users a variety of login options, enhancing their experience while ensuring security.&lt;br&gt;
But Appwrite doesn't stop there. It also supports two-factor authentication (2FA) and robust session management, giving your users an extra layer of security and allowing them to maintain their login status across sessions and devices. Whether you're building a social app that needs social logins or an enterprise solution requiring strict access controls, Appwrite has you covered.&lt;br&gt;
&lt;a href="https://media.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%2F0szho8k71cybojq4qzdl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F0szho8k71cybojq4qzdl.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0szho8k71cybojq4qzdl.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database Management&lt;/strong&gt;: Appwrite simplifies database management for developers by offering robust support for both SQL and NoSQL databases within a unified platform. Whether you're launching a new startup or scaling an existing SaaS application, Appwrite allows you to effortlessly create and manage databases, collections, and documents. This means you can focus more on crafting innovative features for your application and less on the complexities of backend infrastructure. With Appwrite, scaling your database to accommodate growing user bases and increasing data volumes becomes seamless, ensuring your application maintains high performance and reliability as it evolves.&lt;br&gt;
&lt;a href="https://media.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%2Fd604vh5dg14lxrf9xzj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fd604vh5dg14lxrf9xzj3.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d604vh5dg14lxrf9xzj3.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File Storage&lt;/strong&gt;: Appwrite simplifies file storage and management by seamlessly integrating with Content Delivery Networks (CDNs). Whether you're dealing with images, videos, or documents, Appwrite ensures that your multimedia content is securely stored and efficiently delivered to users worldwide. This CDN integration not only enhances the speed and reliability of content delivery but also reduces latency, improving the overall user experience. For SaaS applications that heavily rely on multimedia content, Appwrite's scalable file storage capabilities ensure efficient content management and delivery without concerns about storage limitations or performance bottlenecks.&lt;br&gt;
&lt;a href="https://media.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%2F5434prslcz9ox9h6v3tr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F5434prslcz9ox9h6v3tr.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5434prslcz9ox9h6v3tr.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Serverless Functions&lt;/strong&gt;: Serverless functions are a cloud computing execution model that allows developers to run code without having to manage their own servers. These functions are typically small, stateless pieces of code that are triggered by specific events, such as HTTP requests, database changes or file uploads.  Appwrite gives developers the power of serverless computing, freeing them from server management to focus on writing business logic. On Appwrite, serverless functions can be triggered by different events like database changes and HTTP requests, enabling the creation of responsive and scalable applications.&lt;br&gt;
&lt;a href="https://media.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%2Fponm4m8toar81g0cj0nm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fponm4m8toar81g0cj0nm.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ponm4m8toar81g0cj0nm.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why choose Appwrite?
&lt;/h2&gt;

&lt;p&gt;Choosing the right backend-as-a-service (BaaS) platform is crucial for the success of your SaaS application. Here’s a direct comparison of Appwrite with other popular BaaS platforms like Firebase and AWS Amplify, highlighting their unique strengths and ideal use cases. By examining these comparisons, you can make an informed decision on the best BaaS solution for your project.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature/Platform&lt;/th&gt;
&lt;th&gt;Appwrite&lt;/th&gt;
&lt;th&gt;Firebase&lt;/th&gt;
&lt;th&gt;AWS Amplify&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Platform Focus&lt;/td&gt;
&lt;td&gt;Unified platform for essential backend services: database, authentication, file storage, serverless functions&lt;/td&gt;
&lt;td&gt;Real-time database capabilities and Google services integration&lt;/td&gt;
&lt;td&gt;Comprehensive cloud services integration with AWS, including AI/ML and IoT support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Development Approach&lt;/td&gt;
&lt;td&gt;Simplifies development with a cohesive approach, reducing multiple service integrations&lt;/td&gt;
&lt;td&gt;Excels in real-time synchronization, mobile development&lt;/td&gt;
&lt;td&gt;Suitable for enterprise-level applications needing extensive scalability and complex cloud integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ideal Use Cases&lt;/td&gt;
&lt;td&gt;Applications needing robust multimedia content management and scalable serverless architectures&lt;/td&gt;
&lt;td&gt;Applications requiring extensive real-time synchronization and mobile development&lt;/td&gt;
&lt;td&gt;Enterprise-level applications needing extensive scalability and complex cloud integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Setting Up Appwrite in Your Application
&lt;/h2&gt;

&lt;p&gt;To demonstrate the power and ease of using Appwrite, this article will take you through the process of setting up Appwrite for a web application built in React.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Make sure you have the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; and npm installed on your machine.&lt;/li&gt;
&lt;li&gt;Basic knowledge of &lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React.js&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 1: Setting Up Appwrite via Browser
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Access the Appwrite Console:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Open your web browser and navigate to &lt;a href="https://appwrite.io/" rel="noopener noreferrer"&gt;Appwrite Console&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you don't have an account, sign up for free. Otherwise, log in to your existing account.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a New Project:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once logged in, click on "Projects" in the sidebar.&lt;/li&gt;
&lt;li&gt;Click the "Create a New Project" button.&lt;/li&gt;
&lt;li&gt;Enter a name for your project (e.g., "Appwrite Demo Project") and optionally a description.&lt;/li&gt;
&lt;li&gt;Click "Create Project" to proceed.
&lt;img src="https://media.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%2Fcwlgrmnpka1c9ap21u6l.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cwlgrmnpka1c9ap21u6l.png"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Get Your Project ID and API Keys:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After creating your project, click on its name to enter the project dashboard.&lt;/li&gt;
&lt;li&gt;Take note of your Project ID, which you will need to configure the Appwrite SDK in your application later.
&lt;img src="https://media.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%2Fq8hx5yblf7jocn0taegf.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q8hx5yblf7jocn0taegf.png"&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to the API Keys tab under Project Settings.&lt;/li&gt;
&lt;li&gt;Create a new API key with appropriate permissions (e.g., full access for demo purposes).&lt;/li&gt;
&lt;li&gt;Copy the API key value securely. You will use this in your application to authenticate API requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Create a New React Project
&lt;/h3&gt;

&lt;p&gt;To create a new React.js project, run this in your terminal:&lt;/p&gt;

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

&lt;span class="nv"&gt;$ &lt;/span&gt;npx create-react-app appwrite-demo
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;appwrite-demo


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 3: Install Appwrite SDK
&lt;/h3&gt;

&lt;p&gt;To interact with Appwrite from your React application, you need to install the Appwrite SDK. Run the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;appwrite


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 4: Initialize Appwrite in Your React App
&lt;/h3&gt;

&lt;p&gt;Open your &lt;code&gt;src/App.js&lt;/code&gt; file and initialize the Appwrite client:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;appwrite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;https://appwrite.io/v1&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Replace with your Appwrite Endpoint&lt;/span&gt;
      &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PROJECT_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Replace with your Project ID&lt;/span&gt;
      &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Replace with your API Key&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Example: Create a new user&lt;/span&gt;
    &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User created:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error creating user:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Welcome to Appwrite Demo&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;



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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 5: Run Your React App
&lt;/h3&gt;

&lt;p&gt;Finally, start your React application by running:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;npm start


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

&lt;/div&gt;

&lt;p&gt;Open your browser and navigate to &lt;code&gt;http://localhost:3000&lt;/code&gt; to see your application in action. You should see the message "Welcome to Appwrite Demo" and, in your console, a response indicating the creation of a new user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As we’ve explored, Appwrite stands out as an ideal backend solution for SaaS startups in 2024 due to its comprehensive platform that simplifies backend development. By offering essential services like database management, authentication, file storage, and serverless functions in one cohesive package, Appwrite eliminates the need for multiple service integrations, saving valuable development time and resources. Its open-source nature, robust security features, and scalability make it a reliable choice for both indie hackers and growing startups. With Appwrite, developers can focus on what truly matters: building and scaling their applications to meet market demands swiftly and efficiently. Thanks for reading!&lt;/p&gt;

</description>
      <category>appwritehack</category>
      <category>backend</category>
      <category>javascript</category>
      <category>saas</category>
    </item>
    <item>
      <title>Automating User and Group Management with a Bash Script in Linux</title>
      <dc:creator>Alexin</dc:creator>
      <pubDate>Mon, 01 Jul 2024 14:32:16 +0000</pubDate>
      <link>https://forem.com/alexindevs/automating-user-and-group-management-with-a-bash-script-in-linux-225j</link>
      <guid>https://forem.com/alexindevs/automating-user-and-group-management-with-a-bash-script-in-linux-225j</guid>
      <description>&lt;p&gt;In the fast-paced world of DevOps Engineering, automation is key to efficiency and reliability. Managing user accounts and groups manually can be a stressful, time-consuming, and error-prone task, especially in environments with numerous users. Recognizing this challenge, the &lt;a href="https://hng.tech/internship"&gt;HNG Internship&lt;/a&gt; provided a practical task that simulates a real-world scenario, where &lt;a href="https://hng.tech/premium"&gt;interns&lt;/a&gt; are required to automate user and group management on a Linux system.&lt;br&gt;
The task is to create a Bash script that automates the creation of users and groups, securely manages passwords, and logs all actions performed. This exercise not only enhances scripting skills but also deepens the understanding of Linux system administration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Task
&lt;/h2&gt;

&lt;p&gt;Your company has employed many new developers. As a SysOps engineer, write a bash script called &lt;code&gt;create_users.sh&lt;/code&gt; that reads a text file containing the employee’s usernames and group names, where each line is formatted as user;groups.&lt;br&gt;
The script should create users and groups as specified, set up home directories with appropriate permissions and ownership, generate random passwords for the users, and log all actions to &lt;code&gt;/var/log/user_management.log&lt;/code&gt;. Additionally, store the generated passwords securely in &lt;code&gt;/var/secure/user_passwords.txt&lt;/code&gt;.&lt;br&gt;
Ensure error handling for scenarios like existing users and provide clear documentation and comments within the script.&lt;/p&gt;
&lt;h3&gt;
  
  
  Requirements:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Each User must have a personal group with the same group name as the username, this group name will not be written in the text file.&lt;/li&gt;
&lt;li&gt;A user can have multiple groups, each group delimited by comma ","&lt;/li&gt;
&lt;li&gt;Usernames and user groups are separated by semicolon ";"- Ignore whitespace
e.g.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   light; sudo,dev,www-data
   idimma; sudo
   mayowa; dev,www-data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For the first line, light is username and groups are sudo, dev, www-data.&lt;/p&gt;
&lt;h2&gt;
  
  
  My solution
&lt;/h2&gt;

&lt;p&gt;To tackle this problem, I first broke down the requirements stated into clear, actionable steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Read Input File:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the text file containing the employee’s usernames and group names.&lt;/li&gt;
&lt;li&gt;Each line is formatted as &lt;code&gt;user;groups&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Process Each Line:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Split each line into the username and the corresponding groups.&lt;/li&gt;
&lt;li&gt;Remove any whitespace for accurate processing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create Users and Groups:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure each user has a personal group with the same name as their username.&lt;/li&gt;
&lt;li&gt;Create additional groups if they do not already exist.&lt;/li&gt;
&lt;li&gt;Add the user to the specified groups.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set Up Home Directories:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create home directories for each user.&lt;/li&gt;
&lt;li&gt;Set appropriate permissions and ownership for the directories.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Generate and Store Passwords:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate random passwords for each user.&lt;/li&gt;
&lt;li&gt;Securely store the passwords in &lt;code&gt;/var/secure/user_passwords.txt&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Log Actions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log all actions performed (e.g., user creation, group assignment) to &lt;code&gt;/var/log/user_management.log&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Error Handling:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement error handling to manage scenarios like existing users or groups.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From this list of requirements, I mapped out a clear plan to solve the problem. These are the steps I followed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create folders for logs and secure passwords, but do nothing if they already exist.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/log /var/secure
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Create files for logs and password storage.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch&lt;/span&gt; /var/log/user_management.log
&lt;span class="nb"&gt;touch&lt;/span&gt; /var/secure/user_passwords.txt
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Make the password file secure, giving it read and write permission for the file owner only.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;600 /var/secure/user_passwords.txt
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Define a function that logs actions performed by the script to the log file.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;log_action&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"/var/log/user_management.log"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Create a function that handles user creation. This function does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checks if the user already exists by calling the id command and redirecting the output to &lt;code&gt;/dev/null&lt;/code&gt;. If the user exists, it logs a message and returns.&lt;/li&gt;
&lt;li&gt;Creates a personal group for the user using the &lt;code&gt;groupadd&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;Creates the additional groups if they do not exist.&lt;/li&gt;
&lt;li&gt;Creates the user with the &lt;code&gt;useradd&lt;/code&gt; command, setting the home directory, shell, and primary group.&lt;/li&gt;
&lt;li&gt;Logs a message indicating the success or failure of the &lt;code&gt;useradd&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;Adds the user to the other groups using the &lt;code&gt;usermod&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;Generates a random password for the user using &lt;code&gt;/dev/urandom&lt;/code&gt; and stores the user and their respective password in &lt;code&gt;/var/secure/user_passwords.txt&lt;/code&gt;, the secure password file.&lt;/li&gt;
&lt;li&gt;Sets the permissions and ownership for the user's home directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the source code:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;create_user&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

&lt;span class="c"&gt;# defines 3 variables passed to the function: user, groups, and password&lt;/span&gt;
&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;local groups&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;local &lt;/span&gt;password

&lt;span class="c"&gt;# check if user already exists by logging user information with id&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp;&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;log_action &lt;span class="s2"&gt;"User &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; already exists."&lt;/span&gt;
    &lt;span class="k"&gt;return
fi&lt;/span&gt;

&lt;span class="c"&gt;# Create personal group for the user&lt;/span&gt;
groupadd &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Create additional groups if they do not exist&lt;/span&gt;
&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-ra&lt;/span&gt; group_array &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$groups&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Log the group array&lt;/span&gt;
log_action &lt;span class="s2"&gt;"User &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; will be added to groups: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;group_array&lt;/span&gt;&lt;span class="p"&gt;[*]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;group &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;group_array&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | xargs&lt;span class="si"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# Trim whitespace&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; getent group &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp;&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;groupadd &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        log_action &lt;span class="s2"&gt;"Group &lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt; created."&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt;

&lt;span class="c"&gt;# Create user with home directory and shell, primary group set to the personal group&lt;/span&gt;
useradd &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /bin/bash &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;log_action &lt;span class="s2"&gt;"User &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; created with primary group: &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;log_action &lt;span class="s2"&gt;"Failed to create user &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
    &lt;span class="k"&gt;return
fi&lt;/span&gt;

&lt;span class="c"&gt;# Add the user to additional groups&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;group &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;group_array&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done
&lt;/span&gt;log_action &lt;span class="s2"&gt;"User &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; added to groups: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;group_array&lt;/span&gt;&lt;span class="p"&gt;[*]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# generate password and store it securely in a file&lt;/span&gt;
&lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&amp;lt;/dev/urandom &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-dc&lt;/span&gt; A-Za-z0-9 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; 12&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | chpasswd

&lt;span class="c"&gt;# store user and password securely in a file&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"/var/secure/user_passwords.txt"&lt;/span&gt;

&lt;span class="c"&gt;# set permissions and ownership for user home directory&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 &lt;span class="s2"&gt;"/home/&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"/home/&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

log_action &lt;span class="s2"&gt;"Password for user &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; set and stored securely."&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;In the main script, check if the list of users was provided in the script's arguments.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$# &lt;/span&gt;&lt;span class="nt"&gt;-ne&lt;/span&gt; 1 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;user_list_file&amp;gt;"&lt;/span&gt;
&lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;If it was provided, check that it is a valid file:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Users list file &lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt; not found."&lt;/span&gt;
&lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Read the file line-by-line, extract the user and groups from each line, and call the &lt;code&gt;create_user&lt;/code&gt; function passing the user and groups as an argument:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Users list file &lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt; not found."&lt;/span&gt;
&lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the complete code file:&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;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# create folders for logs and secure passwords&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/log /var/secure

&lt;span class="c"&gt;# create logs file and passwords file&lt;/span&gt;
&lt;span class="nb"&gt;touch&lt;/span&gt; /var/log/user_management.log
&lt;span class="nb"&gt;touch&lt;/span&gt; /var/secure/user_passwords.txt

&lt;span class="c"&gt;# make password file secure (read and write permissions for file owner only)&lt;/span&gt;

&lt;span class="nb"&gt;chmod &lt;/span&gt;600 /var/secure/user_passwords.txt

&lt;span class="c"&gt;# function to log actions to log file&lt;/span&gt;
log_action&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"/var/log/user_management.log"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


create_user&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c"&gt;# defines 3 variables passed to the function: user, groups, and password&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;local groups&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;password

    &lt;span class="c"&gt;# check if user already exists by logging user information with id&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp;&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;log_action &lt;span class="s2"&gt;"User &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; already exists."&lt;/span&gt;
        &lt;span class="k"&gt;return
    fi&lt;/span&gt;

    &lt;span class="c"&gt;# Create personal group for the user&lt;/span&gt;
    groupadd &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="c"&gt;# Create additional groups if they do not exist&lt;/span&gt;
    &lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-ra&lt;/span&gt; group_array &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$groups&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="c"&gt;# Log the group array&lt;/span&gt;
    log_action &lt;span class="s2"&gt;"User &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; will be added to groups: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;group_array&lt;/span&gt;&lt;span class="p"&gt;[*]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;group &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;group_array&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
        &lt;/span&gt;&lt;span class="nv"&gt;group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | xargs&lt;span class="si"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# Trim whitespace&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; getent group &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp;&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
            &lt;/span&gt;groupadd &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            log_action &lt;span class="s2"&gt;"Group &lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt; created."&lt;/span&gt;
        &lt;span class="k"&gt;fi
    done&lt;/span&gt;

    &lt;span class="c"&gt;# Create user with home directory and shell, primary group set to the personal group&lt;/span&gt;
    useradd &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /bin/bash &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;log_action &lt;span class="s2"&gt;"User &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; created with primary group: &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;log_action &lt;span class="s2"&gt;"Failed to create user &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
        &lt;span class="k"&gt;return
    fi&lt;/span&gt;

    &lt;span class="c"&gt;# Add the user to additional groups&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;group &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;group_array&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
        &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;done
    &lt;/span&gt;log_action &lt;span class="s2"&gt;"User &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; added to groups: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;group_array&lt;/span&gt;&lt;span class="p"&gt;[*]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="c"&gt;# generate password and store it securely in a file&lt;/span&gt;
    &lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&amp;lt;/dev/urandom &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-dc&lt;/span&gt; A-Za-z0-9 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; 12&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | chpasswd

    &lt;span class="c"&gt;# store user and password securely in a file&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"/var/secure/user_passwords.txt"&lt;/span&gt;

    &lt;span class="c"&gt;# set permissions and ownership for user home directory&lt;/span&gt;
    &lt;span class="nb"&gt;chmod &lt;/span&gt;700 &lt;span class="s2"&gt;"/home/&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"/home/&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    log_action &lt;span class="s2"&gt;"Password for user &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; set and stored securely."&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# check if user list file is provided&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$# &lt;/span&gt;&lt;span class="nt"&gt;-ne&lt;/span&gt; 1 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;user_list_file&amp;gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Users list file &lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt; not found."&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# read user list file and create users&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;';'&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; user &lt;span class="nb"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | xargs&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;groups&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$groups&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | xargs | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# Replace commas with spaces for usermod group format&lt;/span&gt;
    &lt;span class="nb"&gt;groups&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$groups&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    create_user &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$groups&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt; &amp;lt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"User creation process completed. Check /var/log/user_management.log for details."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;create_users.sh&lt;/code&gt; bash script has successfully automated user and group management on a Linux system. It reads a text file containing employee usernames and group names, creates users and groups as specified, sets up home directories with appropriate permissions and ownership, generates random passwords for the users, and logs all actions to &lt;code&gt;/var/log/user_management.log&lt;/code&gt;. Additionally, it securely stores the generated passwords in &lt;code&gt;/var/secure/user_passwords.txt&lt;/code&gt;. Thanks for reading!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>linux</category>
      <category>bash</category>
    </item>
    <item>
      <title>How to Containerize Your Backend Applications Using Docker</title>
      <dc:creator>Alexin</dc:creator>
      <pubDate>Mon, 01 Jul 2024 07:00:00 +0000</pubDate>
      <link>https://forem.com/mlasunilag/how-to-containerize-your-backend-applications-using-docker-3ap7</link>
      <guid>https://forem.com/mlasunilag/how-to-containerize-your-backend-applications-using-docker-3ap7</guid>
      <description>&lt;p&gt;Imagine you have spent months meticulously building a backend application. It handles user requests flawlessly, scales beautifully, and is ready to take your product to the next level. But then comes deployment dread. Different environments, dependency conflicts, and a looming fear of something breaking - all potential roadblocks on your path to launch.&lt;/p&gt;

&lt;p&gt;Docker solves these problems and gives you a cleaner, more efficient way to package, deploy, and scale your applications. This article will guide you through the process of containerizing your backend application and deploying it to an EC2 instance on Amazon Web Services (AWS).&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Docker?
&lt;/h2&gt;

&lt;p&gt;Assume you have a perfect pie recipe, complete with ingredients and instructions, and you bake it using an oven set to 190 degrees Celsius. When your friend tries to bake the same pie using only a microwave that goes up to 140 degrees, it doesn't turn out as expected. You can solve this problem by providing not just the ingredients and recipe, but also the exact oven, kitchen setup, and tools you used. This way, your friend can recreate the exact same pie, regardless of their own kitchen's limitations.&lt;/p&gt;

&lt;p&gt;Similarly, &lt;a href="https://docker.com/"&gt;Docker&lt;/a&gt; is a tool that helps developers package an application and all its parts—like code, libraries, and system settings—into a "container". This container can run on any computer, making sure the application works the same everywhere. Docker also lets you move these containers around easily, so you can run your app on any computer or even in the cloud without any fuss. And since containers are lightweight, you can spin up as many as you need without hogging too much space or resources. Overall, Docker makes developing and running software smoother, more consistent, and less of a headache.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Does Docker Work?
&lt;/h3&gt;

&lt;p&gt;In simple terms, Docker works by creating containers, which are like &lt;a href="https://v2cloud.com/blog/what-is-a-virtual-machine"&gt;virtual machines&lt;/a&gt; but much lighter. These containers package up all the code and dependencies needed to run an application, including libraries, system tools, and settings. Docker then runs these containers on any computer, making sure the application runs the same everywhere. It's like having a portable box that contains everything your app needs, so you can easily move it around and run it on any computer without any extra setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started With Docker
&lt;/h2&gt;

&lt;p&gt;This article will refer to a &lt;a href="https://nodejs.org"&gt;Node.js&lt;/a&gt; application built with &lt;a href="https://nestjs.com"&gt;NestJS&lt;/a&gt; as an example. To follow along, you'll need a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A Linux Environment:&lt;/strong&gt;  Linux operating system or a virtual machine running Linux is preferred. If you primarily work with Windows, you can download the &lt;a href="https://learn.microsoft.com/en-us/windows/wsl/install"&gt;Windows Subsystem for Linux (WSL)&lt;/a&gt;. If you use MacOS, that also works fine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker installed:&lt;/strong&gt; Download and install Docker Desktop for your operating system from the &lt;a href="https://www.docker.com/get-started/"&gt;official Docker website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js and npm:&lt;/strong&gt; Ensure you have Node.js and &lt;a href="https://www.npmjs.com/"&gt;npm&lt;/a&gt; (Node Package Manager) installed on your machine. You can verify this by running &lt;code&gt;node -v&lt;/code&gt; and &lt;code&gt;npm -v&lt;/code&gt; in your terminal. If not installed, download them from the official &lt;a href="https://nodejs.org/en/"&gt;Node.js website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A basic NestJS Application&lt;/strong&gt;: I will be working with a project called "Dorm Haven". I will assume you have a NestJS application set up. If you do not have one, you can clone &lt;a href="https://github.com/alexindevs/nestjs-starter-pack"&gt;A NestJS project&lt;/a&gt; from my GitHub account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Having an account on Docker Hub:&lt;/strong&gt; Sign up for a Docker Hub account at &lt;a href="https://hub.docker.com/"&gt;Docker Hub&lt;/a&gt; if you don't already have one. This will be necessary for pushing your Docker images to a remote repository.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Having an AWS Account:&lt;/strong&gt; Sign up for an AWS account at &lt;a href="https://aws.amazon.com/"&gt;AWS&lt;/a&gt; if you don't already have one. This will be necessary for deploying your application to Amazon EC2.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that you have Docker, Node.js, npm, and a basic NestJS application ready, let's containerize your application and deploy it to an EC2 instance on AWS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Docker on your application
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a file and name it &lt;code&gt;Dockerfile&lt;/code&gt;&lt;/strong&gt;: Note that this file should have no extension. This is a text file that contains a set of instructions to build a Docker image. Each instruction in a &lt;code&gt;Dockerfile&lt;/code&gt; defines a step in the process of setting up the environment Docker needs to run a specific application. Add the following code to the file:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:20.10.0-alpine
WORKDIR /usr/src/app
COPY . .
RUN npm install
RUN npm run build
ENV NODE_ENV production
EXPOSE 3000
CMD ["npm", "start"]
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The code above does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;FROM node:20.10.0-alpine&lt;/code&gt;:&lt;/strong&gt; Sets the base image for the Docker container to the official Node.js Alpine Linux image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;WORKDIR /usr/src/app&lt;/code&gt;:&lt;/strong&gt; Changes the working directory to &lt;code&gt;/usr/src/app&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;COPY . .&lt;/code&gt;:&lt;/strong&gt; Copies the entire contents of the local directory to the container's working directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;RUN npm install&lt;/code&gt;:&lt;/strong&gt; Installs NPM packages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;RUN npm run build&lt;/code&gt;:&lt;/strong&gt; Builds the Node.js application inside the container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ENV NODE_ENV production&lt;/code&gt;:&lt;/strong&gt; Sets the &lt;code&gt;NODE_ENV&lt;/code&gt; environment variable to &lt;code&gt;production&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;EXPOSE 3000&lt;/code&gt;:&lt;/strong&gt; Exposes port 3000, so the application can be accessed from outside the container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;CMD ["npm", "start"]&lt;/code&gt;:&lt;/strong&gt; Defines the command to start the application.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build Your Docker Image:&lt;/strong&gt; In the root directory of your project, run the following command to build your Docker image. Replace &lt;code&gt;dorm-haven&lt;/code&gt; with the name of your application:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; dorm-haven &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This command tells Docker to build an image (a lightweight, standalone, executable package that includes everything one needs to run a piece of software) using the instructions in your &lt;code&gt;Dockerfile&lt;/code&gt; and tag it with the name &lt;code&gt;dorm-haven&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Run Your Docker Container:&lt;/strong&gt; After building the image, you can run it as a container. Use the following command to start the container:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 dorm-haven
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This command maps port 3000 on your local machine to port 3000 in the Docker container, allowing you to access your application at &lt;code&gt;http://localhost:3000&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Pushing the Docker Image to Docker Hub:
&lt;/h3&gt;

&lt;p&gt;To deploy your application to an EC2 instance on AWS, you first need to push your Docker image to a Docker registry like &lt;a href="https://hub.docker.com"&gt;Docker Hub&lt;/a&gt;. Follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Log in to Docker Hub using the command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker login
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tag your Docker image:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker tag dorm-haven alexindevs/dorm-haven
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Push the image to Docker Hub:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker push alexindevs/dorm-haven
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that you have your application containerized and ready for deployment, it's time to set up the EC2 instance on AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the EC2 instance
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Log in to your AWS Dashboard. You should see something similar to the screen below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faz764hhl6sjjfgv3n4ko.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faz764hhl6sjjfgv3n4ko.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/az764hhl6sjjfgv3n4ko.png" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on the &lt;code&gt;Services&lt;/code&gt; option on the navigation bar. Click on Compute, then select EC2.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmau7vulbnhg7q9x8670.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmau7vulbnhg7q9x8670.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bmau7vulbnhg7q9x8670.png" width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You'll be redirected to the EC2 dashboard. There, click on &lt;code&gt;Launch Instance&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnrhvc8qr8roy2c6a5htv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnrhvc8qr8roy2c6a5htv.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nrhvc8qr8roy2c6a5htv.png" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter your server name, and choose an Amazon Machine Image. For this tutorial, I will be using Ubuntu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft84zoflqkxuel8ffvpfr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft84zoflqkxuel8ffvpfr.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t84zoflqkxuel8ffvpfr.png" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, create a key pair. This will grant you SSH access to your server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hnr16xx02ornv263lxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hnr16xx02ornv263lxk.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9hnr16xx02ornv263lxk.png" width="609" height="209"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter a name and choose a key pair type. It is recommended to use the RSA encrypted &lt;code&gt;.pem&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4f1s95l9pyp8ey2qw2b1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4f1s95l9pyp8ey2qw2b1.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4f1s95l9pyp8ey2qw2b1.png" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on &lt;code&gt;Launch Instance&lt;/code&gt;. This will redirect you to the dashboard shown below. You have successfully created an EC2 instance on AWS! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6l1ci6mcra6uwf0fkj0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6l1ci6mcra6uwf0fkj0.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m6l1ci6mcra6uwf0fkj0.png" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Accessing the EC2 instance through SSH
&lt;/h2&gt;

&lt;p&gt;Now your repository is stored on the Docker Hub, and you have an EC2 instance. It is time to navigate to the EC2 instance and deploy your application.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open your instance dashboard and click on &lt;code&gt;Connect to Instance&lt;/code&gt;. Navigate to the &lt;code&gt;SSH client&lt;/code&gt; tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sk0ic4k5iuhpzqe8key.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sk0ic4k5iuhpzqe8key.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5sk0ic4k5iuhpzqe8key.png" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On your terminal, locate your private key and change its permissions as described above. Then run the command. It will grant you access to your instance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switch to the super user using this command.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;su
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the following commands to install and set up Docker on the instance.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get upgrade
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;docker.io
&lt;span class="nv"&gt;$ &lt;/span&gt;systemctl start docker
&lt;span class="nv"&gt;$ &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check that Docker is running.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Login to Docker. This will grant you access to your stored repositories.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker login
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pull the uploaded image from the Docker Hub, and confirm that it was downloaded successfully.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker pull alexindevs/dorm-haven
&lt;span class="nv"&gt;$ &lt;/span&gt;docker images
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After pulling the image, run your Docker container. Map port 80 on your EC2 instance to port 3000 in the Docker container (or any other appropriate port based on your application - make sure to configure your instance to allow public requests on that port).&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 80:3000 alexindevs/dorm-haven
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;-d&lt;/code&gt; flag runs the container in detached mode, which means it will run in the background.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify that your container is running using the following command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Additional Tips
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check Container Logs:&lt;/strong&gt;&lt;br&gt;
If you need to check the logs for your container to troubleshoot any issues, use:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs &amp;lt;container-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Replace &lt;code&gt;&amp;lt;container-id&amp;gt;&lt;/code&gt; with the actual container ID from the &lt;code&gt;docker ps&lt;/code&gt; output.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Manage Containers:&lt;/strong&gt;&lt;br&gt;
To stop a running container:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stop &amp;lt;container-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;To remove a stopped container:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;rm&lt;/span&gt; &amp;lt;container-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we walked through the process of setting up Docker, creating a &lt;code&gt;Dockerfile&lt;/code&gt; for your Node.js application, building and running your Docker container, and finally deploying it to an AWS EC2 instance. By following these steps, you can streamline your deployment process, reduce environment-related issues, and scale your application effortlessly. Thank you for reading!&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/"&gt;Docker Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=gAkwW2tuIqE"&gt;Fireship Video on Docker&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>aws</category>
    </item>
    <item>
      <title>Debugging 101 - How to Fix Software Errors Efficiently</title>
      <dc:creator>Alexin</dc:creator>
      <pubDate>Wed, 12 Jun 2024 20:22:48 +0000</pubDate>
      <link>https://forem.com/alexindevs/debugging-101-how-to-fix-software-errors-efficiently-5hm2</link>
      <guid>https://forem.com/alexindevs/debugging-101-how-to-fix-software-errors-efficiently-5hm2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;If debugging is the process of removing software bugs, then programming must be the process of putting them in.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You’re sitting at your desk, staring (glaring, rather) at your laptop. It’s 2 am. Your code just isn’t working and you’re not sure why. You’ve tried everything you can think of, but the bug is still there, taunting you. You feel like giving up and going to bed. You feel like throwing your laptop at the wall. You feel like crying. You start to doubt your abilities and wonder if you’ll ever be a great software engineer. In the depths of despair and frustration, you take a deep breath and decide to give it one more shot. You go through your code line by line, trying to find where you went wrong. And then, after what feels like an eternity, you see it. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A repeated function call.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A line without proper indentation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A dang semicolon.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bugs are the bane of every developer's existence. They come in all shapes and sizes and can be a real headache to deal with. That’s why in this article, I’ll be teaching you the classic steps to solve any kind of bug in as little time as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a bug?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A software bug is an error, flaw, or fault in the design, development, or operation of computer software that causes it to produce an incorrect or unexpected result, or to behave in unintended ways. The process of finding and correcting bugs is termed "debugging" and often uses formal techniques or tools to pinpoint bugs. Since the 1950s, some computer systems have been designed to detect or auto-correct various software errors during operations. - Wikipedia&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simply put, a bug is a software error. It’s when your code doesn’t produce the expected results. For example, when you write a function to increment the number 1 till it reaches 10, but you end up with a 10-character string of 1’s instead, that’s a bug. Debugging, on the other hand, is just what it sounds like: removing or fixing bugs.&lt;/p&gt;

&lt;p&gt;Now, bugs typically have more disastrous consequences in everyday applications. Imagine a scenario where a bug in a banking application causes a user's balance to be incorrectly displayed or a payment to be processed twice. That could lead to serious financial problems for the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different types of bugs
&lt;/h2&gt;

&lt;p&gt;Different types of bugs can occur while writing software. Some of the most common types of bugs include:&lt;/p&gt;

&lt;p&gt;Syntax errors: Typos, missing punctuation, or incorrect formatting – these basic code mistakes prevent the program from even running.&lt;/p&gt;

&lt;p&gt;Logic errors: The code runs smoothly, but the output is wrong due to flaws in the underlying logic, like the banking app example.&lt;/p&gt;

&lt;p&gt;Runtime errors: Unexpected situations during execution, like memory issues or accessing invalid data, cause the program to crash or behave erratically.&lt;/p&gt;

&lt;p&gt;Misinterpreted requirements: Even with seemingly correct code, the program might not achieve its intended purpose if the developer misunderstood the requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Debug Code
&lt;/h2&gt;

&lt;p&gt;In the following paragraphs, I'll walk you through an efficient bug-solving process step-by-step, using an example to help you understand how to use it effectively.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reproduce the error: When you first encounter a bug, you need to reproduce the error to understand its root cause. This involves identifying the specific steps or conditions that trigger the issue and then attempting to replicate them in a non-production environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Isolate the bug: To identify faulty code, the error message needs to be examined meticulously and then traced back to the specific line or lines of code that caused the issue. This may involve debugging tools, print statements, or code reviews.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understand the Code: Go through every line of code in the program. Make sure you comprehend what each line is supposed to do. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test Inputs and Outputs: Test your code with different inputs to see if the bug occurs consistently or only under certain conditions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fix the bug: At this point, you’ve probably identified the error in your code. Check for syntax errors, faulty logic, and issues with external dependencies. Brainstorm the solution to the bug, then refine it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do research: If you can’t come up with a solution on your own, it’s best to do some research online. Debug with your favorite AI tool. Look for forums like Stack Overflow where people may have experienced a similar issue and have found a solution. You can also search for tutorials or guides on how to fix the problem. If no solution is found, reach out to colleagues and senior engineers for assistance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test your solution: Once you have found a solution, test it. Make sure that the bug is completely fixed and that it doesn't cause any new issues or side effects. It's always a good idea to get a second opinion from a colleague or mentor before deploying the code to a production environment.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In conclusion, debugging is an essential skill for any developer. It can be a frustrating and time-consuming process, but with the right approach, it doesn't have to be. By following the steps outlined in this article, you can systematically identify and fix bugs in your code, saving yourself countless hours of hair-pulling and frustration. Remember, bugs are inevitable, but with practice and patience, you can become a proficient debugger. Thanks for reading!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>debugging</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Bash Scripting for Software Engineers - A Beginner's Guide</title>
      <dc:creator>Alexin</dc:creator>
      <pubDate>Sun, 09 Jun 2024 15:00:00 +0000</pubDate>
      <link>https://forem.com/alexindevs/bash-scripting-for-software-engineers-a-beginners-guide-1j65</link>
      <guid>https://forem.com/alexindevs/bash-scripting-for-software-engineers-a-beginners-guide-1j65</guid>
      <description>&lt;p&gt;It's your first day at your new job. You've been handed a computer running Linux, and you were told to locate all the files containing the word "key". It's a simple enough task, right? The catch is, there are thousands of files on that system, and you've never written a shell script before. &lt;/p&gt;

&lt;p&gt;Shell scripting, the language of the command line, is your ticket to automating repetitive tasks and mastering your Linux environment. With this guide, you'll be able to navigate your way around any Bash terminal with ease, and you might learn a couple of cool tricks along the way!&lt;/p&gt;

&lt;h2&gt;
  
  
  What are all these terms, anyway?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Shell
&lt;/h3&gt;

&lt;p&gt;A shell is a program that interprets commands and executes them on your operating system. Simply put, a shell is a command-line interpreter that acts as a bridge between you and your operating system. It is usually run in a terminal or console. The terminal provides an input interface to run textual commands, and the shell takes in those commands and executes them on your system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bash
&lt;/h3&gt;

&lt;p&gt;It is a shell program and command language. Bash has its roots in earlier Unix shells. The &lt;strong&gt;Bourne shell&lt;/strong&gt;, released in 1977, was a major step forward in allowing users to write scripts and automate tasks. Bash, short for &lt;strong&gt;Bourne-Again SHell&lt;/strong&gt;, was created in 1989 by Brian Fox as part of the GNU Project. It was designed as a free and improved alternative to the Bourne shell, while still maintaining compatibility with existing scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with Bash Scripting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up the Development Environment
&lt;/h3&gt;

&lt;p&gt;Bash shells are commonly found on Linux operating systems. In this article, we will be working primarily with Ubuntu, a Linux distribution. You can download and set up Ubuntu here: (Canonical Ubuntu)[&lt;a href="http://ubuntu.com/download"&gt;http://ubuntu.com/download&lt;/a&gt;].&lt;/p&gt;

&lt;p&gt;Alternatively, if you're working from a Windows environment, you can download the Windows Subsystem for Linux (WSL) which gives you access to a Linux operating system and a bash terminal, without the need for dual booting, or clean wiping Windows. You can get WSL here: &lt;a href="https://learn.microsoft.com/en-us/windows/wsl/install"&gt;https://learn.microsoft.com/en-us/windows/wsl/install&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have your terminal open, you should see a prompt like the one below:&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="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are ready to begin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Shell commands
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cd&lt;/code&gt;: Change directory. This command is used to navigate to a different directory within the file system.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;Desktop
&lt;span class="c"&gt;# This will switch to the ./Desktop directory.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ls&lt;/code&gt;: List directory contents. It displays the files and directories in the current directory.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;file1.txt
file2.txt
directory1/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mkdir&lt;/code&gt;: Make a directory. This command creates a new directory with the given name.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;newDir
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;newDir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rm&lt;/code&gt;: Remove. It is used to delete files or directories. Be cautious as it does not have a confirmation prompt by default.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rm newFile
$ ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; newDir
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pwd&lt;/code&gt;: Print working directory. It shows the current directory path.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pwd
/home/alexin/newDir/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cp&lt;/code&gt;: Copy. This command is used to copy files or directories from one location to another.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; ../file_to_copy.txt &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;file_to_copy.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mv&lt;/code&gt;: Move. It moves files or directories from one location to another. It can also be used to rename files.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mv&lt;/span&gt; ../file_to_move.txt &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;file_to_move.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;touch&lt;/code&gt;: Create a new file. It creates an empty file with the specified name or updates the timestamp of an existing file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;newFile.txt
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;newFile.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cat&lt;/code&gt;: Concatenate and display content. This command is used to display the content of files on the terminal. It can also be used to concatenate and display multiple files.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;newFile.txt
This is the content of newFile.txt.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;echo&lt;/code&gt;: Print text. This is used to print text or variables to the terminal or standard output.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'I am Alexin'&lt;/span&gt;
I am Alexin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Alexin"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'My name is $name'&lt;/span&gt;
My name is Alexin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;man&lt;/code&gt;: Displays information about a command. 'man' stands for manual, and it is used to provide detailed information about the specified command, including its purpose, syntax, options, and examples of usage.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;man &lt;span class="nb"&gt;ls
&lt;/span&gt;LS&lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;                            User Commands                           LS&lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;

NAME
       &lt;span class="nb"&gt;ls&lt;/span&gt; - list directory contents

SYNOPSIS
       &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;OPTION]... &lt;span class="o"&gt;[&lt;/span&gt;FILE]...

DESCRIPTION
       List  information  about  the FILEs &lt;span class="o"&gt;(&lt;/span&gt;the current directory by default&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
       Sort entries alphabetically &lt;span class="k"&gt;if &lt;/span&gt;none of &lt;span class="nt"&gt;-cftuvSUX&lt;/span&gt; nor &lt;span class="nt"&gt;--sort&lt;/span&gt;  is  speci‐
       fied.

       Mandatory  arguments  to  long  options are mandatory &lt;span class="k"&gt;for &lt;/span&gt;short options
       too.

       &lt;span class="nt"&gt;-a&lt;/span&gt;, &lt;span class="nt"&gt;--all&lt;/span&gt;
              &lt;span class="k"&gt;do &lt;/span&gt;not ignore entries starting with &lt;span class="nb"&gt;.&lt;/span&gt;

       &lt;span class="nt"&gt;-A&lt;/span&gt;, &lt;span class="nt"&gt;--almost-all&lt;/span&gt;
              &lt;span class="k"&gt;do &lt;/span&gt;not list implied &lt;span class="nb"&gt;.&lt;/span&gt; and ..

       &lt;span class="nt"&gt;--author&lt;/span&gt;
 Manual page &lt;span class="nb"&gt;ls&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; line 1 &lt;span class="o"&gt;(&lt;/span&gt;press h &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="nb"&gt;help &lt;/span&gt;or q to quit&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;grep&lt;/code&gt;: The &lt;code&gt;grep&lt;/code&gt; command is used to search for specific patterns or regular expressions within files or streams of text. It stands for "Global Regular Expression Print".
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"error"&lt;/span&gt; file.txt
This line contains error.
This line also contains the word &lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
This line has errors &lt;span class="o"&gt;(&lt;/span&gt;error is &lt;span class="k"&gt;in &lt;/span&gt;the word errors&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;find&lt;/code&gt;: Search files and directories. This command lets you search for matching expressions or patterns in a specified file or directory. It allows you to search based on various criteria such as name, type, size, and permissions.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;find / -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating Bash Scripts
&lt;/h2&gt;

&lt;p&gt;A bash script is a file typically ending with the extension &lt;code&gt;.sh&lt;/code&gt; that contains a logical series of related commands to be executed.  You can create a bash script using the nano text editor by running this command in your terminal:&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="nv"&gt;$ &lt;/span&gt;nano new_script.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the editor, start your script with a &lt;strong&gt;shebang&lt;/strong&gt; line. The shebang line tells the system that this file is a script and specifies the interpreter to use.&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;#!/bin/bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can add a simple command to print the text "Hello, World!" to the terminal.&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;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Hello, World!"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file then exit: &lt;code&gt;CTRL X&lt;/code&gt; + &lt;code&gt;Y&lt;/code&gt; + &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before you can run the file, you have to make it executable. Change the file's permissions using the following commands:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;u+x new_script.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run your bash script.&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="nv"&gt;$ &lt;/span&gt;./new_script.sh
Hello, World!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! You have created your first bash script. Now, let's learn about handling control flow with conditionals and loops.&lt;/p&gt;

&lt;h3&gt;
  
  
  Control flow
&lt;/h3&gt;

&lt;p&gt;This refers to the order in which commands are executed in a program. In Bash scripting, control flow constructs allow you to manage the execution sequence of your script, enabling you to make decisions, repeat actions, and manage complex logical conditions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Control Flow Constructs in Bash
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Conditional Statements&lt;/strong&gt;: These are used to execute a block of code only if a specified condition is true.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;if Statement&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; condition &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
   &lt;span class="c"&gt;# Code to execute if condition is true&lt;/span&gt;
 &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;if-else Statement&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; condition &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
   &lt;span class="c"&gt;# Code to execute if condition is true&lt;/span&gt;
 &lt;span class="k"&gt;else&lt;/span&gt;
   &lt;span class="c"&gt;# Code to execute if condition is false&lt;/span&gt;
 &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;if-elif-else Statement&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; condition1 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
   &lt;span class="c"&gt;# Code to execute if condition1 is true&lt;/span&gt;
 &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; condition2 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
   &lt;span class="c"&gt;# Code to execute if condition2 is true&lt;/span&gt;
 &lt;span class="k"&gt;else&lt;/span&gt;
   &lt;span class="c"&gt;# Code to execute if neither condition1 nor condition2 is true&lt;/span&gt;
 &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Loops&lt;/strong&gt;: These are used to repeat a block of code multiple times.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;for Loop&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="k"&gt;for &lt;/span&gt;variable &lt;span class="k"&gt;in &lt;/span&gt;list&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="c"&gt;# Code to execute for each item in list&lt;/span&gt;
 &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;while Loop&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; condition &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="c"&gt;# Code to execute as long as condition is true&lt;/span&gt;
 &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;until Loop&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="k"&gt;until&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; condition &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="c"&gt;# Code to execute until condition is true&lt;/span&gt;
 &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Case Statement&lt;/strong&gt;: This is used to execute one of several blocks of code based on the value of a variable.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;$variable&lt;/span&gt; &lt;span class="k"&gt;in
     &lt;/span&gt;pattern1&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="c"&gt;# Code to execute if variable matches pattern1&lt;/span&gt;
       &lt;span class="p"&gt;;;&lt;/span&gt;
     pattern2&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="c"&gt;# Code to execute if variable matches pattern2&lt;/span&gt;
       &lt;span class="p"&gt;;;&lt;/span&gt;
     &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="c"&gt;# Code to execute if variable doesn't match any pattern&lt;/span&gt;
       &lt;span class="p"&gt;;;&lt;/span&gt;
   &lt;span class="k"&gt;esac&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To demonstrate these concepts, let us write a program that performs a calculation given two numbers and an operation as input:&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;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# Function to perform arithmetic operations&lt;/span&gt;
perform_operation&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;# First we define 3 variables, to store the arguments passed into the function.&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;num1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;num2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;operation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;

  &lt;span class="c"&gt;# We then use a case statement to execute an arithmetic operation, based on the value of the $operation variable. We log the result of the operation to the terminal.&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;$operation&lt;/span&gt; &lt;span class="k"&gt;in
    &lt;/span&gt;addition&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;num1 &lt;span class="o"&gt;+&lt;/span&gt; num2&lt;span class="k"&gt;))&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Result of addition: &lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    subtraction&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;num1 &lt;span class="o"&gt;-&lt;/span&gt; num2&lt;span class="k"&gt;))&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Result of subtraction: &lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    multiplication&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;num1 &lt;span class="o"&gt;*&lt;/span&gt; num2&lt;span class="k"&gt;))&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Result of multiplication: &lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    division&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$num2&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: Division by zero is not allowed."&lt;/span&gt;
      &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;num1 &lt;span class="o"&gt;/&lt;/span&gt; num2&lt;span class="k"&gt;))&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Result of division: &lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;fi&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Invalid operation. Please use one of the following: addition, subtraction, multiplication, division."&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;esac&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Main script starts here&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Enter the first number:"&lt;/span&gt;
&lt;span class="nb"&gt;read &lt;/span&gt;num1

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Enter the second number:"&lt;/span&gt;
&lt;span class="nb"&gt;read &lt;/span&gt;num2

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Enter the operation (addition, subtraction, multiplication, division):"&lt;/span&gt;
&lt;span class="nb"&gt;read &lt;/span&gt;operation

&lt;span class="c"&gt;# Perform the operation&lt;/span&gt;
perform_operation &lt;span class="nv"&gt;$num1&lt;/span&gt; &lt;span class="nv"&gt;$num2&lt;/span&gt; &lt;span class="nv"&gt;$operation&lt;/span&gt;

&lt;span class="c"&gt;# Loop to check if user wants to perform another operation&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Do you want to perform another operation? (yes/no)"&lt;/span&gt;
  &lt;span class="nb"&gt;read &lt;/span&gt;choice

  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;$choice&lt;/span&gt; &lt;span class="k"&gt;in
    &lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;y|Yes|YES&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Enter the first number:"&lt;/span&gt;
      &lt;span class="nb"&gt;read &lt;/span&gt;num1

      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Enter the second number:"&lt;/span&gt;
      &lt;span class="nb"&gt;read &lt;/span&gt;num2

      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Enter the operation (addition, subtraction, multiplication, division):"&lt;/span&gt;
      &lt;span class="nb"&gt;read &lt;/span&gt;operation
      &lt;span class="c"&gt;# The read command enables a shell script to read user input from the command line.&lt;/span&gt;

      perform_operation &lt;span class="nv"&gt;$num1&lt;/span&gt; &lt;span class="nv"&gt;$num2&lt;/span&gt; &lt;span class="nv"&gt;$operation&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    no|n|No|NO&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Exiting the script. Goodbye!"&lt;/span&gt;
      &lt;span class="nb"&gt;break&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Invalid choice. Please enter yes or no."&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;esac&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Handling command line arguments
&lt;/h4&gt;

&lt;p&gt;n a Bash script, command-line arguments are accessed using positional parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$0&lt;/code&gt; is the name of the script.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, ..., &lt;code&gt;$N&lt;/code&gt; are the arguments passed to the script.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$#&lt;/code&gt; is the number of arguments passed to the script.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$@&lt;/code&gt; is all the arguments passed to the script.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$*&lt;/code&gt; is all the arguments passed to the script as a single word.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"$@"&lt;/code&gt; is all the arguments passed to the script, individually quoted.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"$*"&lt;/code&gt; is all the arguments passed to the script, quoted as a single word.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's modify the previous arithmetic script to handle command-line arguments. This way, users can specify the numbers and the operation directly when they run the script.&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;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Function to perform arithmetic operations&lt;/span&gt;
perform_operation&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;num1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;num2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;operation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;

  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;$operation&lt;/span&gt; &lt;span class="k"&gt;in
    &lt;/span&gt;addition&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;num1 &lt;span class="o"&gt;+&lt;/span&gt; num2&lt;span class="k"&gt;))&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Result of addition: &lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    subtraction&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;num1 &lt;span class="o"&gt;-&lt;/span&gt; num2&lt;span class="k"&gt;))&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Result of subtraction: &lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    multiplication&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;num1 &lt;span class="o"&gt;*&lt;/span&gt; num2&lt;span class="k"&gt;))&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Result of multiplication: &lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    division&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$num2&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: Division by zero is not allowed."&lt;/span&gt;
      &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;num1 &lt;span class="o"&gt;/&lt;/span&gt; num2&lt;span class="k"&gt;))&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Result of division: &lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;fi&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Invalid operation. Please use one of the following: addition, subtraction, multiplication, division."&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;esac&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$# &lt;/span&gt;&lt;span class="nt"&gt;-ne&lt;/span&gt; 3 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;num1&amp;gt; &amp;lt;num2&amp;gt; &amp;lt;operation&amp;gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Example: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; 5 3 addition"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;num1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nv"&gt;num2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
&lt;span class="nv"&gt;operation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;

perform_operation &lt;span class="nv"&gt;$num1&lt;/span&gt; &lt;span class="nv"&gt;$num2&lt;/span&gt; &lt;span class="nv"&gt;$operation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that you know the basics of scripting in shell, try out these practice assignments:&lt;/p&gt;

&lt;h3&gt;
  
  
  Assignment #1: Locate Files Containing the Word "key"
&lt;/h3&gt;

&lt;p&gt;Your task is to write a Bash script that searches for all files containing the word "key" within a specified directory and its subdirectories. The script should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Accept the directory path as a command-line argument.&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;grep&lt;/code&gt; command to search for files containing the word "key".&lt;/li&gt;
&lt;li&gt;Print the paths of the files that contain the word "key".&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Assignment #2: Automate Git Commits for Each Edited File
&lt;/h3&gt;

&lt;p&gt;In this assignment, you will write a Bash script to automate the process of creating a separate Git commit for every file that has been edited in a Git repository. This script will be particularly useful in scenarios where you want to commit each file separately, perhaps for clearer version history or to adhere to specific project guidelines.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensure the script is executed within a Git repository.&lt;/li&gt;
&lt;li&gt;Use Git commands to list files that have been edited.&lt;/li&gt;
&lt;li&gt;Loop through the list of modified files and create a commit for each one.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In summary, this guide has equipped you with the foundational knowledge to navigate the world of Bash scripting. You've explored core concepts like shell commands, creating scripts, control flow structures, and handling user input. With this strong base, you can now venture into more complex scripting tasks to automate various processes and streamline your workflow on Linux systems.&lt;/p&gt;

&lt;p&gt;Remember, practice is key to mastering any skill. Experiment with the provided assignments and explore other scripting challenges to solidify your understanding. Thank you for reading!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>bash</category>
      <category>shell</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
